diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java index de4c8665..32017ea3 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java @@ -1,14 +1,13 @@ package com.softeer.backend.fo_domain.fcfs.controller; +import com.softeer.backend.fo_domain.fcfs.dto.FcfsHistoryResponseDto; import com.softeer.backend.fo_domain.fcfs.dto.FcfsPageResponseDto; import com.softeer.backend.fo_domain.fcfs.dto.FcfsRequestDto; -import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResult; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResultResponseDto; import com.softeer.backend.fo_domain.fcfs.service.FcfsService; import com.softeer.backend.global.annotation.AuthInfo; import com.softeer.backend.global.common.response.ResponseDto; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -63,5 +62,13 @@ public ResponseDto handleFcfs(@Parameter(hidden = true) H return ResponseDto.onSuccess(fcfsResultResponseDto); } + @GetMapping("/fcfs/history") + public ResponseDto getFcfsHistory(@Parameter(hidden = true) @AuthInfo Integer userId){ + + FcfsHistoryResponseDto fcfsHistoryResponseDto = fcfsService.getFcfsHistory(userId); + + return ResponseDto.onSuccess(fcfsHistoryResponseDto); + } + } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Fcfs.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Fcfs.java index 727f4f01..f11e8b38 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Fcfs.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Fcfs.java @@ -9,6 +9,7 @@ import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import java.time.LocalDate; import java.time.LocalDateTime; /** @@ -38,8 +39,7 @@ public class Fcfs { @Column(name = "code") private String code; - @CreatedDate @Column(name = "winning_date", nullable = false) - private LocalDateTime winningDate; + private LocalDate winningDate; } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsHistoryResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsHistoryResponseDto.java new file mode 100644 index 00000000..4d848f47 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsHistoryResponseDto.java @@ -0,0 +1,39 @@ +package com.softeer.backend.fo_domain.fcfs.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.time.LocalDate; +import java.util.List; + +/** + * 선착순 이벤트 당첨 기록 응답 Dto 클래스 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@Builder +@Getter +@Setter +public class FcfsHistoryResponseDto { + + @JsonProperty("isFcfsWin") + private boolean isFcfsWin; + + private List fcfsHistoryList; + + @Getter + @AllArgsConstructor + @Builder + public static class FcfsHistory { + + private String barcode; + + private String fcfsCode; + + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate winningDate; + } + + +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsRepository.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsRepository.java index 5d70647c..94ed7d7e 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsRepository.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsRepository.java @@ -22,4 +22,6 @@ public interface FcfsRepository extends JpaRepository { @Query("SELECT f FROM Fcfs f JOIN FETCH f.user WHERE f.round = :round") List findFcfsWithUser(@Param("round") int round); + List findByUserIdOrderByWinningDateAsc(Integer userId); + } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java index 3716307e..6384f53b 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java @@ -1,11 +1,13 @@ package com.softeer.backend.fo_domain.fcfs.service; import com.softeer.backend.fo_domain.draw.service.DrawSettingManager; +import com.softeer.backend.fo_domain.fcfs.domain.Fcfs; import com.softeer.backend.fo_domain.fcfs.dto.*; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsFailResult; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResultResponseDto; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsSuccessResult; import com.softeer.backend.fo_domain.fcfs.exception.FcfsException; +import com.softeer.backend.fo_domain.fcfs.repository.FcfsRepository; import com.softeer.backend.global.annotation.EventLock; import com.softeer.backend.global.common.code.status.ErrorStatus; import com.softeer.backend.global.common.constant.RedisKeyPrefix; @@ -20,9 +22,15 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import static java.util.stream.Collectors.toList; + /** * 선착순 관련 이벤트를 처리하는 클래스 */ @@ -40,6 +48,8 @@ public class FcfsService { private final RandomCodeUtil randomCodeUtil; private final StaticResourceUtil staticResourceUtil; + private final FcfsRepository fcfsRepository; + /** * 선착순 페이지에 필요한 정보를 반환하는 메서드 */ @@ -235,4 +245,53 @@ public FcfsFailResult getFcfsFailResult(Map textContentMap) { .build(); } + /** + * 선착순 당첨 기록 응답을 반환하는 메서드 + */ + public FcfsHistoryResponseDto getFcfsHistory(int userId){ + fcfsRepository.findByUserIdOrderByWinningDateAsc(userId); + List fcfsHistoryList = new ArrayList<>(); + + Map s3ContentMap = staticResourceUtil.getS3ContentMap(); + + LocalDate now = LocalDate.now(); + Integer round = fcfsSettingManager.getFcfsRoundForHistory(now); + if(round == null) + round = fcfsSettingManager.getFcfsRoundForHistory(now.minusDays(1)); + if(round != null + && fcfsRedisUtil.isValueInIntegerSet(RedisKeyPrefix.FCFS_USERID_PREFIX.getPrefix() + round, userId)){ + Map fcfsMap = fcfsRedisUtil.getHashEntries(RedisKeyPrefix.FCFS_CODE_USERID_PREFIX.getPrefix() + round); + + for (Map.Entry entry : fcfsMap.entrySet()) { + if (entry.getValue().equals(userId)) { + String fcfsCode = entry.getKey(); + + fcfsHistoryList.add(FcfsHistoryResponseDto.FcfsHistory.builder() + .barcode(s3ContentMap.get(S3FileName.BARCODE_IMAGE.name())) + .fcfsCode(fcfsCode) + .winningDate(now) + .build()); + + break; + } + } + } + + List fcfsList = fcfsRepository.findByUserIdOrderByWinningDateAsc(userId); + fcfsHistoryList.addAll(fcfsList.stream() + .map((fcfs) -> + FcfsHistoryResponseDto.FcfsHistory.builder() + .barcode(s3ContentMap.get(S3FileName.BARCODE_IMAGE.name())) + .fcfsCode(fcfs.getCode()) + .winningDate(fcfs.getWinningDate()) + .build() + ).toList()); + + return FcfsHistoryResponseDto.builder() + .isFcfsWin(!fcfsHistoryList.isEmpty()) + .fcfsHistoryList(fcfsHistoryList) + .build(); + + } + } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsSettingManager.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsSettingManager.java index b1690841..26a1707a 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsSettingManager.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsSettingManager.java @@ -77,7 +77,7 @@ public void loadInitialData() { /** * 인수로 넘어온 선착순 설정 정보를 바인딩하는 메서드 */ - public void setFcfsSettingList(List fcfsSettings){ + public void setFcfsSettingList(List fcfsSettings) { fcfsSettings.forEach((fcfsSetting) -> { fcfsSettingList.set(fcfsSetting.getRound() - 1, FcfsSettingDto.builder() @@ -110,19 +110,19 @@ public int getRoundForScheduler(LocalDate localDate) { /** * 선착순 이벤트 당첨 가능한 인원수를 반환하는 메서드 */ - public int getFcfsWinnerNum(){ + public int getFcfsWinnerNum() { return fcfsSettingList.get(0).getWinnerNum(); } /** * 현재 시간을 기준으로 선착순 이벤트가 활성화 되어 있는지를 반환하는 메서드 */ - public boolean isFcfsEntryAvailable(LocalDateTime now){ - for(FcfsSettingDto fcfsSettingDto : fcfsSettingList){ + public boolean isFcfsEntryAvailable(LocalDateTime now) { + for (FcfsSettingDto fcfsSettingDto : fcfsSettingList) { LocalDateTime startTime = fcfsSettingDto.getStartTime(); LocalDateTime endTime = fcfsSettingDto.getEndTime(); - if((now.isEqual(startTime) || now.isAfter(startTime)) + if ((now.isEqual(startTime) || now.isAfter(startTime)) && (now.isEqual(endTime) || now.isBefore(endTime))) { return true; } @@ -133,13 +133,13 @@ public boolean isFcfsEntryAvailable(LocalDateTime now){ /** * 현재 시간에 해당하는 선착순 이벤트의 round값을 반환하는 메서드 */ - public Integer getFcfsRound(LocalDateTime now){ + public Integer getFcfsRound(LocalDateTime now) { - for(FcfsSettingDto fcfsSettingDto : fcfsSettingList){ + for (FcfsSettingDto fcfsSettingDto : fcfsSettingList) { LocalDateTime startTime = fcfsSettingDto.getStartTime(); LocalDateTime endTime = fcfsSettingDto.getEndTime(); - if((now.isEqual(startTime) || now.isAfter(startTime)) + if ((now.isEqual(startTime) || now.isAfter(startTime)) && (now.isEqual(endTime) || now.isBefore(endTime))) { return fcfsSettingDto.getRound(); } @@ -150,16 +150,28 @@ public Integer getFcfsRound(LocalDateTime now){ /** * 현재 시간을 기준으로 다음 선착순 이벤트의 시작 시간을 반환하는 메서드 */ - public LocalDateTime getNextFcfsTime(LocalDateTime now){ + public LocalDateTime getNextFcfsTime(LocalDateTime now) { - for(FcfsSettingDto fcfsSettingDto : fcfsSettingList){ + for (FcfsSettingDto fcfsSettingDto : fcfsSettingList) { LocalDateTime startTime = fcfsSettingDto.getStartTime(); - if(now.isBefore(startTime)) { + if (now.isBefore(startTime)) { return startTime; } } return null; } + public Integer getFcfsRoundForHistory(LocalDate now) { + + for (FcfsSettingDto fcfsSettingDto : fcfsSettingList) { + LocalDateTime startTime = fcfsSettingDto.getStartTime(); + + if (now.isEqual(startTime.toLocalDate())) { + return fcfsSettingDto.getRound(); + } + } + return null; + } + } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/QuizManager.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/QuizManager.java index 239b095c..3eacf017 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/QuizManager.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/QuizManager.java @@ -73,8 +73,7 @@ public String getHint(){ if (fcfsSettingDto != null) { LocalDateTime endTime = fcfsSettingDto.getEndTime(); - // localDate가 startDate의 하루 다음날과 같은지 확인 - if (endTime.isBefore(now)) { + if (now.isBefore(endTime)) { return quizList.get(i).getHint(); } } diff --git a/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java index 727f3f82..08631629 100644 --- a/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java +++ b/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java @@ -1,6 +1,7 @@ package com.softeer.backend.fo_domain.mainpage.dto; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.time.LocalDateTime; @@ -26,6 +27,9 @@ public class MainPageEventInfoResponseDto { private String fcfsHint; + @JsonProperty("isFcfsAvailable") + private boolean isFcfsAvailable; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime fcfsStartTime; + private LocalDateTime nextFcfsStartTime; } diff --git a/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java b/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java index 62cb4b93..2729a3eb 100644 --- a/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java +++ b/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java @@ -36,7 +36,8 @@ @RequiredArgsConstructor public class MainPageService { private final DateTimeFormatter eventTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd"); - private final DateTimeFormatter fcfsTimeFormatter = DateTimeFormatter.ofPattern("a h", Locale.KOREAN); + private final DateTimeFormatter fcfsTimeFormatter = DateTimeFormatter.ofPattern("a h시", Locale.KOREAN); + private final DateTimeFormatter fcfsTimeMinFormatter = DateTimeFormatter.ofPattern("a h시 m분", Locale.KOREAN); private final DecimalFormat decimalFormat = new DecimalFormat("#,###"); private final EventLockRedisUtil eventLockRedisUtil; @@ -104,20 +105,28 @@ public MainPageEventInfoResponseDto getEventPageInfo() { int remainDrawCount = totalDrawWinner - (int) drawRepository.count(); + String fcfsTime = ""; + if(firstFcfsSetting.getStartTime().getMinute() != 0){ + fcfsTime = firstFcfsSetting.getStartTime().format(fcfsTimeFormatter); + } + else + fcfsTime = firstFcfsSetting.getStartTime().format(fcfsTimeMinFormatter); + return MainPageEventInfoResponseDto.builder() .startDate(drawSettingManager.getStartDate().format(eventTimeFormatter)) .endDate(drawSettingManager.getEndDate().format(eventTimeFormatter)) .fcfsInfo(staticResourceUtil.format(textContentMap.get(StaticTextName.FCFS_INFO.name()), staticResourceUtil.getKoreanDayOfWeek(firstFcfsSetting.getStartTime().getDayOfWeek()), staticResourceUtil.getKoreanDayOfWeek(secondFcfsSetting.getStartTime().getDayOfWeek()), - firstFcfsSetting.getStartTime().format(fcfsTimeFormatter), + fcfsTime, firstFcfsSetting.getWinnerNum())) .totalDrawWinner(staticResourceUtil.format( textContentMap.get(StaticTextName.TOTAL_DRAW_WINNER.name()), decimalFormat.format(totalDrawWinner))) .remainDrawCount(staticResourceUtil.format( textContentMap.get(StaticTextName.REMAIN_DRAW_COUNT.name()), decimalFormat.format(remainDrawCount))) .fcfsHint(quizManager.getHint()) - .fcfsStartTime(fcfsSettingManager.getNextFcfsTime(LocalDateTime.now())) + .isFcfsAvailable(fcfsSettingManager.isFcfsEntryAvailable(LocalDateTime.now())) + .nextFcfsStartTime(fcfsSettingManager.getNextFcfsTime(LocalDateTime.now())) .build(); } diff --git a/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java b/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java index 224a61b5..d230e72b 100644 --- a/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java +++ b/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java @@ -18,7 +18,7 @@ public enum RedisKeyPrefix { DRAW_PARTICIPANT_COUNT_PREFIX("DRAW_PARTICIPANT_COUNT"), // 사이트 방문자 수 - TOTAL_VISITORS_COUNT_PREFIX("TOTAL_VISITORS_COUNT_"); + TOTAL_VISITORS_COUNT_PREFIX("TOTAL_VISITORS_COUNT"); private final String prefix; diff --git a/src/main/java/com/softeer/backend/global/scheduler/DbInsertScheduler.java b/src/main/java/com/softeer/backend/global/scheduler/DbInsertScheduler.java index 91b12163..74abc264 100644 --- a/src/main/java/com/softeer/backend/global/scheduler/DbInsertScheduler.java +++ b/src/main/java/com/softeer/backend/global/scheduler/DbInsertScheduler.java @@ -103,6 +103,7 @@ protected void insertData() { .user(user) .round(round) .code(code) + .winningDate(now.minusDays(1)) .build(); // 코드와 사용자 저장 diff --git a/src/test/java/com/softeer/backend/fo_domain/admin/service/AdminLoginServiceTest.java b/src/test/java/com/softeer/backend/bo_domain/admin/service/AdminLoginServiceTest.java similarity index 98% rename from src/test/java/com/softeer/backend/fo_domain/admin/service/AdminLoginServiceTest.java rename to src/test/java/com/softeer/backend/bo_domain/admin/service/AdminLoginServiceTest.java index c866fe79..d82afd9c 100644 --- a/src/test/java/com/softeer/backend/fo_domain/admin/service/AdminLoginServiceTest.java +++ b/src/test/java/com/softeer/backend/bo_domain/admin/service/AdminLoginServiceTest.java @@ -1,4 +1,4 @@ -package com.softeer.backend.fo_domain.admin.service; +package com.softeer.backend.bo_domain.admin.service; import com.softeer.backend.bo_domain.admin.domain.Admin; import com.softeer.backend.bo_domain.admin.dto.login.AdminLoginRequestDto; diff --git a/src/test/java/com/softeer/backend/fo_domain/admin/service/EventPageServiceTest.java b/src/test/java/com/softeer/backend/bo_domain/admin/service/EventPageServiceTest.java similarity index 98% rename from src/test/java/com/softeer/backend/fo_domain/admin/service/EventPageServiceTest.java rename to src/test/java/com/softeer/backend/bo_domain/admin/service/EventPageServiceTest.java index 13f6d9da..01f2e458 100644 --- a/src/test/java/com/softeer/backend/fo_domain/admin/service/EventPageServiceTest.java +++ b/src/test/java/com/softeer/backend/bo_domain/admin/service/EventPageServiceTest.java @@ -1,4 +1,4 @@ -package com.softeer.backend.fo_domain.admin.service; +package com.softeer.backend.bo_domain.admin.service; import com.softeer.backend.bo_domain.admin.dto.event.DrawEventTimeRequestDto; import com.softeer.backend.bo_domain.admin.dto.event.EventPageResponseDto; diff --git a/src/test/java/com/softeer/backend/fo_domain/admin/service/IndicatorPageServiceTest.java b/src/test/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageServiceTest.java similarity index 98% rename from src/test/java/com/softeer/backend/fo_domain/admin/service/IndicatorPageServiceTest.java rename to src/test/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageServiceTest.java index b18a671e..df4a4aa0 100644 --- a/src/test/java/com/softeer/backend/fo_domain/admin/service/IndicatorPageServiceTest.java +++ b/src/test/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageServiceTest.java @@ -1,4 +1,4 @@ -package com.softeer.backend.fo_domain.admin.service; +package com.softeer.backend.bo_domain.admin.service; import com.softeer.backend.bo_domain.admin.dto.indicator.EventIndicatorResponseDto; import com.softeer.backend.bo_domain.admin.service.IndicatorPageService; diff --git a/src/test/java/com/softeer/backend/fo_domain/admin/service/WinnerPageServiceTest.java b/src/test/java/com/softeer/backend/bo_domain/admin/service/WinnerPageServiceTest.java similarity index 99% rename from src/test/java/com/softeer/backend/fo_domain/admin/service/WinnerPageServiceTest.java rename to src/test/java/com/softeer/backend/bo_domain/admin/service/WinnerPageServiceTest.java index feccf05b..20e8a085 100644 --- a/src/test/java/com/softeer/backend/fo_domain/admin/service/WinnerPageServiceTest.java +++ b/src/test/java/com/softeer/backend/bo_domain/admin/service/WinnerPageServiceTest.java @@ -1,4 +1,4 @@ -package com.softeer.backend.fo_domain.admin.service; +package com.softeer.backend.bo_domain.admin.service; import com.softeer.backend.bo_domain.admin.dto.winner.*; import com.softeer.backend.bo_domain.admin.service.WinnerPageService; diff --git a/src/test/java/com/softeer/backend/fo_domain/mainpage/service/MainPageServiceTest.java b/src/test/java/com/softeer/backend/fo_domain/mainpage/service/MainPageServiceTest.java index 6e63d4ab..bffa4709 100644 --- a/src/test/java/com/softeer/backend/fo_domain/mainpage/service/MainPageServiceTest.java +++ b/src/test/java/com/softeer/backend/fo_domain/mainpage/service/MainPageServiceTest.java @@ -139,7 +139,7 @@ void testGetEventPageInfo() { assertThat(response.getStartDate()).isEqualTo("2024.08.01"); assertThat(response.getEndDate()).isEqualTo("2024.08.31"); assertThat(response.getFcfsHint()).isEqualTo("퀴즈 힌트"); - assertThat(response.getFcfsStartTime()).isEqualTo(LocalDateTime.of(2024, 8, 22, 11, 0)); + assertThat(response.getNextFcfsStartTime()).isEqualTo(LocalDateTime.of(2024, 8, 22, 11, 0)); } @Test