From ab57a78f02bc674818438bcd5d5138302a9cbfcf Mon Sep 17 00:00:00 2001 From: JungTae Kwon Date: Sat, 9 Nov 2024 15:37:50 +0900 Subject: [PATCH] =?UTF-8?q?FIX:=20User=20=EC=97=AD=ED=95=A0=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20Application=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=84=EC=86=8C=ED=99=94=20(#181)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/soongsil/CoffeeChat/entity/User.java | 51 +- .../repository/ApplicationRepository.java | 2 + .../service/ApplicationService.java | 555 +++++++++--------- 3 files changed, 310 insertions(+), 298 deletions(-) diff --git a/src/main/java/com/soongsil/CoffeeChat/entity/User.java b/src/main/java/com/soongsil/CoffeeChat/entity/User.java index 2cac1d2..a2fa304 100644 --- a/src/main/java/com/soongsil/CoffeeChat/entity/User.java +++ b/src/main/java/com/soongsil/CoffeeChat/entity/User.java @@ -26,35 +26,42 @@ //@Inheritance(strategy = InheritanceType.JOINED) //자식 : Mentor, Mentee //@DiscriminatorColumn // 하위 테이블의 구분 컬럼 생성(default = DTYPE) public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") + private Long id; - @Column - private String username; + @Column + private String username; - @Column - private String name; + @Column + private String name; - @Column - private String email; + @Column + private String email; - @Column - private String role; + @Column + private String role; - @Column - private String phoneNum; //전화번호 + @Column + private String phoneNum; //전화번호 - @Column - private String picture; + @Column + private String picture; - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) - @JoinColumn(name = "user_mentor", referencedColumnName = "mentor_id") - private Mentor mentor; + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "user_mentor", referencedColumnName = "mentor_id") + private Mentor mentor; - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) - @JoinColumn(name = "user_mentee", referencedColumnName = "mentee_id") - private Mentee mentee; + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "user_mentee", referencedColumnName = "mentee_id") + private Mentee mentee; + public boolean isMentor() { + return this.mentor != null; + } + + public boolean isMentee() { + return this.mentee != null; + } } diff --git a/src/main/java/com/soongsil/CoffeeChat/repository/ApplicationRepository.java b/src/main/java/com/soongsil/CoffeeChat/repository/ApplicationRepository.java index ec5c9fe..a645096 100644 --- a/src/main/java/com/soongsil/CoffeeChat/repository/ApplicationRepository.java +++ b/src/main/java/com/soongsil/CoffeeChat/repository/ApplicationRepository.java @@ -2,6 +2,7 @@ import java.util.List; +import com.soongsil.CoffeeChat.entity.Mentee; import org.springframework.data.jpa.repository.JpaRepository; import com.soongsil.CoffeeChat.entity.Application; @@ -9,4 +10,5 @@ public interface ApplicationRepository extends JpaRepository { List findApplicationByMentor(Mentor mentor); + List findApplicationByMentee(Mentee mentee); } diff --git a/src/main/java/com/soongsil/CoffeeChat/service/ApplicationService.java b/src/main/java/com/soongsil/CoffeeChat/service/ApplicationService.java index e97713a..9a81a7b 100644 --- a/src/main/java/com/soongsil/CoffeeChat/service/ApplicationService.java +++ b/src/main/java/com/soongsil/CoffeeChat/service/ApplicationService.java @@ -1,36 +1,11 @@ package com.soongsil.CoffeeChat.service; -import static com.soongsil.CoffeeChat.controller.exception.enums.ApplicationErrorCode.*; -import static com.soongsil.CoffeeChat.controller.exception.enums.MentorErrorCode.*; -import static com.soongsil.CoffeeChat.controller.exception.enums.PossibleDateErrorCode.*; -import static com.soongsil.CoffeeChat.controller.exception.enums.UserErrorCode.USER_NOT_FOUND; -import static com.soongsil.CoffeeChat.enums.ApplicationStatus.*; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - import com.soongsil.CoffeeChat.controller.exception.CustomException; import com.soongsil.CoffeeChat.dto.ApplicationCreateRequestDto; import com.soongsil.CoffeeChat.dto.ApplicationCreateResponseDto; import com.soongsil.CoffeeChat.dto.ApplicationGetResponseDto; import com.soongsil.CoffeeChat.dto.ApplicationMatchResponseDto; -import com.soongsil.CoffeeChat.entity.Application; -import com.soongsil.CoffeeChat.entity.Mentee; -import com.soongsil.CoffeeChat.entity.Mentor; -import com.soongsil.CoffeeChat.entity.PossibleDate; -import com.soongsil.CoffeeChat.entity.User; +import com.soongsil.CoffeeChat.entity.*; import com.soongsil.CoffeeChat.enums.ApplicationStatus; import com.soongsil.CoffeeChat.repository.ApplicationRepository; import com.soongsil.CoffeeChat.repository.MenteeRepository; @@ -38,12 +13,35 @@ import com.soongsil.CoffeeChat.repository.PossibleDate.PossibleDateRepository; import com.soongsil.CoffeeChat.repository.User.UserRepository; import com.soongsil.CoffeeChat.util.email.EmailUtil; - import jakarta.mail.MessagingException; import jakarta.persistence.EntityManager; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.soongsil.CoffeeChat.controller.exception.enums.ApplicationErrorCode.APPLICATION_NOT_FOUND; +import static com.soongsil.CoffeeChat.controller.exception.enums.ApplicationErrorCode.INVALID_MATCH_STATUS; +import static com.soongsil.CoffeeChat.controller.exception.enums.MentorErrorCode.MENTOR_NOT_FOUND; +import static com.soongsil.CoffeeChat.controller.exception.enums.PossibleDateErrorCode.POSSIBLE_DATE_NOT_FOUND; +import static com.soongsil.CoffeeChat.controller.exception.enums.PossibleDateErrorCode.PREEMPTED_POSSIBLE_DATE; +import static com.soongsil.CoffeeChat.controller.exception.enums.UserErrorCode.USER_NOT_FOUND; +import static com.soongsil.CoffeeChat.enums.ApplicationStatus.MATCHED; +import static com.soongsil.CoffeeChat.enums.ApplicationStatus.UNMATCHED; @Service @RequiredArgsConstructor @@ -51,254 +49,259 @@ public class ApplicationService { - private final EntityManager em; - private final ApplicationRepository applicationRepository; - private final MentorRepository mentorRepository; - private final MenteeRepository menteeRepository; - private final UserRepository userRepository; - private final PossibleDateRepository possibleDateRepository; - private final EmailUtil emailUtil; - - @Autowired - private ApplicationContext applicationContext; // 프록시를 통해 자신을 호출하기 위해 ApplicationContext 주입 - - @Autowired - private RedisTemplate redisTemplate; - - private User findUserByUsername(String username){ - return userRepository.findByUsername(username) - .orElseThrow(() -> new CustomException( - USER_NOT_FOUND.getHttpStatusCode(), - USER_NOT_FOUND.getErrorMessage()) - ); - } - - @Transactional - public ApplicationCreateResponseDto createApplication(ApplicationCreateRequestDto request, String userName) throws - Exception { - // System.out.println("여긴들어옴"); - // String lockKey = "lock:" + request.getMentorId() + ":" +request.getDate()+":"+ request.getStartTime(); - // ValueOperations valueOperations = redisTemplate.opsForValue(); - // - // boolean isLockAcquired = valueOperations.setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS); - // if (!isLockAcquired) { - // throw new ResponseStatusException(HttpStatus.CONFLICT, "Lock을 획득하지 못하였습니다."); //409반환 - // } - // - // try { - // System.out.println("mentorid: " + request.getMentorId() + ", " + request.getDate() + ", " + request.getStartTime() + ", " + request.getEndTime()); - // User findMentorUser = userRepository.findByMentorIdWithFetch(request.getMentorId()); - // Mentor findMentor = findMentorUser.getMentor(); - // User findMenteeUser = userRepository.findByUsername(userName); - // Mentee findMentee = findMenteeUser.getMentee(); - // - // LocalTime startTime = request.getStartTime(); - // LocalDate date = request.getDate(); - // - // // possibleDate 불러오는 JPQL - // TypedQuery query = em.createQuery( - // "SELECT p FROM PossibleDate p JOIN p.mentor m WHERE m.id = :mentorId AND p.startTime = :startTime AND p.date = :date", - // PossibleDate.class); - // query.setParameter("mentorId", request.getMentorId()); - // query.setParameter("startTime", startTime); - // query.setParameter("date", date); - // - // Optional possibleDateOpt = query.getResultList().stream().findFirst(); - // - // if (possibleDateOpt.isPresent()) { - // PossibleDate possibleDate = possibleDateOpt.get(); - // if (!possibleDate.isActive()) { - // throw new ResponseStatusException(HttpStatus.GONE, "이미 신청된 시간입니다."); //410 반환 - // } - // System.out.println("possibleDate.getId() = " + possibleDate.getId()); - // possibleDate.setActive(false); - // possibleDateRepository.save(possibleDate); - // } else { - // throw new Exception("NOT FOUND"); - // } - // - // Application savedApplication = applicationRepository.save(request.toEntity(findMentor, findMentee)); - // /* - // ApplicationService proxy = applicationContext.getBean(ApplicationService.class); - // proxy.sendApplicationMatchedEmailAsync(findMenteeUser.getEmail(), findMentorUser.getName(), - // findMenteeUser.getName(), savedApplication.getDate(), savedApplication.getStartTime(), - // savedApplication.getEndTime()); - // - // - // */ - // return ApplicationCreateResponse.from(savedApplication); - // } finally { - // redisTemplate.delete(lockKey); - // } - //TODO: Fetch Join - // 가능시간 체크 - PossibleDate requestedPossibleDate = possibleDateRepository.findById(request.getPossibleDateId()) - .orElseThrow(() -> new CustomException( - POSSIBLE_DATE_NOT_FOUND.getHttpStatusCode(), - POSSIBLE_DATE_NOT_FOUND.getErrorMessage()) - ); - log.info("[*] Find possibleDate id: " + requestedPossibleDate.getId()); - - // 선점된 가능시간 - if (!requestedPossibleDate.isActive()) { - log.warn("[*] Found possibleDate(id:" + requestedPossibleDate.getId() + ") is already preempted"); - throw new CustomException( - PREEMPTED_POSSIBLE_DATE.getHttpStatusCode(), - PREEMPTED_POSSIBLE_DATE.getErrorMessage() - ); - } - log.info("[*] Found possibleDate is not preempted"); - - // 가능시간 비활성화 - System.out.println("possibleDate.getId() = " + requestedPossibleDate.getId()); - requestedPossibleDate.setActive(false); - possibleDateRepository.save(requestedPossibleDate); - log.info( - "[*] PossibleDate(id:" + requestedPossibleDate.getId() + ") is just preempted: " - + requestedPossibleDate.isActive() - ); - - // COGO 저장 - User user = findUserByUsername(userName); - Mentee findMentee = user.getMentee(); - Mentor findMentor = mentorRepository.findById(request.getMentorId()) - .orElseThrow(() -> new CustomException( - MENTOR_NOT_FOUND.getHttpStatusCode(), - MENTOR_NOT_FOUND.getErrorMessage()) - ); - return ApplicationCreateResponseDto.from( - applicationRepository.save( - request.toEntity(findMentor, findMentee, request.getMemo(), requestedPossibleDate)) - ); - } - - @Async("mailExecutor") - public void sendApplicationMatchedEmailAsync(String email, String mentorName, String menteeName, LocalDate date, - LocalTime startTime, LocalTime endTime) throws MessagingException { - emailUtil.sendApplicationMatchedEmail(email, mentorName, menteeName, date, startTime, endTime); - } - - //동시성 테스트용 - private static final Logger logger = LoggerFactory.getLogger(ApplicationService.class); - private static final AtomicInteger transactionCounter = new AtomicInteger(0); //트랜잭션마다 ID부여 - - @Transactional - public Application createApplicationIfPossible(Long possibleDateId, Mentor mentor, Mentee mentee) throws Exception { - int transactionId = transactionCounter.incrementAndGet(); //트랜잭션 ID 1씩 증가하며 부여 - MDC.put("transactionId", String.valueOf(transactionId)); //로그에 트랜잭션ID 띄우기 - MDC.put("threadId", String.valueOf(Thread.currentThread().getId())); //로그에 스레드ID 띄우기 - - try { - logger.info("aaa트랜잭션 시작"); - - PossibleDate possibleDate = em.find(PossibleDate.class, possibleDateId); - - if (possibleDate != null && possibleDate.isActive()) { //Active상태면, Application생성 - possibleDate.setActive(false); //중요! active상태를 false로 변경 - em.merge(possibleDate); - - Application application = Application.builder() - .mentor(mentor) - .mentee(mentee) - - .accept(UNMATCHED) - .build(); - em.persist(application); - - logger.info("aaaApplication 생성: {}", application); - return application; - } else { - logger.error("aaaAplication 생성 실패-Active하지 않음."); - throw new Exception("The PossibleDate is already booked or does not exist."); - } - } catch (Exception e) { - logger.error("aaaAplication 생성중 에러: ", e); - throw e; - } finally { - logger.info("aaa트랜잭션 종료"); - MDC.clear(); - } - } - - public ApplicationGetResponseDto getApplication(Long applicationId) { - Application findApplication = applicationRepository.findById(applicationId) - .orElseThrow(() -> new CustomException( - APPLICATION_NOT_FOUND.getHttpStatusCode(), - APPLICATION_NOT_FOUND.getErrorMessage() - )); - User findMenteeUser = userRepository.findByMenteeId(findApplication.getMentee().getId()); - User findMentorUser = userRepository.findByMentor(findApplication.getMentor()); - //TODO: toDTO 빌더 만들어두고, join으로 묶자 - return ApplicationGetResponseDto.builder() - .applicationId(applicationId) - .menteeName(findMenteeUser.getName()) - .mentorName(findMentorUser.getName()) - .memo(findApplication.getMemo()) - .date(findApplication.getPossibleDate().getDate()) - .startTime(findApplication.getPossibleDate().getStartTime()) - .endTime(findApplication.getPossibleDate().getEndTime()) - .build(); - } - - public List getApplications(String username, String applicationStatus) { - if (!"matched".equalsIgnoreCase(applicationStatus) && !"unmatched".equalsIgnoreCase(applicationStatus)) { - log.warn("[*] Requested applicationStatus is not MATCHED or UNMATCHED"); - throw new CustomException( - INVALID_MATCH_STATUS.getHttpStatusCode(), - INVALID_MATCH_STATUS.getErrorMessage() - ); - } - log.info("[*] Find applications with condition [" + applicationStatus + "]"); - - //TODO: JOIN문으로 변경 - List dtos = new ArrayList<>(); - User user = findUserByUsername(username); - Mentor findMentor = user.getMentor(); - List findApplications = applicationRepository.findApplicationByMentor(findMentor); - - for (Application app : findApplications) { - if (app.getAccept() == ApplicationStatus.valueOf(applicationStatus.toUpperCase())) { - User findMenteeUser = userRepository.findByMenteeId(app.getMentee().getId()); - // MATCHED든 UNMATCHED든 둘 중 하나 필터링 된 것들 다 반환 - dtos.add(ApplicationGetResponseDto.toDto( - app, - user.getName(), - findMenteeUser.getName() - )); - } - } - return dtos; - } - - @Transactional - public ApplicationMatchResponseDto updateApplicationStatus(Long applicationId, String decision) { - Application findApplication = applicationRepository.findById(applicationId) - .orElseThrow(() -> new CustomException( - APPLICATION_NOT_FOUND.getHttpStatusCode(), - APPLICATION_NOT_FOUND.getErrorMessage()) - ); - - ApplicationMatchResponseDto responseDto = ApplicationMatchResponseDto.builder() - .applicationId(applicationId) - .build(); - - switch (decision) { - case "reject" -> { - log.warn("[*] Application({}) is deleted", applicationId); - applicationRepository.deleteById(applicationId); - responseDto.setStatus("REJECTED"); - } - case "accept" -> { - findApplication.setAccept(MATCHED); - responseDto.setStatus(MATCHED.name()); - } - default -> throw new CustomException( - INVALID_MATCH_STATUS.getHttpStatusCode(), - INVALID_MATCH_STATUS.getErrorMessage() - ); - } - - return responseDto; - } + private final EntityManager em; + private final ApplicationRepository applicationRepository; + private final MentorRepository mentorRepository; + private final MenteeRepository menteeRepository; + private final UserRepository userRepository; + private final PossibleDateRepository possibleDateRepository; + private final EmailUtil emailUtil; + + @Autowired + private ApplicationContext applicationContext; // 프록시를 통해 자신을 호출하기 위해 ApplicationContext 주입 + + @Autowired + private RedisTemplate redisTemplate; + + private User findUserByUsername(String username) { + return userRepository.findByUsername(username) + .orElseThrow(() -> new CustomException( + USER_NOT_FOUND.getHttpStatusCode(), + USER_NOT_FOUND.getErrorMessage()) + ); + } + + @Transactional + public ApplicationCreateResponseDto createApplication(ApplicationCreateRequestDto request, String userName) throws + Exception { + // System.out.println("여긴들어옴"); + // String lockKey = "lock:" + request.getMentorId() + ":" +request.getDate()+":"+ request.getStartTime(); + // ValueOperations valueOperations = redisTemplate.opsForValue(); + // + // boolean isLockAcquired = valueOperations.setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS); + // if (!isLockAcquired) { + // throw new ResponseStatusException(HttpStatus.CONFLICT, "Lock을 획득하지 못하였습니다."); //409반환 + // } + // + // try { + // System.out.println("mentorid: " + request.getMentorId() + ", " + request.getDate() + ", " + request.getStartTime() + ", " + request.getEndTime()); + // User findMentorUser = userRepository.findByMentorIdWithFetch(request.getMentorId()); + // Mentor findMentor = findMentorUser.getMentor(); + // User findMenteeUser = userRepository.findByUsername(userName); + // Mentee findMentee = findMenteeUser.getMentee(); + // + // LocalTime startTime = request.getStartTime(); + // LocalDate date = request.getDate(); + // + // // possibleDate 불러오는 JPQL + // TypedQuery query = em.createQuery( + // "SELECT p FROM PossibleDate p JOIN p.mentor m WHERE m.id = :mentorId AND p.startTime = :startTime AND p.date = :date", + // PossibleDate.class); + // query.setParameter("mentorId", request.getMentorId()); + // query.setParameter("startTime", startTime); + // query.setParameter("date", date); + // + // Optional possibleDateOpt = query.getResultList().stream().findFirst(); + // + // if (possibleDateOpt.isPresent()) { + // PossibleDate possibleDate = possibleDateOpt.get(); + // if (!possibleDate.isActive()) { + // throw new ResponseStatusException(HttpStatus.GONE, "이미 신청된 시간입니다."); //410 반환 + // } + // System.out.println("possibleDate.getId() = " + possibleDate.getId()); + // possibleDate.setActive(false); + // possibleDateRepository.save(possibleDate); + // } else { + // throw new Exception("NOT FOUND"); + // } + // + // Application savedApplication = applicationRepository.save(request.toEntity(findMentor, findMentee)); + // /* + // ApplicationService proxy = applicationContext.getBean(ApplicationService.class); + // proxy.sendApplicationMatchedEmailAsync(findMenteeUser.getEmail(), findMentorUser.getName(), + // findMenteeUser.getName(), savedApplication.getDate(), savedApplication.getStartTime(), + // savedApplication.getEndTime()); + // + // + // */ + // return ApplicationCreateResponse.from(savedApplication); + // } finally { + // redisTemplate.delete(lockKey); + // } + //TODO: Fetch Join + // 가능시간 체크 + PossibleDate requestedPossibleDate = possibleDateRepository.findById(request.getPossibleDateId()) + .orElseThrow(() -> new CustomException( + POSSIBLE_DATE_NOT_FOUND.getHttpStatusCode(), + POSSIBLE_DATE_NOT_FOUND.getErrorMessage()) + ); + log.info("[*] Find possibleDate id: " + requestedPossibleDate.getId()); + + // 선점된 가능시간 + if (!requestedPossibleDate.isActive()) { + log.warn("[*] Found possibleDate(id:" + requestedPossibleDate.getId() + ") is already preempted"); + throw new CustomException( + PREEMPTED_POSSIBLE_DATE.getHttpStatusCode(), + PREEMPTED_POSSIBLE_DATE.getErrorMessage() + ); + } + log.info("[*] Found possibleDate is not preempted"); + + // 가능시간 비활성화 + System.out.println("possibleDate.getId() = " + requestedPossibleDate.getId()); + requestedPossibleDate.setActive(false); + possibleDateRepository.save(requestedPossibleDate); + log.info( + "[*] PossibleDate(id:" + requestedPossibleDate.getId() + ") is just preempted: " + + requestedPossibleDate.isActive() + ); + + // COGO 저장 + User user = findUserByUsername(userName); + Mentee findMentee = user.getMentee(); + Mentor findMentor = mentorRepository.findById(request.getMentorId()) + .orElseThrow(() -> new CustomException( + MENTOR_NOT_FOUND.getHttpStatusCode(), + MENTOR_NOT_FOUND.getErrorMessage()) + ); + return ApplicationCreateResponseDto.from( + applicationRepository.save( + request.toEntity(findMentor, findMentee, request.getMemo(), requestedPossibleDate)) + ); + } + + @Async("mailExecutor") + public void sendApplicationMatchedEmailAsync(String email, String mentorName, String menteeName, LocalDate date, + LocalTime startTime, LocalTime endTime) throws MessagingException { + emailUtil.sendApplicationMatchedEmail(email, mentorName, menteeName, date, startTime, endTime); + } + + //동시성 테스트용 + private static final Logger logger = LoggerFactory.getLogger(ApplicationService.class); + private static final AtomicInteger transactionCounter = new AtomicInteger(0); //트랜잭션마다 ID부여 + + @Transactional + public Application createApplicationIfPossible(Long possibleDateId, Mentor mentor, Mentee mentee) throws Exception { + int transactionId = transactionCounter.incrementAndGet(); //트랜잭션 ID 1씩 증가하며 부여 + MDC.put("transactionId", String.valueOf(transactionId)); //로그에 트랜잭션ID 띄우기 + MDC.put("threadId", String.valueOf(Thread.currentThread().getId())); //로그에 스레드ID 띄우기 + + try { + logger.info("aaa트랜잭션 시작"); + + PossibleDate possibleDate = em.find(PossibleDate.class, possibleDateId); + + if (possibleDate != null && possibleDate.isActive()) { //Active상태면, Application생성 + possibleDate.setActive(false); //중요! active상태를 false로 변경 + em.merge(possibleDate); + + Application application = Application.builder() + .mentor(mentor) + .mentee(mentee) + + .accept(UNMATCHED) + .build(); + em.persist(application); + + logger.info("aaaApplication 생성: {}", application); + return application; + } else { + logger.error("aaaAplication 생성 실패-Active하지 않음."); + throw new Exception("The PossibleDate is already booked or does not exist."); + } + } catch (Exception e) { + logger.error("aaaAplication 생성중 에러: ", e); + throw e; + } finally { + logger.info("aaa트랜잭션 종료"); + MDC.clear(); + } + } + + public ApplicationGetResponseDto getApplication(Long applicationId) { + Application findApplication = applicationRepository.findById(applicationId) + .orElseThrow(() -> new CustomException( + APPLICATION_NOT_FOUND.getHttpStatusCode(), + APPLICATION_NOT_FOUND.getErrorMessage() + )); + User findMenteeUser = userRepository.findByMenteeId(findApplication.getMentee().getId()); + User findMentorUser = userRepository.findByMentor(findApplication.getMentor()); + //TODO: toDTO 빌더 만들어두고, join으로 묶자 + return ApplicationGetResponseDto.builder() + .applicationId(applicationId) + .menteeName(findMenteeUser.getName()) + .mentorName(findMentorUser.getName()) + .memo(findApplication.getMemo()) + .date(findApplication.getPossibleDate().getDate()) + .startTime(findApplication.getPossibleDate().getStartTime()) + .endTime(findApplication.getPossibleDate().getEndTime()) + .build(); + } + + public List getApplications(String username, String applicationStatus) { + if (!"matched".equalsIgnoreCase(applicationStatus) && !"unmatched".equalsIgnoreCase(applicationStatus)) { + log.warn("[*] Requested applicationStatus is not MATCHED or UNMATCHED"); + throw new CustomException( + INVALID_MATCH_STATUS.getHttpStatusCode(), + INVALID_MATCH_STATUS.getErrorMessage() + ); + } + log.info("[*] Find applications with condition [" + applicationStatus + "]"); + + //TODO: JOIN문으로 변경 + List dtos = new ArrayList<>(); + User user = findUserByUsername(username); + List findApplications; + + findApplications = user.isMentor() ? + applicationRepository.findApplicationByMentor(user.getMentor()) : + user.isMentee() ? + applicationRepository.findApplicationByMentee(user.getMentee()) : + Collections.emptyList(); + + for (Application app : findApplications) { + if (app.getAccept() == ApplicationStatus.valueOf(applicationStatus.toUpperCase())) { + User findMenteeUser = userRepository.findByMenteeId(app.getMentee().getId()); + // MATCHED든 UNMATCHED든 둘 중 하나 필터링 된 것들 다 반환 + dtos.add(ApplicationGetResponseDto.toDto( + app, + user.getName(), + findMenteeUser.getName() + )); + } + } + return dtos; + } + + @Transactional + public ApplicationMatchResponseDto updateApplicationStatus(Long applicationId, String decision) { + Application findApplication = applicationRepository.findById(applicationId) + .orElseThrow(() -> new CustomException( + APPLICATION_NOT_FOUND.getHttpStatusCode(), + APPLICATION_NOT_FOUND.getErrorMessage()) + ); + + ApplicationMatchResponseDto responseDto = ApplicationMatchResponseDto.builder() + .applicationId(applicationId) + .build(); + + switch (decision) { + case "reject" -> { + log.warn("[*] Application({}) is deleted", applicationId); + applicationRepository.deleteById(applicationId); + responseDto.setStatus("REJECTED"); + } + case "accept" -> { + findApplication.setAccept(MATCHED); + responseDto.setStatus(MATCHED.name()); + } + default -> throw new CustomException( + INVALID_MATCH_STATUS.getHttpStatusCode(), + INVALID_MATCH_STATUS.getErrorMessage() + ); + } + + return responseDto; + } }