Skip to content

Commit

Permalink
conflict 해결
Browse files Browse the repository at this point in the history
  • Loading branch information
yuuuyeonho committed Feb 2, 2025
2 parents 4dc1a33 + fd7d00c commit 7aa1116
Show file tree
Hide file tree
Showing 14 changed files with 348 additions and 96 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/prod-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
on:
push:
branches:
- main

jobs:
build_application:
name: build application and make jar file
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4

# Build Project
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'

- name: Set Redis
run: docker compose -f docker-compose-test.yml up -d

- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0'

- name: Set Permission to gradlew
run: chmod +x ./gradlew

- name: Build with Gradle Wrapper
run: ./gradlew build

# Build Docker Image & Push
- name: Login to Dockerhub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Build Docker Image & Push Image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKER_PROD_IMAGE_TAG }}

# Deploy
- name: Access to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
port: ${{ secrets.EC2_PORT }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: |
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
sudo docker pull ${{ secrets.DOCKER_PROD_IMAGE_TAG }}
sudo docker compose up -f docker-compose-prod.yml -d
sudo docker image prune -a -f
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package com.keunsori.keunsoriserver.domain.auth.controller;

import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.MEMBER_NOT_EXISTS_WITH_STUDENT_ID;

import com.keunsori.keunsoriserver.domain.auth.login.LoginService;
import com.keunsori.keunsoriserver.domain.auth.login.dto.request.LoginRequest;
import com.keunsori.keunsoriserver.domain.auth.redis.RefreshTokenService;
import com.keunsori.keunsoriserver.domain.auth.login.JwtTokenManager;
import com.keunsori.keunsoriserver.domain.auth.login.dto.response.LoginResponse;
import com.keunsori.keunsoriserver.domain.member.domain.Member;
import com.keunsori.keunsoriserver.domain.member.domain.vo.MemberStatus;
import com.keunsori.keunsoriserver.domain.member.repository.MemberRepository;
import com.keunsori.keunsoriserver.global.exception.AuthException;
import com.keunsori.keunsoriserver.global.exception.MemberException;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand All @@ -20,6 +26,7 @@ public class AuthController {
private final LoginService loginService;
private final JwtTokenManager jwtTokenManager;
private final RefreshTokenService authService;
private final MemberRepository memberRepository;

@PostMapping("/login")
public ResponseEntity<LoginResponse> login(@Valid @RequestBody LoginRequest loginRequest) {
Expand All @@ -30,22 +37,28 @@ public ResponseEntity<LoginResponse> login(@Valid @RequestBody LoginRequest logi
@PostMapping("/reissue")
public ResponseEntity<LoginResponse> reissue(@RequestHeader("Refresh-Token") String refreshToken){
//Refresh Token에서 studentId 뽑아내기
String studentId= jwtTokenManager.getStudentIdFromToken(refreshToken);
String studentId = jwtTokenManager.getStudentIdFromToken(refreshToken);

Member member = memberRepository.findByStudentId(studentId)
.orElseThrow(() -> new MemberException(MEMBER_NOT_EXISTS_WITH_STUDENT_ID));

//Redis에 저장된 Refresh Token과 일치하는지 확인
String storedRefreshToken=authService.getRefreshToken(studentId);
if(storedRefreshToken==null || !storedRefreshToken.equals(refreshToken)){
String storedRefreshToken = authService.getRefreshToken(studentId);
if(storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)){
throw new AuthException("유효하지 않은 Refresh Token");
}

//새로운 AccessToken 생성
String newAccessToken= jwtTokenManager.generateAccessToken(studentId, "Name", MemberStatus.일반);
String newAccessToken = jwtTokenManager.generateAccessToken(studentId, member.getName(), member.getStatus());

//새로운 Acess Token 반환
return ResponseEntity.ok(new LoginResponse(
newAccessToken,
refreshToken,
String.valueOf(jwtTokenManager.getExpirationTime(newAccessToken))));
String.valueOf(jwtTokenManager.getExpirationTime(newAccessToken)),
member.getName(),
member.getStatus()
));
}
//로그아웃
@PostMapping("/logout")
Expand All @@ -68,6 +81,5 @@ public ResponseEntity<String> validateToken(@RequestHeader("Authorization") Stri
else {
return ResponseEntity.status(401).body("AccessToken 유효하지 않습니다.");
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public LoginResponse login(LoginRequest loginRequest) {

//학번으로 사용자 조회
Member member= memberRepository.findByStudentId(loginRequest.studentId())
.orElseThrow(()->new MemberException("존재하지 않는 학번입니다."));
.orElseThrow(() -> new MemberException("존재하지 않는 학번입니다."));

//비밀번호 일치하는지 검증
if(!passwordEncoder.matches(loginRequest.password(), member.getPassword())){
Expand All @@ -49,8 +49,9 @@ public LoginResponse login(LoginRequest loginRequest) {
return new LoginResponse(
accessToken,
refreshToken,
String.valueOf(jwtTokenManager.getExpirationTime(accessToken)));

String.valueOf(jwtTokenManager.getExpirationTime(accessToken)),
member.getName(),
member.getStatus()
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
import lombok.Getter;


public record LoginResponse(String accessToken, String refreshToken, String accessTokenExpireTime) {}
public record LoginResponse(String accessToken, String refreshToken, String accessTokenExpireTime, String name, MemberStatus memberStatus) {}
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package com.keunsori.keunsoriserver.domain.reservation.domain.validator;

import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.ANOTHER_RESERVATION_EXISTS;
import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.ANOTHER_RESERVATION_ALREADY_EXISTS;
import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.INVALID_RESERVATION_DATE;
import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.INVALID_RESERVATION_TIME;
import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.INVALID_RESERVATION_TYPE;
import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.RESERVATION_ALREADY_COMPLETED;
import static com.keunsori.keunsoriserver.global.exception.ErrorMessage.RESERVATION_NOT_EQUAL_MEMBER;

import org.springframework.stereotype.Component;

import com.keunsori.keunsoriserver.domain.member.domain.Member;
import com.keunsori.keunsoriserver.domain.reservation.domain.Reservation;
import com.keunsori.keunsoriserver.domain.reservation.domain.vo.ReservationType;
import com.keunsori.keunsoriserver.domain.reservation.domain.vo.Session;
import com.keunsori.keunsoriserver.domain.reservation.dto.requset.ReservationCreateRequest;
import com.keunsori.keunsoriserver.domain.reservation.dto.requset.ReservationUpdateRequest;
import com.keunsori.keunsoriserver.domain.reservation.repository.ReservationRepository;
import com.keunsori.keunsoriserver.global.exception.ReservationException;

import java.time.LocalDate;
import java.time.LocalTime;
import lombok.RequiredArgsConstructor;

Expand All @@ -23,48 +28,41 @@ public class ReservationValidator {

private final ReservationRepository reservationRepository;

public void validateReservationCreateForm(ReservationCreateRequest request) {
public void validateReservationFromCreateRequest(ReservationCreateRequest request) {
validateReservationDateIsNotPast(request.reservationDate());
validateReservationTime(request.reservationStartTime(), request.reservationEndTime());

boolean isThereAnotherReservation = reservationRepository.existsAnotherReservationAtDateAndTimePeriod(
validateOtherReservationsNotExist(
ReservationType.from(request.reservationType()),
Session.from(request.reservationSession()),
request.reservationDate(),
request.reservationStartTime().plusMinutes(1),
request.reservationEndTime().minusMinutes(1)
request.reservationStartTime(),
request.reservationEndTime()
);

if (isThereAnotherReservation) {
throw new ReservationException(ANOTHER_RESERVATION_EXISTS);
}
}

public void validateReservationUpdateForm(ReservationUpdateRequest request) {
public void validateReservationFromUpdateRequest(ReservationUpdateRequest request) {
validateReservationDateIsNotPast(request.reservationDate());
validateReservationTime(request.reservationStartTime(), request.reservationEndTime());

boolean isThereAnotherReservation = reservationRepository.existsAnotherReservationAtDateAndTimePeriod(
validateOtherReservationsNotExist(
ReservationType.from(request.reservationType()),
Session.from(request.reservationSession()),
request.reservationDate(),
request.reservationStartTime().plusMinutes(1),
request.reservationEndTime().minusMinutes(1)
request.reservationStartTime(),
request.reservationEndTime()
);

if (isThereAnotherReservation) {
throw new ReservationException(ANOTHER_RESERVATION_EXISTS);
}
}

public void validateReservationDeletable(Reservation reservation, Member loggedInMember) {
validateReservationNotComplete(reservation);
if (loggedInMember.isAdmin()) {
return;
}
validateReservationMember(reservation, loggedInMember);
validateReservationMemberIsOwner(reservation, loggedInMember);
}

public void validateReservationUpdatable(Reservation reservation, Member loggedInMember) {
validateReservationMember(reservation, loggedInMember);
public void validateOriginalReservationUpdatable(Reservation reservation, Member loggedInMember) {
validateReservationMemberIsOwner(reservation, loggedInMember);
validateReservationNotComplete(reservation);
}

private void validateReservationMember(Reservation reservation, Member loggedInMember) {
private void validateReservationMemberIsOwner(Reservation reservation, Member loggedInMember) {
if (!reservation.hasMember(loggedInMember)) {
throw new ReservationException(RESERVATION_NOT_EQUAL_MEMBER);
}
Expand All @@ -81,4 +79,50 @@ private void validateReservationTime(LocalTime startTime, LocalTime endTime) {
throw new ReservationException(INVALID_RESERVATION_TIME);
}
}

private void validateOtherReservationsNotExist(ReservationType reservationType, Session reservationSession, LocalDate reservationDate, LocalTime reservationStartTime, LocalTime reservationEndTime) {
if (reservationType == ReservationType.TEAM) {
validateTeamReservable(reservationDate, reservationStartTime, reservationEndTime);
return;
}

if (reservationType == ReservationType.PERSONAL) {
validatePersonalReservable(reservationSession, reservationDate, reservationStartTime, reservationEndTime);
return;
}

throw new ReservationException(INVALID_RESERVATION_TYPE);
}

private void validateTeamReservable(LocalDate reservationDate, LocalTime reservationStartTime, LocalTime reservationEndTime) {
boolean isThereAnotherReservation = reservationRepository.existsAnotherReservationAtDateAndTimePeriod(
reservationDate,
reservationStartTime.plusMinutes(1),
reservationEndTime.minusMinutes(1)
);

if (isThereAnotherReservation) {
throw new ReservationException(ANOTHER_RESERVATION_ALREADY_EXISTS);
}
}

private void validatePersonalReservable(Session reservationSession, LocalDate reservationDate, LocalTime reservationStartTime, LocalTime reservationEndTime) {
boolean isThereAnotherReservationWithSameSession = reservationRepository
.existsAnotherReservationAtDateAndTimePeriodWithSession(
reservationDate,
reservationSession,
reservationStartTime.plusMinutes(1),
reservationEndTime.minusMinutes(1)
);

if (isThereAnotherReservationWithSameSession) {
throw new ReservationException(ANOTHER_RESERVATION_ALREADY_EXISTS);
}
}

private void validateReservationDateIsNotPast(LocalDate reservationDate) {
if (reservationDate.isBefore(LocalDate.now())) {
throw new ReservationException(INVALID_RESERVATION_DATE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ public record ReservationCreateRequest(
String reservationSession,
@Schema(example = "2025-01-01", type = "string")
LocalDate reservationDate,
@Schema(example = "21:00", type = "string")
@Schema(example = "20:00", type = "string")
LocalTime reservationStartTime,
@Schema(example = "21:00", type = "string")
LocalTime reservationEndTime
) {
public Reservation toEntity(Member member) {
ReservationType reservationType = ReservationType.from(reservationType());
return Reservation.builder()
.reservationType(ReservationType.from(reservationType))
.session(Session.from(reservationSession))
.reservationType(reservationType)
.session(reservationType.equals(ReservationType.TEAM) ? Session.ALL : Session.from(reservationSession))
.date(reservationDate)
.startTime(reservationStartTime)
.endTime(reservationEndTime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.keunsori.keunsoriserver.domain.member.domain.Member;
import com.keunsori.keunsoriserver.domain.reservation.domain.Reservation;
import com.keunsori.keunsoriserver.domain.reservation.domain.vo.Session;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
Expand Down Expand Up @@ -35,4 +36,13 @@ public interface ReservationRepository extends JpaRepository<Reservation, Long>
@Modifying(clearAutomatically = true)
@Query("UPDATE Reservation r SET r.member = null WHERE r.member.id = :memberId")
void unlinkMember(Long memberId);

@Query("SELECT COUNT(r) > 0 "
+ "FROM Reservation r "
+ "WHERE r.date = :date "
+ "AND (r.session = :session OR r.reservationType = 'TEAM') "
+ "AND (r.startTime BETWEEN :start_time AND :end_time "
+ "OR r.endTime BETWEEN :start_time AND :end_time "
+ "OR :start_time BETWEEN r.startTime AND r.endTime)")
boolean existsAnotherReservationAtDateAndTimePeriodWithSession(@Param("date") LocalDate date, @Param("session") Session session, @Param("start_time") LocalTime startTime, @Param("end_time") LocalTime endTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ public List<ReservationResponse> findReservationsByMonth(String yearMonth) {
public Long createReservation(ReservationCreateRequest request) {
Member member = memberUtil.getLoggedInMember();

reservationValidator.validateReservationCreateForm(request);

reservationValidator.validateReservationFromCreateRequest(request);
Reservation reservation = request.toEntity(member);

reservationRepository.save(reservation);
return reservation.getId();
}
Expand All @@ -76,8 +76,8 @@ public void updateReservation(Long reservationId, ReservationUpdateRequest reque
Reservation reservation = reservationRepository.findById(reservationId)
.orElseThrow(() -> new ReservationException(RESERVATION_NOT_EXISTS_WITH_ID));

reservationValidator.validateReservationUpdateForm(request);
reservationValidator.validateReservationUpdatable(reservation, member);
reservationValidator.validateReservationFromUpdateRequest(request);
reservationValidator.validateOriginalReservationUpdatable(reservation, member);

reservation.updateReservation(
ReservationType.from(request.reservationSession()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ public class ErrorMessage {
public static final String RESERVATION_NOT_EXISTS_WITH_ID = "해당 아이디 값을 가진 예약이 존재하지 않습니다.";
public static final String RESERVATION_NOT_EQUAL_MEMBER = "예약한 멤버가 아닙니다.";
public static final String RESERVATION_ALREADY_COMPLETED = "확정된 예약은 수정/취소할 수 없습니다.";
public static final String ANOTHER_RESERVATION_EXISTS = "해당 시간대에 다른 예약이 존재합니다.";
public static final String ANOTHER_RESERVATION_ALREADY_EXISTS = "해당 시간대에 다른 예약이 존재합니다.";
public static final String INVALID_RESERVATION_TIME = "예약 종료 시간은 예약 시작 시간보다 나중이어야 합니다.";
public static final String INVALID_RESERVATION_TYPE = "예약 타입이 잘못되었습니다.";
public static final String INVALID_RESERVATION_DATE = "예약 날짜는 과거 날짜면 안됩니다.";

// Admin Schedule
// Admin Reservation
public static final String INVALID_DATE_SCHEDULE = "설정하는 날짜가 이미 지난 날짜입니다.";
public static final String INVALID_SCHEDULE_TIME = "시작 시간과 끝 시간의 순서가 올바르지 않습니다.";
}
7 changes: 7 additions & 0 deletions src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
spring:
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
1 change: 1 addition & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ spring:
group:
local: "local,datasource"
dev: "dev,datasource"
prod: "prod,datasource"
include:
- redis

Expand Down
Loading

0 comments on commit 7aa1116

Please sign in to comment.