From 0179af6cad0b801bdecc34dfb20b9ec2b3757290 Mon Sep 17 00:00:00 2001 From: space Date: Sat, 12 Aug 2023 19:29:16 +0900 Subject: [PATCH 01/21] =?UTF-8?q?[BE]=20REFACTOR:=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ftclub/cabinet/utils/scheduler/SystemScheduler.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java index 00c1ec84d..0e3c0b51e 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java @@ -29,6 +29,8 @@ public class SystemScheduler { private final UserService userService; private final BlackholeManager blackholeManager; + private final long DELAY_TIME = 2000; + /** * 매일 자정마다 대여 기록을 확인하여, 연체 메일 발송 및 휴학생 처리를 트리거하는 메소드 */ @@ -41,7 +43,7 @@ public void checkAllLents() { leaveAbsenceManager.handleLeaveAbsence(activeLent.getUserId(), activeLent.getName()); // 2초 간격으로 대여 검증 try { - Thread.sleep(2000); + Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { log.error(e.getMessage()); } @@ -59,7 +61,7 @@ public void checkRiskOfBlackhole() { blackholeManager.handleBlackhole(blackholeInfo); // 2초 간격으로 블랙홀 검증 try { - Thread.sleep(2000); + Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { log.error(e.getMessage()); } @@ -77,7 +79,7 @@ public void checkNoRiskOfBlackhole() { blackholeManager.handleBlackhole(blackholeInfo); // 2초 간격으로 블랙홀 검증 try { - Thread.sleep(2000); + Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { log.error(e.getMessage()); } From 2d3a7019413a6e84c196bae72004b9233c998ef4 Mon Sep 17 00:00:00 2001 From: space Date: Sat, 12 Aug 2023 19:30:44 +0900 Subject: [PATCH 02/21] =?UTF-8?q?[BE]=20REFACTOR:=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EC=88=98=EC=A0=95=20=EC=BD=94=EB=A9=98?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/ftclub/cabinet/utils/scheduler/SystemScheduler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java index 0e3c0b51e..f370fff9b 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java @@ -33,6 +33,7 @@ public class SystemScheduler { /** * 매일 자정마다 대여 기록을 확인하여, 연체 메일 발송 및 휴학생 처리를 트리거하는 메소드 + * 2초 간격으로 블랙홀 검증 */ @Scheduled(cron = "${spring.schedule.cron.leave-absence}") public void checkAllLents() { @@ -41,7 +42,6 @@ public void checkAllLents() { for (ActiveLentHistoryDto activeLent : activeLents) { overdueManager.handleOverdue(activeLent); leaveAbsenceManager.handleLeaveAbsence(activeLent.getUserId(), activeLent.getName()); - // 2초 간격으로 대여 검증 try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { @@ -52,6 +52,7 @@ public void checkAllLents() { /** * 매주 월요일 자정 42분에 블랙홀에 빠진 유저 처리를 트리거하는 메소드 + * 2초 간격으로 블랙홀 검증 */ @Scheduled(cron = "${spring.schedule.cron.risk-of-blackhole}") public void checkRiskOfBlackhole() { @@ -59,7 +60,6 @@ public void checkRiskOfBlackhole() { List blackholeInfos = userService.getAllRiskOfBlackholeInfo(); for (UserBlackholeInfoDto blackholeInfo : blackholeInfos) { blackholeManager.handleBlackhole(blackholeInfo); - // 2초 간격으로 블랙홀 검증 try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { @@ -70,6 +70,7 @@ public void checkRiskOfBlackhole() { /** * 매월 1일 01시 42분에 블랙홀에 빠질 위험이 없는 유저들의 블랙홀 처리를 트리거하는 메소드 + * 2초 간격으로 블랙홀 검증 */ @Scheduled(cron = "${spring.schedule.cron.no-risk-of-blackhole}") public void checkNoRiskOfBlackhole() { @@ -77,7 +78,6 @@ public void checkNoRiskOfBlackhole() { List blackholeInfos = userService.getAllNoRiskOfBlackholeInfo(); for (UserBlackholeInfoDto blackholeInfo : blackholeInfos) { blackholeManager.handleBlackhole(blackholeInfo); - // 2초 간격으로 블랙홀 검증 try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { From 5dd877a1f0ea87d97477dff4e5f349698cf820af Mon Sep 17 00:00:00 2001 From: space Date: Sat, 12 Aug 2023 23:33:15 +0900 Subject: [PATCH 03/21] =?UTF-8?q?[BE]=20FIX:=20=EB=A1=9C=EA=B1=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/log4j2-local.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/main/resources/log4j2-local.yml b/backend/src/main/resources/log4j2-local.yml index 83f5a42a6..bfe1db4f9 100644 --- a/backend/src/main/resources/log4j2-local.yml +++ b/backend/src/main/resources/log4j2-local.yml @@ -18,13 +18,13 @@ Configuration: - name: org.springframework # local 환경에서는 debug, production 환경에서는 info - level: debug + level: info additivity: false AppenderRef: - ref: console - name: org.ftclub.cabinet - level: debug + level: ㅑ루ㅐ additivity: false AppenderRef: - ref: console From a6a0cd1b521ea9e30176783c6e9b45963367b79e Mon Sep 17 00:00:00 2001 From: Woo Joo Chae Date: Mon, 14 Aug 2023 23:49:13 +0900 Subject: [PATCH 04/21] [BE] REFACTOR: handlePolicyStatus method moved to service --- .../cabinet/exception/ExceptionStatus.java | 4 ++ .../lent/repository/LentOptionalFetcher.java | 36 ----------------- .../user/repository/UserOptionalFetcher.java | 9 +++++ .../blackhole/manager/BlackholeManager.java | 6 +-- .../blackhole/manager/BlackholeRefresher.java | 39 +++++++++++++++++++ 5 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java index 8c4f399a0..ce59d7f79 100644 --- a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java +++ b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java @@ -51,4 +51,8 @@ public enum ExceptionStatus { this.message = message; this.error = status.getReasonPhrase(); } + + public static ExceptionStatus createExceptionStatus(HttpStatus status, String message) { + return new ExceptionStatus(status, message); + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java index 844b3eadc..d1c81f851 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java @@ -10,7 +10,6 @@ import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; import org.ftclub.cabinet.lent.domain.LentHistory; -import org.ftclub.cabinet.lent.domain.LentPolicyStatus; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -86,41 +85,6 @@ public LentHistory getActiveLentHistoryWithUserId(Long userId) { .orElseThrow(() -> new ServiceException(ExceptionStatus.NO_LENT_CABINET)); } - /** - * 정책에 대한 결과 상태({@link LentPolicyStatus})에 맞는 적절한 {@link ServiceException}을 throw합니다. - * - * @param status 정책에 대한 결과 상태 - * @throws ServiceException 정책에 따라 다양한 exception이 throw될 수 있습니다. - */ - public void handlePolicyStatus(LentPolicyStatus status) { - log.info("Called handlePolicyStatus status: {}", status); - switch (status) { - case FINE: - break; - case BROKEN_CABINET: - throw new ServiceException(ExceptionStatus.LENT_BROKEN); - case FULL_CABINET: - throw new ServiceException(ExceptionStatus.LENT_FULL); - case OVERDUE_CABINET: - throw new ServiceException(ExceptionStatus.LENT_EXPIRED); - case LENT_CLUB: - throw new ServiceException(ExceptionStatus.LENT_CLUB); - case IMMINENT_EXPIRATION: - throw new ServiceException(ExceptionStatus.LENT_EXPIRE_IMMINENT); - case ALREADY_LENT_USER: - throw new ServiceException(ExceptionStatus.LENT_ALREADY_EXISTED); - case ALL_BANNED_USER: - throw new ServiceException(ExceptionStatus.ALL_BANNED_USER); - case SHARE_BANNED_USER: - throw new ServiceException(ExceptionStatus.SHARE_BANNED_USER); - case BLACKHOLED_USER: - throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); - case NOT_USER: - case INTERNAL_ERROR: - default: - throw new ServiceException(ExceptionStatus.INTERNAL_SERVER_ERROR); - } - } /** * 사물함에 남은 자리가 있는 지 확인합니다. 남은 자리가 없으면 throw합니다. diff --git a/backend/src/main/java/org/ftclub/cabinet/user/repository/UserOptionalFetcher.java b/backend/src/main/java/org/ftclub/cabinet/user/repository/UserOptionalFetcher.java index 0386d7e44..69e7b0527 100644 --- a/backend/src/main/java/org/ftclub/cabinet/user/repository/UserOptionalFetcher.java +++ b/backend/src/main/java/org/ftclub/cabinet/user/repository/UserOptionalFetcher.java @@ -2,6 +2,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.exception.DomainException; @@ -238,4 +239,12 @@ public BanHistory getRecentBanHistory(Long userId) { } return banHistory.get(0); } + + public BanHistory getActiveBanHistory(Long userId) { + log.debug("Called getActiveBanHistory: {}", userId); + Optional banHistory = banHistoryRepository.findRecentActiveBanHistoryByUserId( + userId, + LocalDateTime.now()); + return banHistory.get(); + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index 2c3b7ee93..593f61d0f 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -22,6 +22,7 @@ public class BlackholeManager { private final FtApiManager ftAPIManager; private final LentService lentService; private final UserService userService; + private final BlackholeRefresher blackholeRefresher; /** * JsonNode에 담긴 cursus_users를 확인하여 해당 유저가 카뎃인지 확인한다. cursus_users에 담긴 정보가 2개 이상이면 카뎃이다. @@ -32,7 +33,7 @@ public class BlackholeManager { */ private Boolean isValidCadet(JsonNode jsonUserInfo) { log.info("isValidCadet {}", jsonUserInfo); - return jsonUserInfo.get("cursus_users").size() >= 2; + return jsonUserInfo.get("cursus_users").size() > 3; } /** @@ -123,8 +124,7 @@ public void handleBlackhole(UserBlackholeInfoDto userBlackholeInfoDto) { log.info("called handleBlackhole {}", userBlackholeInfoDto); LocalDateTime now = LocalDateTime.now(); try { - JsonNode jsonUserInfo = ftAPIManager.getFtUsersInfoByName( - userBlackholeInfoDto.getName()); + JsonNode jsonUserInfo = blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto); if (!isValidCadet(jsonUserInfo)) { handleNotCadet(userBlackholeInfoDto, now); return; diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java new file mode 100644 index 000000000..e88f09c45 --- /dev/null +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -0,0 +1,39 @@ +package org.ftclub.cabinet.utils.blackhole.manager; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.ftclub.cabinet.auth.service.FtApiManager; +import org.ftclub.cabinet.dto.UserBlackholeInfoDto; +import org.ftclub.cabinet.exception.ServiceException; +import org.ftclub.cabinet.user.service.UserService; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Log4j2 +public class BlackholeRefresher { + + private final FtApiManager ftApiManager; + private final UserService userService; + + /** + * 유저의 블랙홀 정보를 찾아온다. + * + * @param userBlackholeInfoDto + * @return JsonNode + * @throws ServiceException + */ + public JsonNode getBlackholeInfo(UserBlackholeInfoDto userBlackholeInfoDto) + throws ServiceException { + log.info("called refreshBlackhole{}", userBlackholeInfoDto); + return ftApiManager.getFtUsersInfoByName( + userBlackholeInfoDto.getName()); + } + + public JsonNode getBlackholeInfo2(UserBlackholeInfoDto userBlackholeInfoDto) + throws ServiceException { + log.info("called refreshBlackhole{}", userBlackholeInfoDto); + getBlackholeInfo(userBlackholeInfoDto); + } +} From 36bd42fbe53e44980371e4d0fea9080325216a55 Mon Sep 17 00:00:00 2001 From: Woo Joo Chae Date: Mon, 14 Aug 2023 23:50:07 +0900 Subject: [PATCH 05/21] =?UTF-8?q?[BE]=20WIP:=20banned=20user=20=EC=9E=94?= =?UTF-8?q?=EC=97=AC=EB=82=A0=EC=A7=9C=ED=91=9C=EA=B8=B0=20&=20blackhole?= =?UTF-8?q?=20=EA=B7=BC=EC=A0=91=EC=9C=A0=EC=A0=80=20=EB=8C=80=EC=97=AC?= =?UTF-8?q?=EC=8B=9C=20=EC=B2=B4=ED=81=AC=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cabinet/lent/domain/LentPolicyImpl.java | 23 +- .../cabinet/lent/service/LentServiceImpl.java | 301 ++++++++++-------- 2 files changed, 185 insertions(+), 139 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java index 776c13c61..84fe16571 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java @@ -1,7 +1,7 @@ package org.ftclub.cabinet.lent.domain; -import java.time.LocalDate; -import java.util.Date; +import java.time.LocalDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.cabinet.domain.Cabinet; @@ -14,17 +14,16 @@ import org.ftclub.cabinet.user.domain.User; import org.ftclub.cabinet.user.domain.UserRole; import org.ftclub.cabinet.utils.DateUtil; +import org.ftclub.cabinet.utils.blackhole.manager.BlackholeRefresher; import org.springframework.stereotype.Component; -import java.time.LocalDateTime; -import java.util.List; - @Component @RequiredArgsConstructor @Log4j2 public class LentPolicyImpl implements LentPolicy { private final CabinetProperties cabinetProperties; + private final BlackholeRefresher blackholeRefresher; private LocalDateTime generateSharedCabinetExpirationDate(LocalDateTime now, CabinetStatus cabinetStatus, LentHistory activeLentHistory) { @@ -78,10 +77,11 @@ public LocalDateTime generateExpirationDate(LocalDateTime now, Cabinet cabinet, @Override public void applyExpirationDate(LentHistory curHistory, List beforeActiveHistories, LocalDateTime expiredAt) { - log.info("Called applyExpirationDate curHistory: {}, beforeActiveHistories: {}, expiredAt: {}", + log.info( + "Called applyExpirationDate curHistory: {}, beforeActiveHistories: {}, expiredAt: {}", curHistory, beforeActiveHistories, expiredAt); - if (expiredAt == null){ + if (expiredAt == null) { throw new DomainException(ExceptionStatus.INVALID_ARGUMENT); } @@ -112,10 +112,11 @@ public LentPolicyStatus verifyUserForLent(User user, Cabinet cabinet, int userAc // BlackholeManager는 스케줄러에 의해 빈에 등록되는 컴포넌트이므로 // 현재 구조상으로는 @Lazy 어노테이션을 통해 순환 참조 문제를 해결할 수 없습니다. // 추후 다른 방식으로 구조적인 리팩토링이 필요한 부분입니다..! -// if (user.getBlackholedAt() != null && user.getBlackholedAt() -// .isBefore(LocalDateTime.now())) { -// return LentPolicyStatus.BLACKHOLED_USER; -// } + if (user.getBlackholedAt() != null && user.getBlackholedAt() + .isBefore(LocalDateTime.now())) { +// blackholeRefresher.getBlackholeInfo(user.get) + return LentPolicyStatus.BLACKHOLED_USER; + } // 유저가 페널티 2 종류 이상 받을 수 있나? <- 실제로 그럴리 없지만 lentPolicy 객체는 그런 사실을 모르고, 유연하게 구현? if (userActiveBanList == null || userActiveBanList.size() == 0) { return LentPolicyStatus.FINE; diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java index 6aac3db9f..5b02ab0ba 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java @@ -1,12 +1,19 @@ package org.ftclub.cabinet.lent.service; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; +import javax.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.cabinet.domain.Cabinet; import org.ftclub.cabinet.cabinet.repository.CabinetOptionalFetcher; import org.ftclub.cabinet.dto.ActiveLentHistoryDto; +import org.ftclub.cabinet.exception.ExceptionStatus; +import org.ftclub.cabinet.exception.ServiceException; import org.ftclub.cabinet.lent.domain.LentHistory; import org.ftclub.cabinet.lent.domain.LentPolicy; +import org.ftclub.cabinet.lent.domain.LentPolicyStatus; import org.ftclub.cabinet.lent.repository.LentOptionalFetcher; import org.ftclub.cabinet.lent.repository.LentRepository; import org.ftclub.cabinet.mapper.LentMapper; @@ -17,147 +24,185 @@ import org.ftclub.cabinet.user.service.UserService; import org.springframework.stereotype.Service; -import javax.transaction.Transactional; -import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; - @Service @RequiredArgsConstructor @Transactional @Log4j2 public class LentServiceImpl implements LentService { - private final LentRepository lentRepository; - private final LentPolicy lentPolicy; - private final LentOptionalFetcher lentOptionalFetcher; - private final CabinetOptionalFetcher cabinetOptionalFetcher; - private final UserOptionalFetcher userExceptionHandler; - private final UserService userService; - private final BanHistoryRepository banHistoryRepository; - private final LentMapper lentMapper; + private final LentRepository lentRepository; + private final LentPolicy lentPolicy; + private final LentOptionalFetcher lentOptionalFetcher; + private final CabinetOptionalFetcher cabinetOptionalFetcher; + private final UserOptionalFetcher userOptionalFetcher; + private final UserService userService; + private final BanHistoryRepository banHistoryRepository; + private final LentMapper lentMapper; + + @Override + public void startLentCabinet(Long userId, Long cabinetId) { + log.info("Called startLentCabinet: {}, {}", userId, cabinetId); + LocalDateTime now = LocalDateTime.now(); + Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); + User user = userOptionalFetcher.getUser(userId); + int userActiveLentCount = lentRepository.countUserActiveLent(userId); + List userActiveBanList = banHistoryRepository.findUserActiveBanList(userId, + now); + // 대여 가능한 유저인지 확인 + //BanHistory activeBanHistory = userOptionalFetcher.getActiveBanHistory(userId); + handlePolicyStatus( + lentPolicy.verifyUserForLent(user, cabinet, userActiveLentCount, + userActiveBanList)); + List cabinetActiveLentHistories = lentRepository.findAllActiveLentByCabinetId( + cabinetId); + // 대여 가능한 캐비넷인지 확인 + handlePolicyStatus( + lentPolicy.verifyCabinetForLent(cabinet, cabinetActiveLentHistories, + now)); + // 캐비넷 상태 변경 + cabinet.specifyStatusByUserCount(cabinetActiveLentHistories.size() + 1); + LocalDateTime expiredAt = lentPolicy.generateExpirationDate(now, cabinet, + cabinetActiveLentHistories); + LentHistory lentHistory = LentHistory.of(now, expiredAt, userId, cabinetId); + // 연체 시간 적용 + lentPolicy.applyExpirationDate(lentHistory, cabinetActiveLentHistories, expiredAt); + lentRepository.save(lentHistory); + } + + @Override + public void startLentClubCabinet(Long userId, Long cabinetId) { + log.debug("Called startLentClubCabinet: {}, {}", userId, cabinetId); + Cabinet cabinet = cabinetOptionalFetcher.getClubCabinet(cabinetId); + lentOptionalFetcher.checkExistedSpace(cabinetId); + LocalDateTime expirationDate = lentPolicy.generateExpirationDate(LocalDateTime.now(), + cabinet, null); + LentHistory result = + LentHistory.of(LocalDateTime.now(), expirationDate, userId, cabinetId); + lentRepository.save(result); + cabinet.specifyStatusByUserCount(1); // todo : policy에서 관리 + } - @Override - public void startLentCabinet(Long userId, Long cabinetId) { - log.info("Called startLentCabinet: {}, {}", userId, cabinetId); - LocalDateTime now = LocalDateTime.now(); - Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); - User user = userExceptionHandler.getUser(userId); - int userActiveLentCount = lentRepository.countUserActiveLent(userId); - List userActiveBanList = banHistoryRepository.findUserActiveBanList(userId, - now); - // 대여 가능한 유저인지 확인 - lentOptionalFetcher.handlePolicyStatus( - lentPolicy.verifyUserForLent(user, cabinet, userActiveLentCount, - userActiveBanList)); - List cabinetActiveLentHistories = lentRepository.findAllActiveLentByCabinetId( - cabinetId); - // 대여 가능한 캐비넷인지 확인 - lentOptionalFetcher.handlePolicyStatus( - lentPolicy.verifyCabinetForLent(cabinet, cabinetActiveLentHistories, - now)); - // 캐비넷 상태 변경 - cabinet.specifyStatusByUserCount(cabinetActiveLentHistories.size() + 1); - LocalDateTime expiredAt = lentPolicy.generateExpirationDate(now, cabinet, - cabinetActiveLentHistories); - LentHistory lentHistory = LentHistory.of(now, expiredAt, userId, cabinetId); - // 연체 시간 적용 - lentPolicy.applyExpirationDate(lentHistory, cabinetActiveLentHistories, expiredAt); - lentRepository.save(lentHistory); - } + @Override + public void endLentCabinet(Long userId) { + log.debug("Called endLentCabinet: {}", userId); + LentHistory lentHistory = returnCabinetByUserId(userId); + Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(lentHistory.getCabinetId()); + // cabinetType도 인자로 전달하면 좋을 거 같습니다 (공유사물함 3일이내 반납 페널티) + userService.banUser(userId, cabinet.getLentType(), lentHistory.getStartedAt(), + lentHistory.getEndedAt(), lentHistory.getExpiredAt()); + } - @Override - public void startLentClubCabinet(Long userId, Long cabinetId) { - log.debug("Called startLentClubCabinet: {}, {}", userId, cabinetId); - Cabinet cabinet = cabinetOptionalFetcher.getClubCabinet(cabinetId); - lentOptionalFetcher.checkExistedSpace(cabinetId); - LocalDateTime expirationDate = lentPolicy.generateExpirationDate(LocalDateTime.now(), - cabinet, null); - LentHistory result = - LentHistory.of(LocalDateTime.now(), expirationDate, userId, cabinetId); - lentRepository.save(result); - cabinet.specifyStatusByUserCount(1); // todo : policy에서 관리 - } + @Override + public void terminateLentCabinet(Long userId) { + log.debug("Called terminateLentCabinet: {}", userId); + returnCabinetByUserId(userId); + } - @Override - public void endLentCabinet(Long userId) { - log.debug("Called endLentCabinet: {}", userId); - LentHistory lentHistory = returnCabinetByUserId(userId); - Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(lentHistory.getCabinetId()); - // cabinetType도 인자로 전달하면 좋을 거 같습니다 (공유사물함 3일이내 반납 페널티) - userService.banUser(userId, cabinet.getLentType(), lentHistory.getStartedAt(), - lentHistory.getEndedAt(), lentHistory.getExpiredAt()); - } + @Override + public void terminateLentByCabinetId(Long cabinetId) { + log.debug("Called terminateLentByCabinetId: {}", cabinetId); + returnCabinetByCabinetId(cabinetId); + } - @Override - public void terminateLentCabinet(Long userId) { - log.debug("Called terminateLentCabinet: {}", userId); - returnCabinetByUserId(userId); - } + // cabinetId로 return하는 경우에서, 공유 사물함과 개인 사물함의 경우에 대한 분기가 되어 있지 않음. + // 또한 어드민의 경우에서 사용하는 returnByCabinetId와 유저가 사용하는 returnByCabinetId가 다른 상황이므로 + // (어드민의 경우에는 뭐든지 전체 반납, 유저가 사용하는 경우에는 본인이 사용하는 사물함에 대한 반납) + // 유저가 사용하는 경우에 대해서는 userId로만 쓰게하든, 한 방식으로만 사용하게끔 해야함 - 함수를 쪼갤 가능성도 있음. + // 우선 현재 관리자만 쓰고 있고, 한 군데에서만 사용되므로 List로 전체 반납을 하도록 구현, 이에 대한 논의는 TO-DO + private List returnCabinetByCabinetId(Long cabinetId) { + log.debug("Called returnCabinetByCabinetId: {}", cabinetId); + Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); + List lentHistories = lentOptionalFetcher.findAllActiveLentByCabinetId( + cabinetId); + lentHistories.forEach(lentHistory -> lentHistory.endLent(LocalDateTime.now())); + cabinet.specifyStatusByUserCount(0); // policy로 빼는게..? + cabinet.writeMemo(""); + cabinet.writeTitle(""); + return lentHistories; + } - @Override - public void terminateLentByCabinetId(Long cabinetId) { - log.debug("Called terminateLentByCabinetId: {}", cabinetId); - returnCabinetByCabinetId(cabinetId); - } + private LentHistory returnCabinetByUserId(Long userId) { + log.debug("Called returnCabinet: {}", userId); + userOptionalFetcher.getUser(userId); + LentHistory lentHistory = lentOptionalFetcher.getActiveLentHistoryWithUserId(userId); + Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(lentHistory.getCabinetId()); + int activeLentCount = lentRepository.countCabinetActiveLent(lentHistory.getCabinetId()); + lentHistory.endLent(LocalDateTime.now()); + cabinet.specifyStatusByUserCount(activeLentCount - 1); // policy로 빠질만한 부분인듯? + if (activeLentCount - 1 == 0) { + cabinet.writeMemo(""); + cabinet.writeTitle(""); + } + return lentHistory; + } - // cabinetId로 return하는 경우에서, 공유 사물함과 개인 사물함의 경우에 대한 분기가 되어 있지 않음. - // 또한 어드민의 경우에서 사용하는 returnByCabinetId와 유저가 사용하는 returnByCabinetId가 다른 상황이므로 - // (어드민의 경우에는 뭐든지 전체 반납, 유저가 사용하는 경우에는 본인이 사용하는 사물함에 대한 반납) - // 유저가 사용하는 경우에 대해서는 userId로만 쓰게하든, 한 방식으로만 사용하게끔 해야함 - 함수를 쪼갤 가능성도 있음. - // 우선 현재 관리자만 쓰고 있고, 한 군데에서만 사용되므로 List로 전체 반납을 하도록 구현, 이에 대한 논의는 TO-DO - private List returnCabinetByCabinetId(Long cabinetId) { - log.debug("Called returnCabinetByCabinetId: {}", cabinetId); - Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); - List lentHistories = lentOptionalFetcher.findAllActiveLentByCabinetId( - cabinetId); - lentHistories.forEach(lentHistory -> lentHistory.endLent(LocalDateTime.now())); - cabinet.specifyStatusByUserCount(0); // policy로 빼는게..? - cabinet.writeMemo(""); - cabinet.writeTitle(""); - return lentHistories; - } + @Override + public void assignLent(Long userId, Long cabinetId) { + log.debug("Called assignLent: {}, {}", userId, cabinetId); + userOptionalFetcher.getUser(userId); + Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); + lentOptionalFetcher.checkExistedSpace(cabinetId); + LocalDateTime expirationDate = lentPolicy.generateExpirationDate(LocalDateTime.now(), + cabinet, null); + LentHistory result = LentHistory.of(LocalDateTime.now(), expirationDate, userId, cabinetId); + cabinet.specifyStatusByUserCount(1); + lentRepository.save(result); + } - private LentHistory returnCabinetByUserId(Long userId) { - log.debug("Called returnCabinet: {}", userId); - userExceptionHandler.getUser(userId); - LentHistory lentHistory = lentOptionalFetcher.getActiveLentHistoryWithUserId(userId); - Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(lentHistory.getCabinetId()); - int activeLentCount = lentRepository.countCabinetActiveLent(lentHistory.getCabinetId()); - lentHistory.endLent(LocalDateTime.now()); - cabinet.specifyStatusByUserCount(activeLentCount - 1); // policy로 빠질만한 부분인듯? - if (activeLentCount - 1 == 0) { - cabinet.writeMemo(""); - cabinet.writeTitle(""); - } - return lentHistory; - } + @Override + public List getAllActiveLentHistories() { + log.debug("Called getAllActiveLentHistories"); + List lentHistories = lentOptionalFetcher.findAllActiveLentHistories(); + LocalDateTime now = LocalDateTime.now(); + return lentHistories.stream() + .map(e -> lentMapper.toActiveLentHistoryDto(e, + e.getUser(), + e.getCabinet(), + e.isExpired(now), + e.getDaysUntilExpiration(now) + )) + .collect(Collectors.toList()); + } - @Override - public void assignLent(Long userId, Long cabinetId) { - log.debug("Called assignLent: {}, {}", userId, cabinetId); - userExceptionHandler.getUser(userId); - Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); - lentOptionalFetcher.checkExistedSpace(cabinetId); - LocalDateTime expirationDate = lentPolicy.generateExpirationDate(LocalDateTime.now(), - cabinet, null); - LentHistory result = LentHistory.of(LocalDateTime.now(), expirationDate, userId, cabinetId); - cabinet.specifyStatusByUserCount(1); - lentRepository.save(result); - } + /** + * 정책에 대한 결과 상태({@link LentPolicyStatus})에 맞는 적절한 {@link ServiceException}을 throw합니다. + * + * @param status 정책에 대한 결과 상태 + * @throws ServiceException 정책에 따라 다양한 exception이 throw될 수 있습니다. + */ + private void handlePolicyStatus(LentPolicyStatus status) { + log.info("Called handlePolicyStatus status: {}", status); + switch (status) { + case FINE: + break; + case BROKEN_CABINET: + throw new ServiceException(ExceptionStatus.LENT_BROKEN); + case FULL_CABINET: + throw new ServiceException(ExceptionStatus.LENT_FULL); + case OVERDUE_CABINET: + throw new ServiceException(ExceptionStatus.LENT_EXPIRED); + case LENT_CLUB: + throw new ServiceException(ExceptionStatus.LENT_CLUB); + case IMMINENT_EXPIRATION: + throw new ServiceException(ExceptionStatus.LENT_EXPIRE_IMMINENT); + case ALREADY_LENT_USER: + throw new ServiceException(ExceptionStatus.LENT_ALREADY_EXISTED); + case ALL_BANNED_USER: + throw new ServiceException(ExceptionStatus.ALL_BANNED_USER); + case SHARE_BANNED_USER: + throw new ServiceException(ExceptionStatus.SHARE_BANNED_USER); + case BLACKHOLED_USER: + throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); + case NOT_USER: + case INTERNAL_ERROR: + default: + throw new ServiceException(ExceptionStatus.INTERNAL_SERVER_ERROR); + } + } - @Override - public List getAllActiveLentHistories() { - log.debug("Called getAllActiveLentHistories"); - List lentHistories = lentOptionalFetcher.findAllActiveLentHistories(); - LocalDateTime now = LocalDateTime.now(); - return lentHistories.stream() - .map(e -> lentMapper.toActiveLentHistoryDto(e, - e.getUser(), - e.getCabinet(), - e.isExpired(now), - e.getDaysUntilExpiration(now) - )) - .collect(Collectors.toList()); - } + private void handleBannedUserResponse(Long userId) { + BanHistory activeBanHistory = userOptionalFetcher.getActiveBanHistory(userId); + LocalDateTime unbannedAt = activeBanHistory.getUnbannedAt(); + throw new ServiceException(ExceptionStatus.ALL_BANNED_USER); + } } From 1451102a55175ac4cee5e0062820a87e9781494c Mon Sep 17 00:00:00 2001 From: space Date: Tue, 15 Aug 2023 02:57:46 +0900 Subject: [PATCH 06/21] =?UTF-8?q?[BE]=20REFACTOR:=20BAN=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EC=9D=BC=EB=95=8C,=20unban=20=EC=9D=BC=EC=9E=90=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EB=A9=94=EC=84=B8=EC=A7=80=EC=97=90=20?= =?UTF-8?q?=ED=91=9C=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/CustomExceptionStatus.java | 30 ++++++++++++ .../exception/CustomServiceException.java | 21 +++++++++ .../exception/ExceptionController.java | 8 ++++ .../cabinet/exception/ExceptionStatus.java | 5 -- .../cabinet/lent/service/LentServiceImpl.java | 47 +++++++++++++------ 5 files changed, 92 insertions(+), 19 deletions(-) create mode 100644 backend/src/main/java/org/ftclub/cabinet/exception/CustomExceptionStatus.java create mode 100644 backend/src/main/java/org/ftclub/cabinet/exception/CustomServiceException.java diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/CustomExceptionStatus.java b/backend/src/main/java/org/ftclub/cabinet/exception/CustomExceptionStatus.java new file mode 100644 index 000000000..471523561 --- /dev/null +++ b/backend/src/main/java/org/ftclub/cabinet/exception/CustomExceptionStatus.java @@ -0,0 +1,30 @@ +package org.ftclub.cabinet.exception; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +/** + * {@link CustomServiceException}을 위한 exception 클래스. 생성할 exception에 대한 정보를 담고있다. + */ +@JsonFormat(shape = JsonFormat.Shape.OBJECT) +@RequiredArgsConstructor +@Getter +public class CustomExceptionStatus { + private final int statusCode; + private final String message; + private final String error; + + public CustomExceptionStatus(HttpStatus status, String message) { + this.statusCode = status.value(); + this.message = message; + this.error = status.getReasonPhrase(); + } + + public CustomExceptionStatus(ExceptionStatus status, String message) { + this.statusCode = status.getStatusCode(); + this.message = status.getMessage() + "\n" + message; + this.error = status.getError(); + } +} diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/CustomServiceException.java b/backend/src/main/java/org/ftclub/cabinet/exception/CustomServiceException.java new file mode 100644 index 000000000..578eb53e0 --- /dev/null +++ b/backend/src/main/java/org/ftclub/cabinet/exception/CustomServiceException.java @@ -0,0 +1,21 @@ +package org.ftclub.cabinet.exception; + +/** + * Service에서 throw 하는 Exception 중 오류메세지를 커스텀 가능한 Exception + * @see CustomExceptionStatus + */ +public class CustomServiceException extends RuntimeException { + + final CustomExceptionStatus status; + + /** + * @param status exception에 대한 정보에 대한 enum + */ + public CustomServiceException(CustomExceptionStatus status) { + this.status = status; + } + + public CustomExceptionStatus getStatus() { + return status; + } +} diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java index 8c63fbc94..96ac777cb 100644 --- a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java +++ b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java @@ -25,6 +25,14 @@ public ResponseEntity serviceExceptionHandler(ServiceException e) { .body(e.status); } + @ExceptionHandler(CustomServiceException.class) + public ResponseEntity customServiceExceptionHandler(CustomServiceException e) { + log.info("[CustomServiceException] {} : {}", e.status.getError(), e.status.getMessage()); + return ResponseEntity + .status(e.status.getStatusCode()) + .body(e.status); + } + @ExceptionHandler(DomainException.class) public ResponseEntity domainExceptionHandler(DomainException e) { log.warn("[DomainException] {} : {}", e.status.getError(), e.status.getMessage()); diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java index ce59d7f79..9da8f73e3 100644 --- a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java +++ b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java @@ -41,7 +41,6 @@ public enum ExceptionStatus { CLUB_HAS_LENT_CABINET(HttpStatus.NOT_ACCEPTABLE, "대여 중인 사물함을 반납 후 삭제할 수 있습니다."), ; - final private int statusCode; final private String message; final private String error; @@ -51,8 +50,4 @@ public enum ExceptionStatus { this.message = message; this.error = status.getReasonPhrase(); } - - public static ExceptionStatus createExceptionStatus(HttpStatus status, String message) { - return new ExceptionStatus(status, message); - } } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java index 5b02ab0ba..fccf8f000 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java @@ -1,6 +1,9 @@ package org.ftclub.cabinet.lent.service; +import static org.ftclub.cabinet.exception.ExceptionStatus.ALL_BANNED_USER; + import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.stream.Collectors; import javax.transaction.Transactional; @@ -9,6 +12,8 @@ import org.ftclub.cabinet.cabinet.domain.Cabinet; import org.ftclub.cabinet.cabinet.repository.CabinetOptionalFetcher; import org.ftclub.cabinet.dto.ActiveLentHistoryDto; +import org.ftclub.cabinet.exception.CustomExceptionStatus; +import org.ftclub.cabinet.exception.CustomServiceException; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; import org.ftclub.cabinet.lent.domain.LentHistory; @@ -49,21 +54,24 @@ public void startLentCabinet(Long userId, Long cabinetId) { List userActiveBanList = banHistoryRepository.findUserActiveBanList(userId, now); // 대여 가능한 유저인지 확인 - //BanHistory activeBanHistory = userOptionalFetcher.getActiveBanHistory(userId); - handlePolicyStatus( - lentPolicy.verifyUserForLent(user, cabinet, userActiveLentCount, - userActiveBanList)); + LentPolicyStatus userPolicyStatus = lentPolicy.verifyUserForLent(user, cabinet, + userActiveLentCount, userActiveBanList); + handlePolicyStatus(userPolicyStatus, userActiveBanList.get(0)); // UserPolicyStatus 와 LentPolicyStatus 가 분리해야 하지않는가? 23/8/15 List cabinetActiveLentHistories = lentRepository.findAllActiveLentByCabinetId( cabinetId); + // 대여 가능한 캐비넷인지 확인 - handlePolicyStatus( - lentPolicy.verifyCabinetForLent(cabinet, cabinetActiveLentHistories, - now)); + LentPolicyStatus cabinetPolicyStatus = lentPolicy.verifyCabinetForLent(cabinet, + cabinetActiveLentHistories, + now); + handlePolicyStatus(cabinetPolicyStatus, userActiveBanList.get(0)); // UserPolicyStatus 와 LentPolicyStatus 가 분리해야 하지않는가? 23/8/15 + // 캐비넷 상태 변경 cabinet.specifyStatusByUserCount(cabinetActiveLentHistories.size() + 1); LocalDateTime expiredAt = lentPolicy.generateExpirationDate(now, cabinet, cabinetActiveLentHistories); LentHistory lentHistory = LentHistory.of(now, expiredAt, userId, cabinetId); + // 연체 시간 적용 lentPolicy.applyExpirationDate(lentHistory, cabinetActiveLentHistories, expiredAt); lentRepository.save(lentHistory); @@ -170,7 +178,7 @@ public List getAllActiveLentHistories() { * @param status 정책에 대한 결과 상태 * @throws ServiceException 정책에 따라 다양한 exception이 throw될 수 있습니다. */ - private void handlePolicyStatus(LentPolicyStatus status) { + private void handlePolicyStatus(LentPolicyStatus status, BanHistory banHistory) { log.info("Called handlePolicyStatus status: {}", status); switch (status) { case FINE: @@ -188,9 +196,8 @@ private void handlePolicyStatus(LentPolicyStatus status) { case ALREADY_LENT_USER: throw new ServiceException(ExceptionStatus.LENT_ALREADY_EXISTED); case ALL_BANNED_USER: - throw new ServiceException(ExceptionStatus.ALL_BANNED_USER); case SHARE_BANNED_USER: - throw new ServiceException(ExceptionStatus.SHARE_BANNED_USER); + handleBannedUserResponse(status, banHistory); case BLACKHOLED_USER: throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); case NOT_USER: @@ -200,9 +207,21 @@ private void handlePolicyStatus(LentPolicyStatus status) { } } - private void handleBannedUserResponse(Long userId) { - BanHistory activeBanHistory = userOptionalFetcher.getActiveBanHistory(userId); - LocalDateTime unbannedAt = activeBanHistory.getUnbannedAt(); - throw new ServiceException(ExceptionStatus.ALL_BANNED_USER); + private void handleBannedUserResponse(LentPolicyStatus status, BanHistory banHistory) { + log.info("Called handleBannedUserResponse: {}", status); + + + LocalDateTime unbannedAt = banHistory.getUnbannedAt(); + String unbannedTimeString = unbannedAt.format( + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + + if (status.equals(LentPolicyStatus.ALL_BANNED_USER)) { + throw new CustomServiceException( + new CustomExceptionStatus(ExceptionStatus.ALL_BANNED_USER, unbannedTimeString)); + } else if (status.equals(LentPolicyStatus.SHARE_BANNED_USER)) { + throw new CustomServiceException( + new CustomExceptionStatus(ExceptionStatus.SHARE_BANNED_USER, + unbannedTimeString)); + } } } From 465f43756a5c9ff24a356c1f33bc21b44cce9cc4 Mon Sep 17 00:00:00 2001 From: space Date: Tue, 15 Aug 2023 02:57:58 +0900 Subject: [PATCH 07/21] =?UTF-8?q?[BE]=20FIX:=20Logger=20=EC=98=A4=ED=83=80?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/log4j2-local.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/log4j2-local.yml b/backend/src/main/resources/log4j2-local.yml index bfe1db4f9..7f1087801 100644 --- a/backend/src/main/resources/log4j2-local.yml +++ b/backend/src/main/resources/log4j2-local.yml @@ -24,7 +24,7 @@ Configuration: - ref: console - name: org.ftclub.cabinet - level: ㅑ루ㅐ + level: info additivity: false AppenderRef: - ref: console From 99f4e43973fcd69a72bd4e6ac335d8919b7a3d8e Mon Sep 17 00:00:00 2001 From: space Date: Tue, 15 Aug 2023 03:12:14 +0900 Subject: [PATCH 08/21] =?UTF-8?q?[BE]=20FIX:=20BanHistory=20=EB=A7=A4?= =?UTF-8?q?=EA=B0=9C=EB=B3=80=EC=88=98=20List=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/ftclub/cabinet/lent/service/LentServiceImpl.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java index fccf8f000..09fd839b4 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java @@ -5,6 +5,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import javax.transaction.Transactional; import lombok.RequiredArgsConstructor; @@ -56,7 +57,7 @@ public void startLentCabinet(Long userId, Long cabinetId) { // 대여 가능한 유저인지 확인 LentPolicyStatus userPolicyStatus = lentPolicy.verifyUserForLent(user, cabinet, userActiveLentCount, userActiveBanList); - handlePolicyStatus(userPolicyStatus, userActiveBanList.get(0)); // UserPolicyStatus 와 LentPolicyStatus 가 분리해야 하지않는가? 23/8/15 + handlePolicyStatus(userPolicyStatus, userActiveBanList); // UserPolicyStatus 와 LentPolicyStatus 가 분리해야 하지않는가? 23/8/15 List cabinetActiveLentHistories = lentRepository.findAllActiveLentByCabinetId( cabinetId); @@ -64,7 +65,7 @@ public void startLentCabinet(Long userId, Long cabinetId) { LentPolicyStatus cabinetPolicyStatus = lentPolicy.verifyCabinetForLent(cabinet, cabinetActiveLentHistories, now); - handlePolicyStatus(cabinetPolicyStatus, userActiveBanList.get(0)); // UserPolicyStatus 와 LentPolicyStatus 가 분리해야 하지않는가? 23/8/15 + handlePolicyStatus(cabinetPolicyStatus, userActiveBanList); // UserPolicyStatus 와 LentPolicyStatus 가 분리해야 하지않는가? 23/8/15 // 캐비넷 상태 변경 cabinet.specifyStatusByUserCount(cabinetActiveLentHistories.size() + 1); @@ -178,7 +179,7 @@ public List getAllActiveLentHistories() { * @param status 정책에 대한 결과 상태 * @throws ServiceException 정책에 따라 다양한 exception이 throw될 수 있습니다. */ - private void handlePolicyStatus(LentPolicyStatus status, BanHistory banHistory) { + private void handlePolicyStatus(LentPolicyStatus status, List banHistory) { log.info("Called handlePolicyStatus status: {}", status); switch (status) { case FINE: @@ -197,7 +198,7 @@ private void handlePolicyStatus(LentPolicyStatus status, BanHistory banHistory) throw new ServiceException(ExceptionStatus.LENT_ALREADY_EXISTED); case ALL_BANNED_USER: case SHARE_BANNED_USER: - handleBannedUserResponse(status, banHistory); + handleBannedUserResponse(status, banHistory.get(0)); case BLACKHOLED_USER: throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); case NOT_USER: From 9810343c32bc41e478fc2cbfdf3a90f77357abe6 Mon Sep 17 00:00:00 2001 From: space Date: Tue, 15 Aug 2023 04:37:55 +0900 Subject: [PATCH 09/21] =?UTF-8?q?[BE]=20REFACTOR=20&=20FIX:=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=ED=99=80=20=EC=9C=A0=EC=A0=80=20=EB=8C=80=EC=97=AC?= =?UTF-8?q?=EC=8B=9C=20=EC=B2=B4=ED=81=AC=20=ED=9B=84=20=EB=B8=94=EB=9E=99?= =?UTF-8?q?=ED=99=80=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cabinet/dto/UserBlackholeInfoDto.java | 4 ++ .../cabinet/lent/domain/LentPolicyImpl.java | 14 +++---- .../blackhole/manager/BlackholeRefresher.java | 41 ++++++++++++++++--- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/dto/UserBlackholeInfoDto.java b/backend/src/main/java/org/ftclub/cabinet/dto/UserBlackholeInfoDto.java index 2ac7e21f3..7e0772a5a 100644 --- a/backend/src/main/java/org/ftclub/cabinet/dto/UserBlackholeInfoDto.java +++ b/backend/src/main/java/org/ftclub/cabinet/dto/UserBlackholeInfoDto.java @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; +import org.ftclub.cabinet.user.domain.User; /** * 유저의 식별자, 이름, 이메일, 블랙홀 날짜를 반환하는 DTO입니다. @@ -22,4 +23,7 @@ public static UserBlackholeInfoDto of(Long userId, String name, String email, LocalDateTime blackHoledAt) { return new UserBlackholeInfoDto(userId, name, email, blackHoledAt); } + public static UserBlackholeInfoDto of(User user) { + return new UserBlackholeInfoDto(user.getUserId(), user.getName(), user.getEmail(), user.getBlackholedAt()); + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java index 84fe16571..bd5150a2e 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java @@ -1,5 +1,6 @@ package org.ftclub.cabinet.lent.domain; +import com.fasterxml.jackson.databind.JsonNode; import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; @@ -8,12 +9,14 @@ import org.ftclub.cabinet.cabinet.domain.CabinetStatus; import org.ftclub.cabinet.cabinet.domain.LentType; import org.ftclub.cabinet.config.CabinetProperties; +import org.ftclub.cabinet.dto.UserBlackholeInfoDto; import org.ftclub.cabinet.exception.DomainException; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.user.domain.BanHistory; import org.ftclub.cabinet.user.domain.User; import org.ftclub.cabinet.user.domain.UserRole; import org.ftclub.cabinet.utils.DateUtil; +import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManager; import org.ftclub.cabinet.utils.blackhole.manager.BlackholeRefresher; import org.springframework.stereotype.Component; @@ -106,16 +109,11 @@ public LentPolicyStatus verifyUserForLent(User user, Cabinet cabinet, int userAc return LentPolicyStatus.ALREADY_LENT_USER; } // TODO: 현재 구조에서는 DB 정합성 문제를 일으키는 코드입니다. -// 블랙홀에 빠진 유저 대여 로직을 막는다고 하면, BlackholeManager.handleBlackhole()을 통해 -// 실제 DB에 반영되기 전에 블랙홀에 빠진 유저를 걸러낼 수 있습니다. -// 하지만, 현재는 BlackholeManager <-> LentService 간의 순환 참조가 발생하는데, -// BlackholeManager는 스케줄러에 의해 빈에 등록되는 컴포넌트이므로 -// 현재 구조상으로는 @Lazy 어노테이션을 통해 순환 참조 문제를 해결할 수 없습니다. -// 추후 다른 방식으로 구조적인 리팩토링이 필요한 부분입니다..! +// 유저의 블랙홀 업데이트와 블랙홀 체크 분리필요- 리펙토링 필요 2023.08.15 if (user.getBlackholedAt() != null && user.getBlackholedAt() .isBefore(LocalDateTime.now())) { -// blackholeRefresher.getBlackholeInfo(user.get) - return LentPolicyStatus.BLACKHOLED_USER; + if(blackholeRefresher.isBlackholedUpdated(UserBlackholeInfoDto.of(user))) + return LentPolicyStatus.BLACKHOLED_USER; } // 유저가 페널티 2 종류 이상 받을 수 있나? <- 실제로 그럴리 없지만 lentPolicy 객체는 그런 사실을 모르고, 유연하게 구현? if (userActiveBanList == null || userActiveBanList.size() == 0) { diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java index e88f09c45..22a2930aa 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -1,6 +1,7 @@ package org.ftclub.cabinet.utils.blackhole.manager; import com.fasterxml.jackson.databind.JsonNode; +import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.auth.service.FtApiManager; @@ -8,6 +9,7 @@ import org.ftclub.cabinet.exception.ServiceException; import org.ftclub.cabinet.user.service.UserService; import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; @Component @RequiredArgsConstructor @@ -24,16 +26,43 @@ public class BlackholeRefresher { * @return JsonNode * @throws ServiceException */ - public JsonNode getBlackholeInfo(UserBlackholeInfoDto userBlackholeInfoDto) - throws ServiceException { + JsonNode getBlackholeInfo(UserBlackholeInfoDto userBlackholeInfoDto) + throws ServiceException, HttpClientErrorException { log.info("called refreshBlackhole{}", userBlackholeInfoDto); return ftApiManager.getFtUsersInfoByName( userBlackholeInfoDto.getName()); } - public JsonNode getBlackholeInfo2(UserBlackholeInfoDto userBlackholeInfoDto) - throws ServiceException { - log.info("called refreshBlackhole{}", userBlackholeInfoDto); - getBlackholeInfo(userBlackholeInfoDto); + /** + * 블랙홀 날짜를 LocalDateTime으로 파싱한다. + * + * @param jsonUserInfo JsonNode에 담긴 유저 정보 + * @return LocalDateTime으로 파싱된 블랙홀 날짜 + */ + private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { + log.info("parseBlackholedAt {}", jsonUserInfo); + JsonNode JsonBlackholedAt = jsonUserInfo.get("cursus_users").get(1).get("blackholed_at"); + if (JsonBlackholedAt == null || JsonBlackholedAt.asText().equals("null")) { + return null; + } + return LocalDateTime.parse(JsonBlackholedAt.asText().substring(0, 19)); + } + + /** + * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. + * + * @return 블랙홀에 빠졌는지 여부 + */ + public Boolean isBlackholedUpdated(UserBlackholeInfoDto userBlackholeInfoDto) { + log.info("isBlackholed {}", userBlackholeInfoDto); + LocalDateTime now = LocalDateTime.now(); + JsonNode blackholeInfo = getBlackholeInfo(userBlackholeInfoDto); + LocalDateTime blackholedAtDate = parseBlackholedAt(blackholeInfo); + if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { + userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), blackholedAtDate); + return false; + } else { + return true; + } } } From be4b5d9a64a2ec044ee4c77b16129dd573fb3b4d Mon Sep 17 00:00:00 2001 From: space Date: Tue, 15 Aug 2023 05:01:40 +0900 Subject: [PATCH 10/21] =?UTF-8?q?[BE]=20REFACTOR:=20BlackholeManager=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=97=90=20=EB=94=B0=EB=A5=B8=20TEST=20Mock?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackhole/manager/BlackholeManager.java | 2 +- .../manager/BlackholeManagerUnitTest.java | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index 593f61d0f..884f88210 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -33,7 +33,7 @@ public class BlackholeManager { */ private Boolean isValidCadet(JsonNode jsonUserInfo) { log.info("isValidCadet {}", jsonUserInfo); - return jsonUserInfo.get("cursus_users").size() > 3; + return jsonUserInfo.get("cursus_users").size() >= 2; } /** diff --git a/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java b/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java index 1fbebd57c..04160bae5 100644 --- a/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java +++ b/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java @@ -14,6 +14,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.time.LocalDateTime; +import java.util.List; import org.ftclub.cabinet.auth.service.FtApiManager; import org.ftclub.cabinet.config.FtApiProperties; import org.ftclub.cabinet.dto.UserBlackholeInfoDto; @@ -24,6 +25,7 @@ import org.ftclub.cabinet.utils.ExceptionUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -39,6 +41,8 @@ public class BlackholeManagerUnitTest { @InjectMocks private BlackholeManager blackholeManager; @Mock + private BlackholeRefresher blackholeRefresher; + @Mock private FtApiManager ftApiManager = mock(FtApiManager.class); @Mock private LentService lentService = mock(LentService.class); @@ -84,7 +88,7 @@ void setUp() { LocalDateTime.now().minusDays(1)); JsonNode JsonafterBlackholedAt = objectMapper.readTree(StringAfterBlackholedAt); - given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -116,9 +120,10 @@ void setUp() { beforeBlackholedAt ); - given(ftApiManager.getFtUsersInfoByName(name)).willThrow(new HttpClientErrorException( - HttpStatus.NOT_FOUND - )); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willThrow( + new HttpClientErrorException( + HttpStatus.NOT_FOUND + )); blackholeManager.handleBlackhole(userBlackholeInfoDto); @@ -148,7 +153,8 @@ void setUp() { JsonNode mockFieldZero = mock(JsonNode.class); JsonNode mockFieldOne = mock(JsonNode.class); - given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); given(mockCursusUsers.size()).willReturn(1); @@ -189,7 +195,8 @@ void setUp() { LocalDateTime.now().plusDays(42)); JsonNode JsonafterBlackholedAt = objectMapper.readTree(StringAfterBlackholedAt); - given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -229,7 +236,8 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -268,7 +276,8 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -307,7 +316,8 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); From 8a0032b7bb25ab228a807b28d8c28b7f29b1beaa Mon Sep 17 00:00:00 2001 From: space Date: Wed, 16 Aug 2023 01:57:20 +0900 Subject: [PATCH 11/21] [BE] REFACTOR: DELAY_TIME static --- .../org/ftclub/cabinet/utils/scheduler/SystemScheduler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java index f370fff9b..5610a44fa 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java @@ -29,7 +29,7 @@ public class SystemScheduler { private final UserService userService; private final BlackholeManager blackholeManager; - private final long DELAY_TIME = 2000; + private static final long DELAY_TIME = 2000; /** * 매일 자정마다 대여 기록을 확인하여, 연체 메일 발송 및 휴학생 처리를 트리거하는 메소드 From 8fde2a141bbb05018626a4a8de24304ab404e4b4 Mon Sep 17 00:00:00 2001 From: space Date: Wed, 16 Aug 2023 02:03:18 +0900 Subject: [PATCH 12/21] =?UTF-8?q?[BE]=20REFACTOR:=20isBlackholed=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=9E=88=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java | 4 +--- .../cabinet/utils/blackhole/manager/BlackholeRefresher.java | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java index bd5150a2e..ca340fbcc 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java @@ -1,6 +1,5 @@ package org.ftclub.cabinet.lent.domain; -import com.fasterxml.jackson.databind.JsonNode; import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; @@ -16,7 +15,6 @@ import org.ftclub.cabinet.user.domain.User; import org.ftclub.cabinet.user.domain.UserRole; import org.ftclub.cabinet.utils.DateUtil; -import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManager; import org.ftclub.cabinet.utils.blackhole.manager.BlackholeRefresher; import org.springframework.stereotype.Component; @@ -112,7 +110,7 @@ public LentPolicyStatus verifyUserForLent(User user, Cabinet cabinet, int userAc // 유저의 블랙홀 업데이트와 블랙홀 체크 분리필요- 리펙토링 필요 2023.08.15 if (user.getBlackholedAt() != null && user.getBlackholedAt() .isBefore(LocalDateTime.now())) { - if(blackholeRefresher.isBlackholedUpdated(UserBlackholeInfoDto.of(user))) + if(blackholeRefresher.isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto.of(user))) return LentPolicyStatus.BLACKHOLED_USER; } // 유저가 페널티 2 종류 이상 받을 수 있나? <- 실제로 그럴리 없지만 lentPolicy 객체는 그런 사실을 모르고, 유연하게 구현? diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java index 22a2930aa..a2a29dd45 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -53,8 +53,8 @@ private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { * * @return 블랙홀에 빠졌는지 여부 */ - public Boolean isBlackholedUpdated(UserBlackholeInfoDto userBlackholeInfoDto) { - log.info("isBlackholed {}", userBlackholeInfoDto); + public Boolean isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto userBlackholeInfoDto) { + log.info("isBlackholedAndUpdateBlackhole {}", userBlackholeInfoDto); LocalDateTime now = LocalDateTime.now(); JsonNode blackholeInfo = getBlackholeInfo(userBlackholeInfoDto); LocalDateTime blackholedAtDate = parseBlackholedAt(blackholeInfo); From 52c0c55541562a062b443d261cb62b7fafcfae8e Mon Sep 17 00:00:00 2001 From: space Date: Wed, 16 Aug 2023 02:11:37 +0900 Subject: [PATCH 13/21] =?UTF-8?q?[BE]=20REFACTOR:=20isBlackholed=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=9E=88=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cabinet/utils/blackhole/manager/BlackholeRefresher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java index a2a29dd45..e71f3b903 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -58,8 +58,8 @@ public Boolean isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto userBlackhole LocalDateTime now = LocalDateTime.now(); JsonNode blackholeInfo = getBlackholeInfo(userBlackholeInfoDto); LocalDateTime blackholedAtDate = parseBlackholedAt(blackholeInfo); + userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), blackholedAtDate); if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { - userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), blackholedAtDate); return false; } else { return true; From ba0a3acbd6e138c5a3a73944d80685ca25c03a35 Mon Sep 17 00:00:00 2001 From: space Date: Thu, 17 Aug 2023 00:28:55 +0900 Subject: [PATCH 14/21] =?UTF-8?q?[BE]=20REFACTOR:=20BlackholeUserInfo=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD,=20=EB=B8=94?= =?UTF-8?q?=EB=9E=99=ED=99=80=20=EB=82=A0=EC=A7=9C=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EC=A0=84=EB=8B=AC=EC=9D=B8=EC=9E=90=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blackhole/manager/BlackholeManager.java | 22 +++++++++---------- .../blackhole/manager/BlackholeRefresher.java | 10 ++++----- .../manager/BlackholeManagerUnitTest.java | 14 ++++++------ 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index 884f88210..55f46ebd3 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -120,32 +120,32 @@ private void handleHttpClientError(UserBlackholeInfoDto userBlackholeInfoDto, Lo } } - public void handleBlackhole(UserBlackholeInfoDto userBlackholeInfoDto) { - log.info("called handleBlackhole {}", userBlackholeInfoDto); + public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { + log.info("called handleBlackhole {}", userInfoDto); LocalDateTime now = LocalDateTime.now(); try { - JsonNode jsonUserInfo = blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto); - if (!isValidCadet(jsonUserInfo)) { - handleNotCadet(userBlackholeInfoDto, now); + JsonNode jsonRefreshedUserInfo = blackholeRefresher.getBlackholeInfo(userInfoDto.getName()); + if (!isValidCadet(jsonRefreshedUserInfo)) { + handleNotCadet(userInfoDto, now); return; } - LocalDateTime newBlackholedAt = parseBlackholedAt(jsonUserInfo); + LocalDateTime newBlackholedAt = parseBlackholedAt(jsonRefreshedUserInfo); log.info("갱신된 블랙홀 날짜 {}", newBlackholedAt); log.info("오늘 날짜 {}", now); if (isBlackholed(newBlackholedAt, now)) { - handleBlackholed(userBlackholeInfoDto, now); + handleBlackholed(userInfoDto, now); } else { - handleNotBlackholed(userBlackholeInfoDto, newBlackholedAt); + handleNotBlackholed(userInfoDto, newBlackholedAt); } } catch (HttpClientErrorException e) { - handleHttpClientError(userBlackholeInfoDto, now, e); + handleHttpClientError(userInfoDto, now, e); } catch (ServiceException e) { if (e.getStatus().equals(ExceptionStatus.NO_LENT_CABINET)) { - userService.deleteUser(userBlackholeInfoDto.getUserId(), now); + userService.deleteUser(userInfoDto.getUserId(), now); } } catch (Exception e) { - log.error("handleBlackhole Exception: {}", userBlackholeInfoDto, e); + log.error("handleBlackhole Exception: {}", userInfoDto, e); } } } diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java index e71f3b903..789cdd6a0 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -26,11 +26,11 @@ public class BlackholeRefresher { * @return JsonNode * @throws ServiceException */ - JsonNode getBlackholeInfo(UserBlackholeInfoDto userBlackholeInfoDto) + public JsonNode getBlackholeInfo(String userName) throws ServiceException, HttpClientErrorException { - log.info("called refreshBlackhole{}", userBlackholeInfoDto); + log.info("called refreshBlackhole{}", userName); return ftApiManager.getFtUsersInfoByName( - userBlackholeInfoDto.getName()); + userName); } /** @@ -56,10 +56,10 @@ private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { public Boolean isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto userBlackholeInfoDto) { log.info("isBlackholedAndUpdateBlackhole {}", userBlackholeInfoDto); LocalDateTime now = LocalDateTime.now(); - JsonNode blackholeInfo = getBlackholeInfo(userBlackholeInfoDto); + JsonNode blackholeInfo = getBlackholeInfo(userBlackholeInfoDto.getName()); LocalDateTime blackholedAtDate = parseBlackholedAt(blackholeInfo); - userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), blackholedAtDate); if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { + userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), blackholedAtDate); return false; } else { return true; diff --git a/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java b/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java index 04160bae5..dd5354837 100644 --- a/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java +++ b/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java @@ -88,7 +88,7 @@ void setUp() { LocalDateTime.now().minusDays(1)); JsonNode JsonafterBlackholedAt = objectMapper.readTree(StringAfterBlackholedAt); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn(jsonUserInfo); + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -120,7 +120,7 @@ void setUp() { beforeBlackholedAt ); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willThrow( + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willThrow( new HttpClientErrorException( HttpStatus.NOT_FOUND )); @@ -153,7 +153,7 @@ void setUp() { JsonNode mockFieldZero = mock(JsonNode.class); JsonNode mockFieldOne = mock(JsonNode.class); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); @@ -195,7 +195,7 @@ void setUp() { LocalDateTime.now().plusDays(42)); JsonNode JsonafterBlackholedAt = objectMapper.readTree(StringAfterBlackholedAt); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); @@ -236,7 +236,7 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); @@ -276,7 +276,7 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); @@ -316,7 +316,7 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto)).willReturn( + given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); From dc27bdc910760005a747418e2eed3564db2fac1c Mon Sep 17 00:00:00 2001 From: space Date: Thu, 17 Aug 2023 01:07:10 +0900 Subject: [PATCH 15/21] =?UTF-8?q?[BE]=20REFACTOR:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EB=B0=8F=20Import=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cabinet/utils/blackhole/manager/BlackholeManager.java | 2 -- .../cabinet/utils/blackhole/manager/BlackholeRefresher.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index 55f46ebd3..678a573b5 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -4,7 +4,6 @@ import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; -import org.ftclub.cabinet.auth.service.FtApiManager; import org.ftclub.cabinet.dto.UserBlackholeInfoDto; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; @@ -19,7 +18,6 @@ @Log4j2 public class BlackholeManager { - private final FtApiManager ftAPIManager; private final LentService lentService; private final UserService userService; private final BlackholeRefresher blackholeRefresher; diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java index 789cdd6a0..61fcba4ad 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -22,7 +22,7 @@ public class BlackholeRefresher { /** * 유저의 블랙홀 정보를 찾아온다. * - * @param userBlackholeInfoDto + * @param userName 유저 이름 * @return JsonNode * @throws ServiceException */ From d5a8fa9caaf334e9d739ef5e6ce1eca909853a5e Mon Sep 17 00:00:00 2001 From: space Date: Thu, 17 Aug 2023 03:17:25 +0900 Subject: [PATCH 16/21] =?UTF-8?q?[BE]=20REFACTOR:=20Event=20Lister=20?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=9C=20=EC=88=9C=ED=99=98=20=EC=B0=B8?= =?UTF-8?q?=EC=A1=B0=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BlackholedUserLentEventListener.java | 26 +++ .../cabinet/exception/ExceptionStatus.java | 1 + .../cabinet/lent/domain/LentPolicyImpl.java | 17 +- .../blackhole/manager/BlackholeManager.java | 1 + .../blackhole/manager/BlackholeManagerV2.java | 214 ++++++++++++++++++ .../blackhole/manager/BlackholeRefresher.java | 46 +++- .../utils/scheduler/SystemScheduler.java | 7 +- 7 files changed, 299 insertions(+), 13 deletions(-) create mode 100644 backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java create mode 100644 backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java diff --git a/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java b/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java new file mode 100644 index 000000000..3a920ab07 --- /dev/null +++ b/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java @@ -0,0 +1,26 @@ +package org.ftclub.cabinet.event; + +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.ftclub.cabinet.dto.UserBlackholeInfoDto; +import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManagerV2; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Component; + +@Log4j2 +@Component +@EnableAsync +@RequiredArgsConstructor +public class BlackholedUserLentEventListener { + + private final BlackholeManagerV2 blackholeManager; + + @Async + @EventListener + public void handleBlackholedUserLentAttemptingEvent(UserBlackholeInfoDto userBlackholeInfoDto) { + log.info("Called handleBlackholedUserLentAttemptingEvent"); + blackholeManager.blackholeRefresher(userBlackholeInfoDto); + } +} diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java index 9da8f73e3..ed8aea3e1 100644 --- a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java +++ b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java @@ -34,6 +34,7 @@ public enum ExceptionStatus { SHARE_BANNED_USER(HttpStatus.BAD_REQUEST, "SHARE 밴 상태의 유저입니다."), NOT_FOUND_BAN_HISTORY(HttpStatus.NOT_FOUND, "현재 정지 상태인 유저가 아닙니다."), BLACKHOLED_USER(HttpStatus.BAD_REQUEST, "블랙홀 상태의 유저입니다."), + BLACKHOLE_REFRESHING(HttpStatus.BAD_REQUEST, "블랙홀 갱신 중 입니다.\n다시 시도해주세요."), UNAUTHORIZED_ADMIN(HttpStatus.UNAUTHORIZED, "관리자 로그인 정보가 유효하지 않습니다\n다시 로그인해주세요"), UNAUTHORIZED_USER(HttpStatus.UNAUTHORIZED, "사용자 로그인 정보가 유효하지 않습니다\n다시 로그인해주세요"), EXTERNAL_API_EXCEPTION(HttpStatus.BAD_REQUEST, "외부 API와 통신 중 에러가 발생했습니다"), diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java index ca340fbcc..a4a60c75f 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java @@ -16,6 +16,7 @@ import org.ftclub.cabinet.user.domain.UserRole; import org.ftclub.cabinet.utils.DateUtil; import org.ftclub.cabinet.utils.blackhole.manager.BlackholeRefresher; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; @Component @@ -24,7 +25,8 @@ public class LentPolicyImpl implements LentPolicy { private final CabinetProperties cabinetProperties; - private final BlackholeRefresher blackholeRefresher; + private final ApplicationEventPublisher publisher; + private LocalDateTime generateSharedCabinetExpirationDate(LocalDateTime now, CabinetStatus cabinetStatus, LentHistory activeLentHistory) { @@ -106,13 +108,18 @@ public LentPolicyStatus verifyUserForLent(User user, Cabinet cabinet, int userAc if (userActiveLentCount >= 1) { return LentPolicyStatus.ALREADY_LENT_USER; } -// TODO: 현재 구조에서는 DB 정합성 문제를 일으키는 코드입니다. -// 유저의 블랙홀 업데이트와 블랙홀 체크 분리필요- 리펙토링 필요 2023.08.15 if (user.getBlackholedAt() != null && user.getBlackholedAt() .isBefore(LocalDateTime.now())) { - if(blackholeRefresher.isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto.of(user))) - return LentPolicyStatus.BLACKHOLED_USER; + publisher.publishEvent(UserBlackholeInfoDto.of(user)); + throw new DomainException(ExceptionStatus.BLACKHOLE_REFRESHING); + +// if(user.getBlackholedAt() != null && user.getBlackholedAt().isBefore(LocalDateTime.now())) +// return LentPolicyStatus.BLACKHOLED_USER; + +// if(blackholeRefresher.isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto.of(user))) +// return LentPolicyStatus.BLACKHOLED_USER; } + // 유저가 페널티 2 종류 이상 받을 수 있나? <- 실제로 그럴리 없지만 lentPolicy 객체는 그런 사실을 모르고, 유연하게 구현? if (userActiveBanList == null || userActiveBanList.size() == 0) { return LentPolicyStatus.FINE; diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index 678a573b5..27edbd914 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -16,6 +16,7 @@ @Component @RequiredArgsConstructor @Log4j2 +@Deprecated public class BlackholeManager { private final LentService lentService; diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java new file mode 100644 index 000000000..e196ac8d6 --- /dev/null +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java @@ -0,0 +1,214 @@ +package org.ftclub.cabinet.utils.blackhole.manager; + +import com.fasterxml.jackson.databind.JsonNode; +import java.time.LocalDateTime; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.ftclub.cabinet.auth.service.FtApiManager; +import org.ftclub.cabinet.dto.UserBlackholeInfoDto; +import org.ftclub.cabinet.exception.DomainException; +import org.ftclub.cabinet.exception.ExceptionStatus; +import org.ftclub.cabinet.exception.ServiceException; +import org.ftclub.cabinet.lent.service.LentService; +import org.ftclub.cabinet.user.service.UserService; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; + +@Component +@RequiredArgsConstructor +@Log4j2 +public class BlackholeManagerV2 { + + private final FtApiManager ftApiManager; + private final LentService lentService; + private final UserService userService; + + /** + * JsonNode에 담긴 cursus_users를 확인하여 해당 유저가 카뎃인지 확인한다. cursus_users에 담긴 정보가 2개 이상이면 카뎃이다. + * cursus_users에 담긴 정보가 2개 미만이면 카뎃이 아니다. (피시너 등) + * + * @param jsonUserInfo JsonNode에 담긴 유저 정보 + * @return 카뎃 여부 + */ + private boolean isValidCadet(JsonNode jsonUserInfo) { + log.info("isValidCadet {}", jsonUserInfo); + return jsonUserInfo.get("cursus_users").size() >= 2; + } + + /** + * 블랙홀 날짜를 LocalDateTime으로 파싱한다. + * + * @param jsonUserInfo JsonNode에 담긴 유저 정보 + * @return LocalDateTime으로 파싱된 블랙홀 날짜 + */ + private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { + log.info("parseBlackholedAt {}", jsonUserInfo); + JsonNode JsonBlackholedAt = jsonUserInfo.get("cursus_users").get(1).get("blackholed_at"); + if (JsonBlackholedAt == null || JsonBlackholedAt.asText().equals("null")) { + return null; + } + return LocalDateTime.parse(JsonBlackholedAt.asText().substring(0, 19)); + } + + /** + * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. + * + * @param blackholedAtDate 블랙홀 날짜 + * @return 블랙홀에 빠졌는지 여부 + */ + private boolean isBlackholed(LocalDateTime blackholedAtDate) { + log.info("isBlackholed {} {}", blackholedAtDate); + LocalDateTime now = LocalDateTime.now(); + if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { + return false; + } else { + return true; + } + } + + /** + * 카뎃이 아닌 유저를 강제 반납 및 삭제 처리한다. + * + * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} + * @param now 현재 시간 + */ + private void handleNotCadet(UserBlackholeInfoDto userBlackholeInfoDto, LocalDateTime now) { + log.warn("{}는 카뎃이 아닙니다.", userBlackholeInfoDto); + lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); + userService.deleteUser(userBlackholeInfoDto.getUserId(), now); + } + + /** + * 블랙홀에 빠진 유저를 강제 반납 및 삭제 처리한다. + * + * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} + */ + private void handleBlackholed(UserBlackholeInfoDto userBlackholeInfoDto) { + log.info("{}는 블랙홀에 빠졌습니다.", userBlackholeInfoDto); + LocalDateTime now = LocalDateTime.now(); + lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); + userService.deleteUser(userBlackholeInfoDto.getUserId(), now); + } + + /** + * 블랙홀에 빠지지 않은 유저의 블랙홀 날짜를 갱신한다. + * + * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} + * @param newBlackholedAt 갱신된 블랙홀 날짜 + */ + private void handleNotBlackholed(UserBlackholeInfoDto userBlackholeInfoDto, + LocalDateTime newBlackholedAt) { + log.info("{}는 블랙홀에 빠지지 않았습니다.", userBlackholeInfoDto); + userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), newBlackholedAt); + } + + /** + * 유저 정보 조회 결과 해당 유저를 42에서 찾을 수 없다면, 강제 반납 및 삭제 처리한다. + * + * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} + * @param now 현재 시간 + * @param e HttpClientErrorException + */ + private void handleHttpClientError(UserBlackholeInfoDto userBlackholeInfoDto, LocalDateTime now, + HttpClientErrorException e) { + log.error("handleBlackhole HttpClientErrorException {}", e.getStatusCode()); + if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) { + log.warn("{}는 42에서 찾을 수 없습니다.", userBlackholeInfoDto); + lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); + userService.deleteUser(userBlackholeInfoDto.getUserId(), now); + } + } + + /** + * 유저의 블랙홀 정보를 API 를 통해 요청하여 찾아온다. + * + * @param userName 유저 이름 + * @return JsonNode 유저의 블랙홀 정보 + * @throws ServiceException + */ + private JsonNode getBlackholeInfo(String userName) + throws ServiceException, HttpClientErrorException { + log.info("called refreshBlackhole{}", userName); + return ftApiManager.getFtUsersInfoByName( + userName); + } + + + /** + * 유저의 블랙홀 날짜를 갱신하여 LocalDateTime으로 반환한다. + * + * @param userName 유저 이름 + * @return 갱신된 블랙홀 날짜 LocalDateTime + */ + private LocalDateTime refreshBlackholedAt(String userName) { + log.info("refreshBlackholedAt {}", userName); + JsonNode blackholeInfo = getBlackholeInfo(userName); + return parseBlackholedAt(blackholeInfo); + } + + /** + * 유저속성의 블랙홀 날짜를 갱신한다. + * + * @param userId 유저 아이디 + * @param blackholedAt 갱신할 블랙홀 날짜 + */ + private void updateUserBlackholedAt(Long userId, LocalDateTime blackholedAt) { + userService.updateUserBlackholedAt(userId, blackholedAt); + } + + /** + * 블랙홀 갱신 후 처리 + * + * 블랙홀일 경우 반납 및 삭제 처리 + * 블랙홀이 아닐경우 유저 정보(블랙홀일자) 업데이트 + * + * @param userBlackholeInfoDto + */ + public void blackholeRefresher(UserBlackholeInfoDto userBlackholeInfoDto) { + LocalDateTime refreshedBlackholedAt = refreshBlackholedAt(userBlackholeInfoDto.getName()); + if (isBlackholed(refreshedBlackholedAt)) { + handleBlackholed(userBlackholeInfoDto); + throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); + } else { + updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), refreshedBlackholedAt); + } + } + + /** + * 스케쥴러가 샐행하는 블랙홀 처리 메서드 유저의 블랙홀 정보를 갱신하여 블랙홀에 빠졌는지 확인 후 처리한다. + *

+ * 블랙홀에 빠진경우 반납 / 계정 삭제처리 블랙홀에 빠지지 않은경우 블랙홀 날짜 갱신 + * + * @param userInfoDto + */ + + public void handleBlackholeByScheduler(UserBlackholeInfoDto userInfoDto) { + log.info("called handleBlackhole {}", userInfoDto); + LocalDateTime now = LocalDateTime.now(); + try { + JsonNode jsonRefreshedUserInfo = getBlackholeInfo(userInfoDto.getName()); + if (!isValidCadet(jsonRefreshedUserInfo)) { + handleNotCadet(userInfoDto, now); + return; + } + LocalDateTime newBlackholedAt = parseBlackholedAt(jsonRefreshedUserInfo); + log.info("갱신된 블랙홀 날짜 {}", newBlackholedAt); + log.info("오늘 날짜 {}", now); + + if (isBlackholed(newBlackholedAt)) { + handleBlackholed(userInfoDto); + } else { + handleNotBlackholed(userInfoDto, newBlackholedAt); + } + } catch (HttpClientErrorException e) { + handleHttpClientError(userInfoDto, now, e); + } catch (ServiceException e) { + if (e.getStatus().equals(ExceptionStatus.NO_LENT_CABINET)) { + userService.deleteUser(userInfoDto.getUserId(), now); + } + } catch (Exception e) { + log.error("handleBlackhole Exception: {}", userInfoDto, e); + } + } +} diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java index 61fcba4ad..3382a5e0e 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java @@ -14,16 +14,17 @@ @Component @RequiredArgsConstructor @Log4j2 +@Deprecated public class BlackholeRefresher { private final FtApiManager ftApiManager; private final UserService userService; /** - * 유저의 블랙홀 정보를 찾아온다. + * 유저의 블랙홀 정보를 API 를 통해 요청하 찾아온다. * * @param userName 유저 이름 - * @return JsonNode + * @return JsonNode 유저의 블랙홀 정보 * @throws ServiceException */ public JsonNode getBlackholeInfo(String userName) @@ -49,9 +50,9 @@ private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { } /** - * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. - * - * @return 블랙홀에 빠졌는지 여부 + * 유저의 블랙홀 날짜를 갱신하여 블랙홀에 빠졌는지 확인 후 업데이트 + * @param userBlackholeInfoDto + * @return */ public Boolean isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto userBlackholeInfoDto) { log.info("isBlackholedAndUpdateBlackhole {}", userBlackholeInfoDto); @@ -65,4 +66,39 @@ public Boolean isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto userBlackhole return true; } } + + /** + * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. + * + * @return 블랙홀에 빠졌는지 여부 + */ + public boolean isBlackholed(LocalDateTime blackholedAt) { + log.info("isBlackholed {}", blackholedAt); + LocalDateTime now = LocalDateTime.now(); + if (blackholedAt == null || blackholedAt.isAfter(now)) { + return false; + } else { + return true; + } + } + + /** + * 유저의 블랙홀 날짜를 갱신하여 LocalDateTime으로 반환한다. + * @param userName 유저 이름 + * @return 갱신된 블랙홀 날짜 LocalDateTime + */ + public LocalDateTime refreshBlackholedAt(String userName) { + log.info("refreshBlackholedAt {}", userName); + JsonNode blackholeInfo = getBlackholeInfo(userName); + return parseBlackholedAt(blackholeInfo); + } + + /** + * 유저속성의 블랙홀 날짜를 갱신한다. + * @param userId 유저 아이디 + * @param blackholedAt 갱신할 블랙홀 날짜 + */ + public void refreshBlackholedAt(Long userId, LocalDateTime blackholedAt){ + userService.updateUserBlackholedAt(userId, blackholedAt); + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java index 5610a44fa..31c684ab4 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java @@ -8,6 +8,7 @@ import org.ftclub.cabinet.lent.service.LentService; import org.ftclub.cabinet.user.service.UserService; import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManager; +import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManagerV2; import org.ftclub.cabinet.utils.leave.absence.LeaveAbsenceManager; import org.ftclub.cabinet.utils.overdue.manager.OverdueManager; import org.springframework.scheduling.annotation.EnableScheduling; @@ -27,7 +28,7 @@ public class SystemScheduler { private final OverdueManager overdueManager; private final LentService lentService; private final UserService userService; - private final BlackholeManager blackholeManager; + private final BlackholeManagerV2 blackholeManager; private static final long DELAY_TIME = 2000; @@ -59,7 +60,7 @@ public void checkRiskOfBlackhole() { log.info("called checkRiskOfBlackhole"); List blackholeInfos = userService.getAllRiskOfBlackholeInfo(); for (UserBlackholeInfoDto blackholeInfo : blackholeInfos) { - blackholeManager.handleBlackhole(blackholeInfo); + blackholeManager.handleBlackholeByScheduler(blackholeInfo); try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { @@ -77,7 +78,7 @@ public void checkNoRiskOfBlackhole() { log.info("called checkNoRiskOfBlackhole"); List blackholeInfos = userService.getAllNoRiskOfBlackholeInfo(); for (UserBlackholeInfoDto blackholeInfo : blackholeInfos) { - blackholeManager.handleBlackhole(blackholeInfo); + blackholeManager.handleBlackholeByScheduler(blackholeInfo); try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { From f3bb117d4a86ed740504df3ed952cee122cc3fbd Mon Sep 17 00:00:00 2001 From: space Date: Thu, 17 Aug 2023 03:41:19 +0900 Subject: [PATCH 17/21] =?UTF-8?q?[BE]=20REFACTOR:=20=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ftclub/cabinet/exception/ExceptionStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java index ed8aea3e1..97b10e89b 100644 --- a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java +++ b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionStatus.java @@ -34,7 +34,7 @@ public enum ExceptionStatus { SHARE_BANNED_USER(HttpStatus.BAD_REQUEST, "SHARE 밴 상태의 유저입니다."), NOT_FOUND_BAN_HISTORY(HttpStatus.NOT_FOUND, "현재 정지 상태인 유저가 아닙니다."), BLACKHOLED_USER(HttpStatus.BAD_REQUEST, "블랙홀 상태의 유저입니다."), - BLACKHOLE_REFRESHING(HttpStatus.BAD_REQUEST, "블랙홀 갱신 중 입니다.\n다시 시도해주세요."), + BLACKHOLE_REFRESHING(HttpStatus.BAD_REQUEST, "블랙홀 갱신 중 입니다.\n잠시 후에 다시 시도해주세요."), UNAUTHORIZED_ADMIN(HttpStatus.UNAUTHORIZED, "관리자 로그인 정보가 유효하지 않습니다\n다시 로그인해주세요"), UNAUTHORIZED_USER(HttpStatus.UNAUTHORIZED, "사용자 로그인 정보가 유효하지 않습니다\n다시 로그인해주세요"), EXTERNAL_API_EXCEPTION(HttpStatus.BAD_REQUEST, "외부 API와 통신 중 에러가 발생했습니다"), From acefae0c6e1c8b6078b7acdeb508c52d555177d9 Mon Sep 17 00:00:00 2001 From: space Date: Thu, 17 Aug 2023 03:47:12 +0900 Subject: [PATCH 18/21] [BE] REFACTOR: refector Blackholemanager --- .../BlackholedUserLentEventListener.java | 2 +- .../cabinet/lent/domain/LentPolicyImpl.java | 2 +- .../blackhole/manager/BlackholeManagerV2.java | 50 +++++++++++-------- .../utils/scheduler/SystemScheduler.java | 4 +- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java b/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java index 3a920ab07..177bede90 100644 --- a/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java +++ b/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java @@ -21,6 +21,6 @@ public class BlackholedUserLentEventListener { @EventListener public void handleBlackholedUserLentAttemptingEvent(UserBlackholeInfoDto userBlackholeInfoDto) { log.info("Called handleBlackholedUserLentAttemptingEvent"); - blackholeManager.blackholeRefresher(userBlackholeInfoDto); + blackholeManager.handleBlackhole(userBlackholeInfoDto); } } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java index a4a60c75f..0201d6fd1 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java @@ -110,12 +110,12 @@ public LentPolicyStatus verifyUserForLent(User user, Cabinet cabinet, int userAc } if (user.getBlackholedAt() != null && user.getBlackholedAt() .isBefore(LocalDateTime.now())) { + // 다시 돌고 돌고 돌고~ publisher.publishEvent(UserBlackholeInfoDto.of(user)); throw new DomainException(ExceptionStatus.BLACKHOLE_REFRESHING); // if(user.getBlackholedAt() != null && user.getBlackholedAt().isBefore(LocalDateTime.now())) // return LentPolicyStatus.BLACKHOLED_USER; - // if(blackholeRefresher.isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto.of(user))) // return LentPolicyStatus.BLACKHOLED_USER; } diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java index e196ac8d6..441947f97 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java @@ -6,7 +6,6 @@ import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.auth.service.FtApiManager; import org.ftclub.cabinet.dto.UserBlackholeInfoDto; -import org.ftclub.cabinet.exception.DomainException; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; import org.ftclub.cabinet.lent.service.LentService; @@ -32,7 +31,8 @@ public class BlackholeManagerV2 { * @return 카뎃 여부 */ private boolean isValidCadet(JsonNode jsonUserInfo) { - log.info("isValidCadet {}", jsonUserInfo); + log.debug("isValidCadet {}", jsonUserInfo); + log.info("isValidCadet" ); return jsonUserInfo.get("cursus_users").size() >= 2; } @@ -130,8 +130,10 @@ private void handleHttpClientError(UserBlackholeInfoDto userBlackholeInfoDto, Lo private JsonNode getBlackholeInfo(String userName) throws ServiceException, HttpClientErrorException { log.info("called refreshBlackhole{}", userName); - return ftApiManager.getFtUsersInfoByName( + JsonNode userInfoFromIntra = ftApiManager.getFtUsersInfoByName( userName); + + return userInfoFromIntra; } @@ -157,23 +159,6 @@ private void updateUserBlackholedAt(Long userId, LocalDateTime blackholedAt) { userService.updateUserBlackholedAt(userId, blackholedAt); } - /** - * 블랙홀 갱신 후 처리 - * - * 블랙홀일 경우 반납 및 삭제 처리 - * 블랙홀이 아닐경우 유저 정보(블랙홀일자) 업데이트 - * - * @param userBlackholeInfoDto - */ - public void blackholeRefresher(UserBlackholeInfoDto userBlackholeInfoDto) { - LocalDateTime refreshedBlackholedAt = refreshBlackholedAt(userBlackholeInfoDto.getName()); - if (isBlackholed(refreshedBlackholedAt)) { - handleBlackholed(userBlackholeInfoDto); - throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); - } else { - updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), refreshedBlackholedAt); - } - } /** * 스케쥴러가 샐행하는 블랙홀 처리 메서드 유저의 블랙홀 정보를 갱신하여 블랙홀에 빠졌는지 확인 후 처리한다. @@ -183,7 +168,7 @@ public void blackholeRefresher(UserBlackholeInfoDto userBlackholeInfoDto) { * @param userInfoDto */ - public void handleBlackholeByScheduler(UserBlackholeInfoDto userInfoDto) { + public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { log.info("called handleBlackhole {}", userInfoDto); LocalDateTime now = LocalDateTime.now(); try { @@ -211,4 +196,27 @@ public void handleBlackholeByScheduler(UserBlackholeInfoDto userInfoDto) { log.error("handleBlackhole Exception: {}", userInfoDto, e); } } + + + + + + // 따로 분리할 필요 없을듯.. + /** + * 블랙홀 갱신 후 처리 + * + * 블랙홀일 경우 반납 및 삭제 처리 + * 블랙홀이 아닐경우 유저 정보(블랙홀일자) 업데이트 + * + * @param userBlackholeInfoDto + */ + public void blackholeRefresher(UserBlackholeInfoDto userBlackholeInfoDto) { + LocalDateTime refreshedBlackholedAt = refreshBlackholedAt(userBlackholeInfoDto.getName()); + if (isBlackholed(refreshedBlackholedAt)) { + handleBlackholed(userBlackholeInfoDto); + throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); + } else { + updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), refreshedBlackholedAt); + } + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java index 31c684ab4..a7fcdaf1d 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java @@ -60,7 +60,7 @@ public void checkRiskOfBlackhole() { log.info("called checkRiskOfBlackhole"); List blackholeInfos = userService.getAllRiskOfBlackholeInfo(); for (UserBlackholeInfoDto blackholeInfo : blackholeInfos) { - blackholeManager.handleBlackholeByScheduler(blackholeInfo); + blackholeManager.handleBlackhole(blackholeInfo); try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { @@ -78,7 +78,7 @@ public void checkNoRiskOfBlackhole() { log.info("called checkNoRiskOfBlackhole"); List blackholeInfos = userService.getAllNoRiskOfBlackholeInfo(); for (UserBlackholeInfoDto blackholeInfo : blackholeInfos) { - blackholeManager.handleBlackholeByScheduler(blackholeInfo); + blackholeManager.handleBlackhole(blackholeInfo); try { Thread.sleep(DELAY_TIME); } catch (InterruptedException e) { From ec325a1d3d25cb919dadccc6fbd204adc2452e77 Mon Sep 17 00:00:00 2001 From: Woo Joo Chae Date: Fri, 18 Aug 2023 17:18:53 +0900 Subject: [PATCH 19/21] =?UTF-8?q?[BE]=20REFACTOR:=20=EB=B8=94=EB=9E=99?= =?UTF-8?q?=ED=99=80=EB=A7=A4=EB=8B=88=EC=A0=80=20=EC=B5=9C=EC=A2=85=20-?= =?UTF-8?q?=20=EC=9E=90=EB=8F=99=EA=B0=B1=EC=8B=A0=ED=98=95=ED=83=9C?= =?UTF-8?q?=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BlackholedUserLentEventListener.java | 10 +- .../cabinet/lent/domain/LentPolicyImpl.java | 12 +- .../blackhole/manager/BlackholeManager.java | 92 +++++++- .../blackhole/manager/BlackholeManagerV2.java | 222 ------------------ .../blackhole/manager/BlackholeRefresher.java | 104 -------- .../utils/scheduler/SystemScheduler.java | 12 +- .../manager/BlackholeManagerUnitTest.java | 32 +-- 7 files changed, 101 insertions(+), 383 deletions(-) delete mode 100644 backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java delete mode 100644 backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java diff --git a/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java b/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java index 177bede90..b2478601b 100644 --- a/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java +++ b/backend/src/main/java/org/ftclub/cabinet/event/BlackholedUserLentEventListener.java @@ -3,21 +3,19 @@ import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.dto.UserBlackholeInfoDto; -import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManagerV2; +import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManager; import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.stereotype.Component; @Log4j2 @Component -@EnableAsync +//@EnableAsync @RequiredArgsConstructor public class BlackholedUserLentEventListener { - private final BlackholeManagerV2 blackholeManager; + private final BlackholeManager blackholeManager; - @Async + // @Async @EventListener public void handleBlackholedUserLentAttemptingEvent(UserBlackholeInfoDto userBlackholeInfoDto) { log.info("Called handleBlackholedUserLentAttemptingEvent"); diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java index 0201d6fd1..a39b8b081 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/domain/LentPolicyImpl.java @@ -15,7 +15,6 @@ import org.ftclub.cabinet.user.domain.User; import org.ftclub.cabinet.user.domain.UserRole; import org.ftclub.cabinet.utils.DateUtil; -import org.ftclub.cabinet.utils.blackhole.manager.BlackholeRefresher; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; @@ -110,14 +109,11 @@ public LentPolicyStatus verifyUserForLent(User user, Cabinet cabinet, int userAc } if (user.getBlackholedAt() != null && user.getBlackholedAt() .isBefore(LocalDateTime.now())) { - // 다시 돌고 돌고 돌고~ publisher.publishEvent(UserBlackholeInfoDto.of(user)); - throw new DomainException(ExceptionStatus.BLACKHOLE_REFRESHING); - -// if(user.getBlackholedAt() != null && user.getBlackholedAt().isBefore(LocalDateTime.now())) -// return LentPolicyStatus.BLACKHOLED_USER; -// if(blackholeRefresher.isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto.of(user))) -// return LentPolicyStatus.BLACKHOLED_USER; + if (user.getBlackholedAt() != null && user.getBlackholedAt() + .isBefore(LocalDateTime.now())) { + return LentPolicyStatus.BLACKHOLED_USER; + } } // 유저가 페널티 2 종류 이상 받을 수 있나? <- 실제로 그럴리 없지만 lentPolicy 객체는 그런 사실을 모르고, 유연하게 구현? diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index 27edbd914..a6720fa11 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -4,6 +4,7 @@ import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; +import org.ftclub.cabinet.auth.service.FtApiManager; import org.ftclub.cabinet.dto.UserBlackholeInfoDto; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; @@ -16,12 +17,11 @@ @Component @RequiredArgsConstructor @Log4j2 -@Deprecated public class BlackholeManager { + private final FtApiManager ftApiManager; private final LentService lentService; private final UserService userService; - private final BlackholeRefresher blackholeRefresher; /** * JsonNode에 담긴 cursus_users를 확인하여 해당 유저가 카뎃인지 확인한다. cursus_users에 담긴 정보가 2개 이상이면 카뎃이다. @@ -30,8 +30,9 @@ public class BlackholeManager { * @param jsonUserInfo JsonNode에 담긴 유저 정보 * @return 카뎃 여부 */ - private Boolean isValidCadet(JsonNode jsonUserInfo) { - log.info("isValidCadet {}", jsonUserInfo); + private boolean isValidCadet(JsonNode jsonUserInfo) { + log.debug("isValidCadet {}", jsonUserInfo); + log.info("isValidCadet"); return jsonUserInfo.get("cursus_users").size() >= 2; } @@ -54,11 +55,11 @@ private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. * * @param blackholedAtDate 블랙홀 날짜 - * @param now 현재 시간 * @return 블랙홀에 빠졌는지 여부 */ - private Boolean isBlackholed(LocalDateTime blackholedAtDate, LocalDateTime now) { - log.info("isBlackholed {} {}", blackholedAtDate, now); + private boolean isBlackholed(LocalDateTime blackholedAtDate) { + log.info("isBlackholed {} {}", blackholedAtDate); + LocalDateTime now = LocalDateTime.now(); if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { return false; } else { @@ -82,10 +83,10 @@ private void handleNotCadet(UserBlackholeInfoDto userBlackholeInfoDto, LocalDate * 블랙홀에 빠진 유저를 강제 반납 및 삭제 처리한다. * * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} - * @param now 현재 시간 */ - private void handleBlackholed(UserBlackholeInfoDto userBlackholeInfoDto, LocalDateTime now) { + private void handleBlackholed(UserBlackholeInfoDto userBlackholeInfoDto) { log.info("{}는 블랙홀에 빠졌습니다.", userBlackholeInfoDto); + LocalDateTime now = LocalDateTime.now(); lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); userService.deleteUser(userBlackholeInfoDto.getUserId(), now); } @@ -119,11 +120,59 @@ private void handleHttpClientError(UserBlackholeInfoDto userBlackholeInfoDto, Lo } } + /** + * 유저의 블랙홀 정보를 API 를 통해 요청하여 찾아온다. + * + * @param userName 유저 이름 + * @return JsonNode 유저의 블랙홀 정보 + * @throws ServiceException + */ + private JsonNode getBlackholeInfo(String userName) + throws ServiceException, HttpClientErrorException { + log.info("called refreshBlackhole{}", userName); + JsonNode userInfoFromIntra = ftApiManager.getFtUsersInfoByName( + userName); + + return userInfoFromIntra; + } + + + /** + * 유저의 블랙홀 날짜를 갱신하여 LocalDateTime으로 반환한다. + * + * @param userName 유저 이름 + * @return 갱신된 블랙홀 날짜 LocalDateTime + */ + private LocalDateTime refreshBlackholedAt(String userName) { + log.info("refreshBlackholedAt {}", userName); + JsonNode blackholeInfo = getBlackholeInfo(userName); + return parseBlackholedAt(blackholeInfo); + } + + /** + * 유저속성의 블랙홀 날짜를 갱신한다. + * + * @param userId 유저 아이디 + * @param blackholedAt 갱신할 블랙홀 날짜 + */ + private void updateUserBlackholedAt(Long userId, LocalDateTime blackholedAt) { + userService.updateUserBlackholedAt(userId, blackholedAt); + } + + + /** + * 스케쥴러가 샐행하는 블랙홀 처리 메서드 유저의 블랙홀 정보를 갱신하여 블랙홀에 빠졌는지 확인 후 처리한다. + *

+ * 블랙홀에 빠진경우 반납 / 계정 삭제처리 블랙홀에 빠지지 않은경우 블랙홀 날짜 갱신 + * + * @param userInfoDto + */ + public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { log.info("called handleBlackhole {}", userInfoDto); LocalDateTime now = LocalDateTime.now(); try { - JsonNode jsonRefreshedUserInfo = blackholeRefresher.getBlackholeInfo(userInfoDto.getName()); + JsonNode jsonRefreshedUserInfo = getBlackholeInfo(userInfoDto.getName()); if (!isValidCadet(jsonRefreshedUserInfo)) { handleNotCadet(userInfoDto, now); return; @@ -132,8 +181,8 @@ public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { log.info("갱신된 블랙홀 날짜 {}", newBlackholedAt); log.info("오늘 날짜 {}", now); - if (isBlackholed(newBlackholedAt, now)) { - handleBlackholed(userInfoDto, now); + if (isBlackholed(newBlackholedAt)) { + handleBlackholed(userInfoDto); } else { handleNotBlackholed(userInfoDto, newBlackholedAt); } @@ -147,4 +196,23 @@ public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { log.error("handleBlackhole Exception: {}", userInfoDto, e); } } + + // 따로 분리할 필요 없을듯.. + + /** + * 블랙홀 갱신 후 처리 + *

+ * 블랙홀일 경우 반납 및 삭제 처리 블랙홀이 아닐경우 유저 정보(블랙홀일자) 업데이트 + * + * @param userBlackholeInfoDto + */ + public void blackholeRefresher(UserBlackholeInfoDto userBlackholeInfoDto) { + LocalDateTime refreshedBlackholedAt = refreshBlackholedAt(userBlackholeInfoDto.getName()); + if (isBlackholed(refreshedBlackholedAt)) { + handleBlackholed(userBlackholeInfoDto); + throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); + } else { + updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), refreshedBlackholedAt); + } + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java deleted file mode 100644 index 441947f97..000000000 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerV2.java +++ /dev/null @@ -1,222 +0,0 @@ -package org.ftclub.cabinet.utils.blackhole.manager; - -import com.fasterxml.jackson.databind.JsonNode; -import java.time.LocalDateTime; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.ftclub.cabinet.auth.service.FtApiManager; -import org.ftclub.cabinet.dto.UserBlackholeInfoDto; -import org.ftclub.cabinet.exception.ExceptionStatus; -import org.ftclub.cabinet.exception.ServiceException; -import org.ftclub.cabinet.lent.service.LentService; -import org.ftclub.cabinet.user.service.UserService; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpClientErrorException; - -@Component -@RequiredArgsConstructor -@Log4j2 -public class BlackholeManagerV2 { - - private final FtApiManager ftApiManager; - private final LentService lentService; - private final UserService userService; - - /** - * JsonNode에 담긴 cursus_users를 확인하여 해당 유저가 카뎃인지 확인한다. cursus_users에 담긴 정보가 2개 이상이면 카뎃이다. - * cursus_users에 담긴 정보가 2개 미만이면 카뎃이 아니다. (피시너 등) - * - * @param jsonUserInfo JsonNode에 담긴 유저 정보 - * @return 카뎃 여부 - */ - private boolean isValidCadet(JsonNode jsonUserInfo) { - log.debug("isValidCadet {}", jsonUserInfo); - log.info("isValidCadet" ); - return jsonUserInfo.get("cursus_users").size() >= 2; - } - - /** - * 블랙홀 날짜를 LocalDateTime으로 파싱한다. - * - * @param jsonUserInfo JsonNode에 담긴 유저 정보 - * @return LocalDateTime으로 파싱된 블랙홀 날짜 - */ - private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { - log.info("parseBlackholedAt {}", jsonUserInfo); - JsonNode JsonBlackholedAt = jsonUserInfo.get("cursus_users").get(1).get("blackholed_at"); - if (JsonBlackholedAt == null || JsonBlackholedAt.asText().equals("null")) { - return null; - } - return LocalDateTime.parse(JsonBlackholedAt.asText().substring(0, 19)); - } - - /** - * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. - * - * @param blackholedAtDate 블랙홀 날짜 - * @return 블랙홀에 빠졌는지 여부 - */ - private boolean isBlackholed(LocalDateTime blackholedAtDate) { - log.info("isBlackholed {} {}", blackholedAtDate); - LocalDateTime now = LocalDateTime.now(); - if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { - return false; - } else { - return true; - } - } - - /** - * 카뎃이 아닌 유저를 강제 반납 및 삭제 처리한다. - * - * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} - * @param now 현재 시간 - */ - private void handleNotCadet(UserBlackholeInfoDto userBlackholeInfoDto, LocalDateTime now) { - log.warn("{}는 카뎃이 아닙니다.", userBlackholeInfoDto); - lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); - userService.deleteUser(userBlackholeInfoDto.getUserId(), now); - } - - /** - * 블랙홀에 빠진 유저를 강제 반납 및 삭제 처리한다. - * - * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} - */ - private void handleBlackholed(UserBlackholeInfoDto userBlackholeInfoDto) { - log.info("{}는 블랙홀에 빠졌습니다.", userBlackholeInfoDto); - LocalDateTime now = LocalDateTime.now(); - lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); - userService.deleteUser(userBlackholeInfoDto.getUserId(), now); - } - - /** - * 블랙홀에 빠지지 않은 유저의 블랙홀 날짜를 갱신한다. - * - * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} - * @param newBlackholedAt 갱신된 블랙홀 날짜 - */ - private void handleNotBlackholed(UserBlackholeInfoDto userBlackholeInfoDto, - LocalDateTime newBlackholedAt) { - log.info("{}는 블랙홀에 빠지지 않았습니다.", userBlackholeInfoDto); - userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), newBlackholedAt); - } - - /** - * 유저 정보 조회 결과 해당 유저를 42에서 찾을 수 없다면, 강제 반납 및 삭제 처리한다. - * - * @param userBlackholeInfoDto 유저 정보 {@link UserBlackholeInfoDto} - * @param now 현재 시간 - * @param e HttpClientErrorException - */ - private void handleHttpClientError(UserBlackholeInfoDto userBlackholeInfoDto, LocalDateTime now, - HttpClientErrorException e) { - log.error("handleBlackhole HttpClientErrorException {}", e.getStatusCode()); - if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) { - log.warn("{}는 42에서 찾을 수 없습니다.", userBlackholeInfoDto); - lentService.terminateLentCabinet(userBlackholeInfoDto.getUserId()); - userService.deleteUser(userBlackholeInfoDto.getUserId(), now); - } - } - - /** - * 유저의 블랙홀 정보를 API 를 통해 요청하여 찾아온다. - * - * @param userName 유저 이름 - * @return JsonNode 유저의 블랙홀 정보 - * @throws ServiceException - */ - private JsonNode getBlackholeInfo(String userName) - throws ServiceException, HttpClientErrorException { - log.info("called refreshBlackhole{}", userName); - JsonNode userInfoFromIntra = ftApiManager.getFtUsersInfoByName( - userName); - - return userInfoFromIntra; - } - - - /** - * 유저의 블랙홀 날짜를 갱신하여 LocalDateTime으로 반환한다. - * - * @param userName 유저 이름 - * @return 갱신된 블랙홀 날짜 LocalDateTime - */ - private LocalDateTime refreshBlackholedAt(String userName) { - log.info("refreshBlackholedAt {}", userName); - JsonNode blackholeInfo = getBlackholeInfo(userName); - return parseBlackholedAt(blackholeInfo); - } - - /** - * 유저속성의 블랙홀 날짜를 갱신한다. - * - * @param userId 유저 아이디 - * @param blackholedAt 갱신할 블랙홀 날짜 - */ - private void updateUserBlackholedAt(Long userId, LocalDateTime blackholedAt) { - userService.updateUserBlackholedAt(userId, blackholedAt); - } - - - /** - * 스케쥴러가 샐행하는 블랙홀 처리 메서드 유저의 블랙홀 정보를 갱신하여 블랙홀에 빠졌는지 확인 후 처리한다. - *

- * 블랙홀에 빠진경우 반납 / 계정 삭제처리 블랙홀에 빠지지 않은경우 블랙홀 날짜 갱신 - * - * @param userInfoDto - */ - - public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { - log.info("called handleBlackhole {}", userInfoDto); - LocalDateTime now = LocalDateTime.now(); - try { - JsonNode jsonRefreshedUserInfo = getBlackholeInfo(userInfoDto.getName()); - if (!isValidCadet(jsonRefreshedUserInfo)) { - handleNotCadet(userInfoDto, now); - return; - } - LocalDateTime newBlackholedAt = parseBlackholedAt(jsonRefreshedUserInfo); - log.info("갱신된 블랙홀 날짜 {}", newBlackholedAt); - log.info("오늘 날짜 {}", now); - - if (isBlackholed(newBlackholedAt)) { - handleBlackholed(userInfoDto); - } else { - handleNotBlackholed(userInfoDto, newBlackholedAt); - } - } catch (HttpClientErrorException e) { - handleHttpClientError(userInfoDto, now, e); - } catch (ServiceException e) { - if (e.getStatus().equals(ExceptionStatus.NO_LENT_CABINET)) { - userService.deleteUser(userInfoDto.getUserId(), now); - } - } catch (Exception e) { - log.error("handleBlackhole Exception: {}", userInfoDto, e); - } - } - - - - - - // 따로 분리할 필요 없을듯.. - /** - * 블랙홀 갱신 후 처리 - * - * 블랙홀일 경우 반납 및 삭제 처리 - * 블랙홀이 아닐경우 유저 정보(블랙홀일자) 업데이트 - * - * @param userBlackholeInfoDto - */ - public void blackholeRefresher(UserBlackholeInfoDto userBlackholeInfoDto) { - LocalDateTime refreshedBlackholedAt = refreshBlackholedAt(userBlackholeInfoDto.getName()); - if (isBlackholed(refreshedBlackholedAt)) { - handleBlackholed(userBlackholeInfoDto); - throw new ServiceException(ExceptionStatus.BLACKHOLED_USER); - } else { - updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), refreshedBlackholedAt); - } - } -} diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java deleted file mode 100644 index 3382a5e0e..000000000 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeRefresher.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.ftclub.cabinet.utils.blackhole.manager; - -import com.fasterxml.jackson.databind.JsonNode; -import java.time.LocalDateTime; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.ftclub.cabinet.auth.service.FtApiManager; -import org.ftclub.cabinet.dto.UserBlackholeInfoDto; -import org.ftclub.cabinet.exception.ServiceException; -import org.ftclub.cabinet.user.service.UserService; -import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpClientErrorException; - -@Component -@RequiredArgsConstructor -@Log4j2 -@Deprecated -public class BlackholeRefresher { - - private final FtApiManager ftApiManager; - private final UserService userService; - - /** - * 유저의 블랙홀 정보를 API 를 통해 요청하 찾아온다. - * - * @param userName 유저 이름 - * @return JsonNode 유저의 블랙홀 정보 - * @throws ServiceException - */ - public JsonNode getBlackholeInfo(String userName) - throws ServiceException, HttpClientErrorException { - log.info("called refreshBlackhole{}", userName); - return ftApiManager.getFtUsersInfoByName( - userName); - } - - /** - * 블랙홀 날짜를 LocalDateTime으로 파싱한다. - * - * @param jsonUserInfo JsonNode에 담긴 유저 정보 - * @return LocalDateTime으로 파싱된 블랙홀 날짜 - */ - private LocalDateTime parseBlackholedAt(JsonNode jsonUserInfo) { - log.info("parseBlackholedAt {}", jsonUserInfo); - JsonNode JsonBlackholedAt = jsonUserInfo.get("cursus_users").get(1).get("blackholed_at"); - if (JsonBlackholedAt == null || JsonBlackholedAt.asText().equals("null")) { - return null; - } - return LocalDateTime.parse(JsonBlackholedAt.asText().substring(0, 19)); - } - - /** - * 유저의 블랙홀 날짜를 갱신하여 블랙홀에 빠졌는지 확인 후 업데이트 - * @param userBlackholeInfoDto - * @return - */ - public Boolean isBlackholedAndUpdateBlackhole(UserBlackholeInfoDto userBlackholeInfoDto) { - log.info("isBlackholedAndUpdateBlackhole {}", userBlackholeInfoDto); - LocalDateTime now = LocalDateTime.now(); - JsonNode blackholeInfo = getBlackholeInfo(userBlackholeInfoDto.getName()); - LocalDateTime blackholedAtDate = parseBlackholedAt(blackholeInfo); - if (blackholedAtDate == null || blackholedAtDate.isAfter(now)) { - userService.updateUserBlackholedAt(userBlackholeInfoDto.getUserId(), blackholedAtDate); - return false; - } else { - return true; - } - } - - /** - * 갱신된 블랙홀 날짜를 바탕으로 블랙홀에 빠졌는지 확인한다. - * - * @return 블랙홀에 빠졌는지 여부 - */ - public boolean isBlackholed(LocalDateTime blackholedAt) { - log.info("isBlackholed {}", blackholedAt); - LocalDateTime now = LocalDateTime.now(); - if (blackholedAt == null || blackholedAt.isAfter(now)) { - return false; - } else { - return true; - } - } - - /** - * 유저의 블랙홀 날짜를 갱신하여 LocalDateTime으로 반환한다. - * @param userName 유저 이름 - * @return 갱신된 블랙홀 날짜 LocalDateTime - */ - public LocalDateTime refreshBlackholedAt(String userName) { - log.info("refreshBlackholedAt {}", userName); - JsonNode blackholeInfo = getBlackholeInfo(userName); - return parseBlackholedAt(blackholeInfo); - } - - /** - * 유저속성의 블랙홀 날짜를 갱신한다. - * @param userId 유저 아이디 - * @param blackholedAt 갱신할 블랙홀 날짜 - */ - public void refreshBlackholedAt(Long userId, LocalDateTime blackholedAt){ - userService.updateUserBlackholedAt(userId, blackholedAt); - } -} diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java index a7fcdaf1d..7a49c5d3e 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/scheduler/SystemScheduler.java @@ -8,7 +8,6 @@ import org.ftclub.cabinet.lent.service.LentService; import org.ftclub.cabinet.user.service.UserService; import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManager; -import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManagerV2; import org.ftclub.cabinet.utils.leave.absence.LeaveAbsenceManager; import org.ftclub.cabinet.utils.overdue.manager.OverdueManager; import org.springframework.scheduling.annotation.EnableScheduling; @@ -28,13 +27,12 @@ public class SystemScheduler { private final OverdueManager overdueManager; private final LentService lentService; private final UserService userService; - private final BlackholeManagerV2 blackholeManager; + private final BlackholeManager blackholeManager; private static final long DELAY_TIME = 2000; /** - * 매일 자정마다 대여 기록을 확인하여, 연체 메일 발송 및 휴학생 처리를 트리거하는 메소드 - * 2초 간격으로 블랙홀 검증 + * 매일 자정마다 대여 기록을 확인하여, 연체 메일 발송 및 휴학생 처리를 트리거하는 메소드 2초 간격으로 블랙홀 검증 */ @Scheduled(cron = "${spring.schedule.cron.leave-absence}") public void checkAllLents() { @@ -52,8 +50,7 @@ public void checkAllLents() { } /** - * 매주 월요일 자정 42분에 블랙홀에 빠진 유저 처리를 트리거하는 메소드 - * 2초 간격으로 블랙홀 검증 + * 매주 월요일 자정 42분에 블랙홀에 빠진 유저 처리를 트리거하는 메소드 2초 간격으로 블랙홀 검증 */ @Scheduled(cron = "${spring.schedule.cron.risk-of-blackhole}") public void checkRiskOfBlackhole() { @@ -70,8 +67,7 @@ public void checkRiskOfBlackhole() { } /** - * 매월 1일 01시 42분에 블랙홀에 빠질 위험이 없는 유저들의 블랙홀 처리를 트리거하는 메소드 - * 2초 간격으로 블랙홀 검증 + * 매월 1일 01시 42분에 블랙홀에 빠질 위험이 없는 유저들의 블랙홀 처리를 트리거하는 메소드 2초 간격으로 블랙홀 검증 */ @Scheduled(cron = "${spring.schedule.cron.no-risk-of-blackhole}") public void checkNoRiskOfBlackhole() { diff --git a/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java b/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java index dd5354837..f1b6746fc 100644 --- a/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java +++ b/backend/src/test/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManagerUnitTest.java @@ -14,18 +14,12 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.time.LocalDateTime; -import java.util.List; import org.ftclub.cabinet.auth.service.FtApiManager; import org.ftclub.cabinet.config.FtApiProperties; import org.ftclub.cabinet.dto.UserBlackholeInfoDto; -import org.ftclub.cabinet.exception.ExceptionStatus; -import org.ftclub.cabinet.exception.ServiceException; import org.ftclub.cabinet.lent.service.LentService; import org.ftclub.cabinet.user.service.UserService; -import org.ftclub.cabinet.utils.ExceptionUtil; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,8 +35,6 @@ public class BlackholeManagerUnitTest { @InjectMocks private BlackholeManager blackholeManager; @Mock - private BlackholeRefresher blackholeRefresher; - @Mock private FtApiManager ftApiManager = mock(FtApiManager.class); @Mock private LentService lentService = mock(LentService.class); @@ -88,7 +80,7 @@ void setUp() { LocalDateTime.now().minusDays(1)); JsonNode JsonafterBlackholedAt = objectMapper.readTree(StringAfterBlackholedAt); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn(jsonUserInfo); + given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -120,10 +112,9 @@ void setUp() { beforeBlackholedAt ); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willThrow( - new HttpClientErrorException( - HttpStatus.NOT_FOUND - )); + given(ftApiManager.getFtUsersInfoByName(name)).willThrow(new HttpClientErrorException( + HttpStatus.NOT_FOUND + )); blackholeManager.handleBlackhole(userBlackholeInfoDto); @@ -153,8 +144,7 @@ void setUp() { JsonNode mockFieldZero = mock(JsonNode.class); JsonNode mockFieldOne = mock(JsonNode.class); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( - jsonUserInfo); + given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); given(mockCursusUsers.size()).willReturn(1); @@ -195,8 +185,7 @@ void setUp() { LocalDateTime.now().plusDays(42)); JsonNode JsonafterBlackholedAt = objectMapper.readTree(StringAfterBlackholedAt); - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( - jsonUserInfo); + given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -236,8 +225,7 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( - jsonUserInfo); + given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -276,8 +264,7 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( - jsonUserInfo); + given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); @@ -316,8 +303,7 @@ void setUp() { // 새 블랙홀 날짜 = null JsonNode JsonafterBlackholedAt = null; - given(blackholeRefresher.getBlackholeInfo(userBlackholeInfoDto.getName())).willReturn( - jsonUserInfo); + given(ftApiManager.getFtUsersInfoByName(name)).willReturn(jsonUserInfo); given(jsonUserInfo.get("cursus_users")).willReturn(mockCursusUsers); lenient().when(mockCursusUsers.get(0)).thenReturn(mockFieldZero); lenient().when(mockCursusUsers.get(1)).thenReturn(mockFieldOne); From 8c39cfa105dc5487966e6d8c1a71425616bcafa3 Mon Sep 17 00:00:00 2001 From: space Date: Fri, 18 Aug 2023 23:56:57 +0900 Subject: [PATCH 20/21] =?UTF-8?q?[BE]=20FEAT:=20UTIL=20Exception=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/ExceptionController.java | 8 +++++++ .../cabinet/exception/UtilException.java | 23 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 backend/src/main/java/org/ftclub/cabinet/exception/UtilException.java diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java index 96ac777cb..8b11cc9c5 100644 --- a/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java +++ b/backend/src/main/java/org/ftclub/cabinet/exception/ExceptionController.java @@ -41,4 +41,12 @@ public ResponseEntity domainExceptionHandler(DomainException e) { .body(e.status); } + @ExceptionHandler(UtilException.class) + public ResponseEntity utilExceptionHandler(UtilException e) { + log.warn("[UtilException] {} : {}", e.status.getError(), e.status.getMessage()); + return ResponseEntity + .status(e.status.getStatusCode()) + .body(e.status); + } + } diff --git a/backend/src/main/java/org/ftclub/cabinet/exception/UtilException.java b/backend/src/main/java/org/ftclub/cabinet/exception/UtilException.java new file mode 100644 index 000000000..d626a0fe5 --- /dev/null +++ b/backend/src/main/java/org/ftclub/cabinet/exception/UtilException.java @@ -0,0 +1,23 @@ +package org.ftclub.cabinet.exception; + +/** + * Util에서 throw하는 exception들을 위한 exception 사용 예시: + *

+ *     {@code throw new UtilException(ExceptionStatus.NOT_FOUND_USER);}
+ *
+ * 만약 새로운 exception을 만들 필요가 있다면 {@link ExceptionStatus}에서 새로운 enum값을 추가하면 된다. + * @see org.ftclub.cabinet.exception.ExceptionStatus + */ + +public class UtilException extends RuntimeException { + + final ExceptionStatus status; + + /** + * @param status exception에 대한 정보에 대한 enum + */ + public UtilException(ExceptionStatus status) { + this.status = status; + } + +} From 6ec842cfb24db93c60acd85ad27b1f8c6c54b3f1 Mon Sep 17 00:00:00 2001 From: space Date: Sat, 19 Aug 2023 00:19:37 +0900 Subject: [PATCH 21/21] [BE] REFACTOR: Exception Wrapping --- .../cabinet/utils/blackhole/manager/BlackholeManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java index a6720fa11..92fcb5379 100644 --- a/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java +++ b/backend/src/main/java/org/ftclub/cabinet/utils/blackhole/manager/BlackholeManager.java @@ -8,6 +8,7 @@ import org.ftclub.cabinet.dto.UserBlackholeInfoDto; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; +import org.ftclub.cabinet.exception.UtilException; import org.ftclub.cabinet.lent.service.LentService; import org.ftclub.cabinet.user.service.UserService; import org.springframework.http.HttpStatus; @@ -192,6 +193,9 @@ public void handleBlackhole(UserBlackholeInfoDto userInfoDto) { if (e.getStatus().equals(ExceptionStatus.NO_LENT_CABINET)) { userService.deleteUser(userInfoDto.getUserId(), now); } + else if (e.getStatus().equals(ExceptionStatus.OAUTH_BAD_GATEWAY)) + log.info("handleBlackhole ServiceException {}", e.getStatus()); + throw new UtilException(e.getStatus()); } catch (Exception e) { log.error("handleBlackhole Exception: {}", userInfoDto, e); }