diff --git a/src/main/java/com/softeer/backend/bo_domain/admin/controller/AdminLoginController.java b/src/main/java/com/softeer/backend/bo_domain/admin/controller/AdminLoginController.java index 6ac11892..55827d18 100644 --- a/src/main/java/com/softeer/backend/bo_domain/admin/controller/AdminLoginController.java +++ b/src/main/java/com/softeer/backend/bo_domain/admin/controller/AdminLoginController.java @@ -6,6 +6,7 @@ import com.softeer.backend.global.annotation.AuthInfo; import com.softeer.backend.global.common.dto.JwtTokenResponseDto; import com.softeer.backend.global.common.response.ResponseDto; +import io.swagger.v3.oas.annotations.Parameter; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; @@ -28,7 +29,7 @@ ResponseDto handleLogin(@Valid @RequestBody AdminLoginReque } @PostMapping("/logout") - ResponseDto handleLogout(@AuthInfo Integer adminId) { + ResponseDto handleLogout(@Parameter(hidden = true) @AuthInfo Integer adminId) { adminLoginService.handleLogout(adminId); return ResponseDto.onSuccess(); diff --git a/src/main/java/com/softeer/backend/bo_domain/admin/dto/indicator/EventIndicatorResponseDto.java b/src/main/java/com/softeer/backend/bo_domain/admin/dto/indicator/EventIndicatorResponseDto.java index 796f6e9e..bed14e3c 100644 --- a/src/main/java/com/softeer/backend/bo_domain/admin/dto/indicator/EventIndicatorResponseDto.java +++ b/src/main/java/com/softeer/backend/bo_domain/admin/dto/indicator/EventIndicatorResponseDto.java @@ -6,6 +6,7 @@ import com.softeer.backend.bo_domain.admin.serializer.PercentageSerializer; import com.softeer.backend.bo_domain.admin.serializer.PhoneNumberSerializer; import com.softeer.backend.bo_domain.eventparticipation.domain.EventParticipation; +import com.softeer.backend.fo_domain.draw.service.DrawSettingManager; import lombok.*; import java.time.LocalDate; @@ -48,9 +49,9 @@ public static class VisitorNum { private int visitorNum; } - public static EventIndicatorResponseDto of(List eventParticipationList) { - LocalDate startDate = eventParticipationList.get(0).getEventDate(); - LocalDate endDate = eventParticipationList.get(eventParticipationList.size() - 1).getEventDate(); + public static EventIndicatorResponseDto of(List eventParticipationList, DrawSettingManager drawSettingManager) { + LocalDate startDate = drawSettingManager.getStartDate(); + LocalDate endDate = drawSettingManager.getEndDate(); int totalVisitorCount = eventParticipationList.stream() .mapToInt(EventParticipation::getVisitorCount) @@ -64,8 +65,8 @@ public static EventIndicatorResponseDto of(List eventPartici .mapToInt(EventParticipation::getDrawParticipantCount) .sum(); - double fcfsParticipantRate = (double) totalFcfsParticipantCount / (double) totalVisitorCount; - double drawParticipantRate = (double) totalDrawParticipantCount / (double) totalVisitorCount; + double fcfsParticipantRate = totalVisitorCount == 0 ? 0 : (double) totalFcfsParticipantCount / (double) totalVisitorCount; + double drawParticipantRate = totalVisitorCount == 0 ? 0 : (double) totalDrawParticipantCount / (double) totalVisitorCount; List visitorNumList = eventParticipationList.stream() .map((eventParticipation) -> diff --git a/src/main/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageService.java b/src/main/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageService.java index 29f3669e..2d1910ac 100644 --- a/src/main/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageService.java +++ b/src/main/java/com/softeer/backend/bo_domain/admin/service/IndicatorPageService.java @@ -26,7 +26,7 @@ public EventIndicatorResponseDto getEventIndicator() { drawSettingManager.getStartDate(), drawSettingManager.getEndDate() ); - return EventIndicatorResponseDto.of(eventParticipationList); + return EventIndicatorResponseDto.of(eventParticipationList, drawSettingManager); } } diff --git a/src/main/java/com/softeer/backend/bo_domain/eventparticipation/domain/EventParticipation.java b/src/main/java/com/softeer/backend/bo_domain/eventparticipation/domain/EventParticipation.java index 5ae8962e..5b3a0f8d 100644 --- a/src/main/java/com/softeer/backend/bo_domain/eventparticipation/domain/EventParticipation.java +++ b/src/main/java/com/softeer/backend/bo_domain/eventparticipation/domain/EventParticipation.java @@ -33,15 +33,4 @@ public class EventParticipation { @Column(name = "event_date", nullable = false) private LocalDate eventDate; - public void addTotalVisitorsCount(int totalVisitorsCount) { - this.visitorCount += totalVisitorsCount; - } - - public void addFcfsParticipantCount(int fcfsParticipantCount) { - this.fcfsParticipantCount += fcfsParticipantCount; - } - - public void addDrawParticipantCount(int drawParticipantCount) { - this.drawParticipantCount += drawParticipantCount; - } } diff --git a/src/main/java/com/softeer/backend/fo_domain/comment/controller/CommentController.java b/src/main/java/com/softeer/backend/fo_domain/comment/controller/CommentController.java index 3342444f..9939862c 100644 --- a/src/main/java/com/softeer/backend/fo_domain/comment/controller/CommentController.java +++ b/src/main/java/com/softeer/backend/fo_domain/comment/controller/CommentController.java @@ -6,6 +6,7 @@ import com.softeer.backend.global.annotation.AuthInfo; import com.softeer.backend.global.common.code.status.ErrorStatus; import com.softeer.backend.global.common.response.ResponseDto; +import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.BindingResult; @@ -20,7 +21,7 @@ public class CommentController { @GetMapping("/comment") ResponseDto getComment(@RequestParam(name = "cursor", required = false) Integer cursor, - @AuthInfo Integer userId) { + @Parameter(hidden = true) @AuthInfo Integer userId) { if (cursor == null) { cursor = Integer.MAX_VALUE; } @@ -35,7 +36,7 @@ ResponseDto getComment(@RequestParam(name = "cursor", requi @PostMapping("/comment") ResponseDto saveComment(@RequestParam(name = "commentType") Integer commentType, - @AuthInfo Integer userId) { + @Parameter(hidden = true) @AuthInfo Integer userId) { if(commentType == null || commentType<1 || commentType > 5){ diff --git a/src/main/java/com/softeer/backend/fo_domain/draw/controller/DrawController.java b/src/main/java/com/softeer/backend/fo_domain/draw/controller/DrawController.java index 4802d271..c22be49b 100644 --- a/src/main/java/com/softeer/backend/fo_domain/draw/controller/DrawController.java +++ b/src/main/java/com/softeer/backend/fo_domain/draw/controller/DrawController.java @@ -5,6 +5,7 @@ import com.softeer.backend.fo_domain.draw.service.DrawService; import com.softeer.backend.global.annotation.AuthInfo; import com.softeer.backend.global.common.response.ResponseDto; +import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -16,7 +17,8 @@ public class DrawController { private final DrawService drawService; @GetMapping("/event/draw") - public ResponseDto getDrawMainPageInfo(@AuthInfo Integer userId) { + public ResponseDto getDrawMainPageInfo(@Parameter(hidden = true) @AuthInfo Integer userId) { + return drawService.getDrawMainPageInfo(userId); } 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 13255ebb..da947d08 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,30 +1,68 @@ package com.softeer.backend.fo_domain.fcfs.controller; -import com.softeer.backend.fo_domain.fcfs.dto.FcfsResponseDto; -import com.softeer.backend.fo_domain.fcfs.dto.FcfsSuccessResponseDto; +import com.softeer.backend.fo_domain.fcfs.dto.FcfsPageResponseDto; +import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResponseDto; 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 org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; -@RestController +@Controller @RequiredArgsConstructor +@RequestMapping("/fcfs") @Tag(name = "Fcfs Controller", description = "선착순 API") public class FcfsController { private final FcfsService fcfsService; -// @PostMapping("/fcfs") -// public ResponseDto handleFCFS(@Parameter(hidden = true) @AuthInfo Integer userId) { -// FcfsResponseDto fcfsResponse = fcfsService.handleFcfsEvent(userId); -// -// if (fcfsResponse instanceof FcfsSuccessResponseDto) -// return ResponseDto.onSuccess(fcfsResponse); + @GetMapping + @ResponseBody + public ResponseDto getFcfsPage(@Parameter(hidden = true) HttpServletRequest request) { + + int round = (Integer) request.getAttribute("round"); + + FcfsPageResponseDto fcfsPageResponseDto = fcfsService.getFcfsPage(round); + + return ResponseDto.onSuccess(fcfsPageResponseDto); + } + + @GetMapping("/tutorial") + @ResponseBody + public ResponseDto getFcfsTutorialPage() { + + FcfsPageResponseDto fcfsPageResponseDto = fcfsService.getFcfsTutorialPage(); + + return ResponseDto.onSuccess(fcfsPageResponseDto); + } + + @PostMapping + public String handleFcfs(@Parameter(hidden = true) HttpServletRequest request, + @Parameter(hidden = true) @AuthInfo Integer userId, + @RequestParam(value = "answer") String answer, + @Parameter(hidden = true) RedirectAttributes redirectAttributes) { + + int round = (Integer) request.getAttribute("round"); + +// boolean isFcfsWinner = fcfsService.handleFcfsEvent(userId, round, answer); // -// return ResponseDto.onSuccess(fcfsResponse); -// } +// // 리다이렉트 시 쿼리 파라미터를 추가하여 정보 전달 +// redirectAttributes.addAttribute("fcfsWin", isFcfsWinner); + + // GET 요청으로 리다이렉트 + return "redirect:/fcfs/result"; + } + + @GetMapping("/result") + @ResponseBody + public ResponseDto getFcfsResult(@RequestParam("fcfsWin") Boolean fcfsWin){ + FcfsResponseDto fcfsResponseDto = fcfsService.getFcfsResult(fcfsWin); + + return ResponseDto.onSuccess(fcfsResponseDto); + } } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Quiz.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Quiz.java new file mode 100644 index 00000000..9678667a --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/domain/Quiz.java @@ -0,0 +1,42 @@ +package com.softeer.backend.fo_domain.fcfs.domain; + +import com.softeer.backend.fo_domain.user.domain.User; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@Table(name = "quiz") +public class Quiz { + + @Id + @Column(name = "quiz_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "hint", nullable = false) + private String hint; + + @Column(name = "answer_word", nullable = false) + private String answerWord; + + @Column(name = "answer_sentence", nullable = false) + private String answerSentence; + + @Column(name = "start_index", nullable = false) + private int startIndex; + + @Column(name = "end_index", nullable = false) + private int endIndex; + +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsFailResponseDtoDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsFailResponseDtoDto.java deleted file mode 100644 index 9e7cc2e6..00000000 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsFailResponseDtoDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.softeer.backend.fo_domain.fcfs.dto; - -import lombok.*; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -@AllArgsConstructor(access = AccessLevel.PUBLIC) -@Builder -@Getter -public class FcfsFailResponseDtoDto implements FcfsResponseDto { - private int a; -} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsPageResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsPageResponseDto.java new file mode 100644 index 00000000..a0898589 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsPageResponseDto.java @@ -0,0 +1,22 @@ +package com.softeer.backend.fo_domain.fcfs.dto; + +import lombok.*; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@Builder +@Getter +@Setter +public class FcfsPageResponseDto { + + private String answerWord; + + private String answerSentence; + + private int startIndex; + + private int endIndex; + + private String quizDescription; + +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsResponseDto.java deleted file mode 100644 index 7d9b2c09..00000000 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsResponseDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.softeer.backend.fo_domain.fcfs.dto; - -public interface FcfsResponseDto { -} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsSuccessResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsSuccessResponseDto.java deleted file mode 100644 index 39e379b3..00000000 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/FcfsSuccessResponseDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.softeer.backend.fo_domain.fcfs.dto; - -import lombok.*; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -@AllArgsConstructor(access = AccessLevel.PUBLIC) -@Builder -@Getter -public class FcfsSuccessResponseDto implements FcfsResponseDto { - private int a; -} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/QuizDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/QuizDto.java new file mode 100644 index 00000000..b524f3d2 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/QuizDto.java @@ -0,0 +1,23 @@ +package com.softeer.backend.fo_domain.fcfs.dto; + +import jakarta.persistence.Column; +import lombok.*; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@Builder +@Getter +@Setter +public class QuizDto { + + private String hint; + + private String answerWord; + + private String answerSentence; + + private int startIndex; + + private int endIndex; + +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsFailResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsFailResponseDto.java new file mode 100644 index 00000000..89a126b8 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsFailResponseDto.java @@ -0,0 +1,16 @@ +package com.softeer.backend.fo_domain.fcfs.dto.result; + +import lombok.*; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@Builder +@Getter +public class FcfsFailResponseDto implements FcfsResponseDto { + + private String title; + + private String subTitle; + + private String caution; +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsResponseDto.java new file mode 100644 index 00000000..253298f4 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsResponseDto.java @@ -0,0 +1,4 @@ +package com.softeer.backend.fo_domain.fcfs.dto.result; + +public interface FcfsResponseDto { +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResponseDto.java new file mode 100644 index 00000000..c90e7804 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResponseDto.java @@ -0,0 +1,25 @@ +package com.softeer.backend.fo_domain.fcfs.dto.result; + +import lombok.*; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@Builder +@Getter +public class FcfsSuccessResponseDto implements FcfsResponseDto { + + private String title; + + private String subTitle; + + private String qrCode; + + private String codeWord; + + private String fcfsCode; + + private String expirationDate; + + private String caution; + +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/exception/FcfsException.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/exception/FcfsException.java new file mode 100644 index 00000000..c9161701 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/exception/FcfsException.java @@ -0,0 +1,11 @@ +package com.softeer.backend.fo_domain.fcfs.exception; + +import com.softeer.backend.global.common.code.BaseErrorCode; +import com.softeer.backend.global.common.exception.GeneralException; + +public class FcfsException extends GeneralException { + + public FcfsException(BaseErrorCode code) { + super(code); + } +} diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/interceptor/FcfsTimeCheckInterceptor.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/interceptor/FcfsTimeCheckInterceptor.java new file mode 100644 index 00000000..e4e4035a --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/interceptor/FcfsTimeCheckInterceptor.java @@ -0,0 +1,39 @@ +package com.softeer.backend.fo_domain.fcfs.interceptor; + +import com.softeer.backend.fo_domain.fcfs.exception.FcfsException; +import com.softeer.backend.fo_domain.fcfs.service.FcfsSettingManager; +import com.softeer.backend.global.common.code.status.ErrorStatus; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.time.LocalDateTime; + +@Slf4j +@Component +@RequiredArgsConstructor +public class FcfsTimeCheckInterceptor implements HandlerInterceptor { + + private final FcfsSettingManager fcfsSettingManager; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + LocalDateTime now = LocalDateTime.now(); + + if(!fcfsSettingManager.isFcfsEntryAvailable(now)){ + + log.error("Cannot access the FCFS event"); + throw new FcfsException(ErrorStatus._BAD_REQUEST); + } + + if(request.getMethod().equals("GET")){ + int round = fcfsSettingManager.getFcfsRound(now); + request.setAttribute("round", round); + } + + return true; + } +} \ No newline at end of file diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsSettingRepository.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsSettingRepository.java index c4f518f6..26b131f2 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsSettingRepository.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/FcfsSettingRepository.java @@ -9,6 +9,5 @@ @Repository public interface FcfsSettingRepository extends JpaRepository { - Optional findByRound(int round); } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/QuizRepository.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/QuizRepository.java new file mode 100644 index 00000000..7ab098f4 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/repository/QuizRepository.java @@ -0,0 +1,7 @@ +package com.softeer.backend.fo_domain.fcfs.repository; + +import com.softeer.backend.fo_domain.fcfs.domain.Quiz; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface QuizRepository extends JpaRepository { +} 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 b8b501fe..564d9c23 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,9 +1,11 @@ package com.softeer.backend.fo_domain.fcfs.service; -import com.softeer.backend.fo_domain.fcfs.dto.FcfsFailResponseDtoDto; +import com.softeer.backend.fo_domain.fcfs.dto.*; +import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsFailResponseDto; +import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResponseDto; import com.softeer.backend.fo_domain.fcfs.repository.FcfsRepository; import com.softeer.backend.fo_domain.user.repository.UserRepository; -import com.softeer.backend.global.common.constant.RedisKeyPrefix; +import com.softeer.backend.global.staticresources.util.StaticResourcesUtil; import com.softeer.backend.global.util.EventLockRedisUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -21,12 +23,39 @@ public class FcfsService { private final FcfsRepository fcfsRepository; private final EventLockRedisUtil eventLockRedisUtil; private final UserRepository userRepository; + private final StaticResourcesUtil staticResourcesUtil; + + + public FcfsPageResponseDto getFcfsPage(int round) { + + QuizDto quiz = fcfsSettingManager.getQuiz(round); + + return FcfsPageResponseDto.builder() + .answerWord(quiz.getAnswerWord()) + .answerSentence(quiz.getAnswerSentence()) + .startIndex(quiz.getStartIndex()) + .endIndex(quiz.getEndIndex()) + .quizDescription(staticResourcesUtil.getData("FCFS_QUIZ_DESCRIPTION")) + .build(); + } + + public FcfsPageResponseDto getFcfsTutorialPage() { + QuizDto tutorialQuiz = fcfsSettingManager.getTutorialQuiz(); + + return FcfsPageResponseDto.builder() + .answerWord(tutorialQuiz.getAnswerWord()) + .answerSentence(tutorialQuiz.getAnswerSentence()) + .startIndex(tutorialQuiz.getStartIndex()) + .endIndex(tutorialQuiz.getEndIndex()) + .quizDescription(staticResourcesUtil.getData("FCFS_QUIZ_DESCRIPTION")) + .build(); + } /** * 1. 선착순 당첨자가 아직 다 결정되지 않았으면, 선착순 당첨 응답 생성 및 반환 * 2. 선착순 당첨자가 다 결정됐다면, Redisson lock을 사용하지 않고 Redis에 저장된 선착순 이벤트 참여자 수를 1명씩 더한다. */ -// public FcfsResponseDto handleFcfsEvent(int userId) { +// public FcfsResponseDto handleFcfsEvent(int userId, int round, String answer) { // if (fcfsSettingManager.isFcfsClosed()) // return countFcfsParticipant(fcfsSettingManager.getRound()); // @@ -68,10 +97,24 @@ public class FcfsService { // return new FcfsFailResponseDtoDto(1); // } - private FcfsFailResponseDtoDto countFcfsParticipant(int round) { - eventLockRedisUtil.incrementData(RedisKeyPrefix.FCFS_PARTICIPANT_COUNT_PREFIX.getPrefix() + round); + public FcfsResponseDto getFcfsResult(boolean fcfsWin){ +// if(fcfsWin){ +// return FcfsSuccessResponseDto.builder() +// .title(staticResourcesUtil.getData("FCFS_WINNER_TITLE")) +// .subTitle(staticResourcesUtil.getData("FCFS_WINNER_SUBTITLE")) +// .qrCode(staticResourcesUtil.getData("barcode_image")) +// .codeWord(staticResourcesUtil.getData("FCFS_WINNER_CODE_WORD")) +// .fcfsCode() +// .expirationDate(staticResourcesUtil.getData("FCFS_WINNER_EXPIRY_DATE")) +// .caution(staticResourcesUtil.getData("FCFS_WINNER_CAUTION")) +// .build(); +// } - return new FcfsFailResponseDtoDto(1); + return FcfsFailResponseDto.builder() + .title(staticResourcesUtil.getData("FCFS_LOSER_TITLE")) + .subTitle(staticResourcesUtil.getData("FCFS_LOSER_SUBTITLE")) + .caution(staticResourcesUtil.getData("FCFS_LOSER_CAUTION")) + .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 eaab4702..7d7e08c8 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 @@ -2,16 +2,21 @@ import com.softeer.backend.bo_domain.eventparticipation.repository.EventParticipationRepository; import com.softeer.backend.fo_domain.fcfs.domain.FcfsSetting; +import com.softeer.backend.fo_domain.fcfs.domain.Quiz; import com.softeer.backend.fo_domain.fcfs.dto.FcfsSettingDto; +import com.softeer.backend.fo_domain.fcfs.dto.QuizDto; import com.softeer.backend.fo_domain.fcfs.repository.FcfsSettingRepository; +import com.softeer.backend.fo_domain.fcfs.repository.QuizRepository; import com.softeer.backend.global.util.EventLockRedisUtil; import jakarta.annotation.PostConstruct; import lombok.*; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Sort; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Component; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledFuture; @@ -25,15 +30,19 @@ @RequiredArgsConstructor public class FcfsSettingManager { - private List fcfsSettingList; - - @Setter - private boolean isFcfsClosed = false; - private final FcfsSettingRepository fcfsSettingRepository; private final ThreadPoolTaskScheduler taskScheduler; private final EventLockRedisUtil eventLockRedisUtil; private final EventParticipationRepository eventParticipationRepository; + private final QuizRepository quizRepository; + + private List fcfsSettingList; + private QuizDto tutorialQuiz; + private List quizList; + + + @Setter + private boolean isFcfsClosed = false; @PostConstruct @@ -66,13 +75,36 @@ public void loadInitialData() { .build()); }); + List quizs = quizRepository.findAll(Sort.by(Sort.Direction.ASC, "id")); + quizList = new ArrayList<>(4); + + for (int i = 0; i < 4; i++) { + quizList.add(null); // 인덱스 0부터 3까지 빈 슬롯을 추가 + } + + quizs.forEach((quiz) -> { + + QuizDto quizDto = QuizDto.builder() + .hint(quiz.getHint()) + .answerWord(quiz.getAnswerWord()) + .answerSentence(quiz.getAnswerSentence()) + .startIndex(quiz.getStartIndex()) + .endIndex(quiz.getEndIndex()) + .build(); + + if(quiz.getHint().equals("튜토리얼")) + tutorialQuiz = quizDto; + else + quizList.add(quizDto); + }); + } public void setFcfsTime(List fcfsSettingList) { fcfsSettingList .forEach((fcfsSetting) -> { - FcfsSettingDto fcfsSettingDto = this.fcfsSettingList.get(fcfsSetting.getRound()); + FcfsSettingDto fcfsSettingDto = this.fcfsSettingList.get(fcfsSetting.getRound()-1); fcfsSettingDto.setStartTime(fcfsSetting.getStartTime()); fcfsSettingDto.setEndTime(fcfsSetting.getEndTime()); }); @@ -99,5 +131,62 @@ public int getRoundForScheduler(LocalDate localDate) { return -1; // 해당하는 데이터가 없는 경우 } + public int getFcfsWinnerNum(){ + return fcfsSettingList.get(0).getWinnerNum(); + } + + public String getHint(){ + + LocalDateTime now = LocalDateTime.now(); + + for (int i=0; i eventInfoList; @Getter 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 352d2317..0fcb2f4d 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 @@ -1,6 +1,7 @@ package com.softeer.backend.fo_domain.mainpage.service; import com.softeer.backend.fo_domain.draw.service.DrawSettingManager; +import com.softeer.backend.fo_domain.fcfs.service.FcfsSettingManager; import com.softeer.backend.fo_domain.mainpage.dto.MainPageCarResponseDto; import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventResponseDto; import com.softeer.backend.global.common.constant.RedisKeyPrefix; @@ -21,6 +22,7 @@ public class MainPageService { private final EventLockRedisUtil eventLockRedisUtil; private final StaticResourcesUtil staticResourcesUtil; + private final FcfsSettingManager fcfsSettingManager; private final DrawSettingManager drawSettingManager; public MainPageEventResponseDto getEventPage(){ @@ -49,6 +51,7 @@ public MainPageEventResponseDto getEventPage(){ .fcfsInfo(staticResourcesUtil.getData("FCFS_INFO")) .totalDrawWinner(staticResourcesUtil.getData("TOTAL_DRAW_WINNER")) .remainDrawCount(staticResourcesUtil.getData("REMAIN_DRAW_COUNT")) + .fcfsHint(fcfsSettingManager.getHint()) .eventInfoList(Arrays.asList(fcfsInfo, drawInfo)) .build(); diff --git a/src/main/java/com/softeer/backend/fo_domain/share/controller/ShareController.java b/src/main/java/com/softeer/backend/fo_domain/share/controller/ShareController.java index b3e5f63e..c2fc474a 100644 --- a/src/main/java/com/softeer/backend/fo_domain/share/controller/ShareController.java +++ b/src/main/java/com/softeer/backend/fo_domain/share/controller/ShareController.java @@ -4,6 +4,7 @@ import com.softeer.backend.fo_domain.share.service.ShareUrlInfoService; import com.softeer.backend.global.annotation.AuthInfo; import com.softeer.backend.global.common.response.ResponseDto; +import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -14,7 +15,7 @@ public class ShareController { private final ShareUrlInfoService shareUrlInfoService; @GetMapping("/share-shorten-url") - public ResponseDto getShortenShareUrl(@AuthInfo Integer userId) { + public ResponseDto getShortenShareUrl(@Parameter(hidden = true) @AuthInfo Integer userId) { return shareUrlInfoService.getShortenShareUrl(userId); } } diff --git a/src/main/java/com/softeer/backend/global/common/exception/ExceptionAdvice.java b/src/main/java/com/softeer/backend/global/common/exception/ExceptionAdvice.java index f0ebd1a2..15a57671 100644 --- a/src/main/java/com/softeer/backend/global/common/exception/ExceptionAdvice.java +++ b/src/main/java/com/softeer/backend/global/common/exception/ExceptionAdvice.java @@ -1,9 +1,7 @@ package com.softeer.backend.global.common.exception; -import com.softeer.backend.fo_domain.fcfs.dto.FcfsFailResponseDtoDto; import com.softeer.backend.global.common.code.status.ErrorStatus; import com.softeer.backend.global.common.response.ResponseDto; -import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DataAccessException; @@ -139,8 +137,8 @@ private ResponseEntity handleEventLockExceptionInternal(EventLockExcepti ResponseDto body = null; - if (redissonKeyName.contains("FCFS")) - body = ResponseDto.onSuccess(new FcfsFailResponseDtoDto(1)); +// if (redissonKeyName.contains("FCFS")) +// body = ResponseDto.onSuccess(new FcfsFailResponseDtoDto(1)); //TODO // DRAW 관련 예외일 경우, body 구성하는 코드 필요 diff --git a/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java b/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java index 0420fecc..efe1d7a3 100644 --- a/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java +++ b/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java @@ -1,6 +1,7 @@ package com.softeer.backend.global.config.web; import com.fasterxml.jackson.databind.ObjectMapper; +import com.softeer.backend.fo_domain.fcfs.interceptor.FcfsTimeCheckInterceptor; import com.softeer.backend.global.annotation.argumentresolver.AuthInfoArgumentResolver; import com.softeer.backend.global.config.properties.JwtProperties; import com.softeer.backend.global.filter.ExceptionHandlingFilter; @@ -14,6 +15,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @@ -30,6 +32,8 @@ public class WebMvcConfig implements WebMvcConfigurer { private final StringRedisUtil stringRedisUtil; private final JwtProperties jwtProperties; + private final FcfsTimeCheckInterceptor fcfsTimeCheckInterceptor; + /** * AuthInfo 애노테이션에 대한 Argument Resolver 등록 * @@ -39,6 +43,12 @@ public void addArgumentResolvers(List resolvers) resolvers.add(new AuthInfoArgumentResolver()); } + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(fcfsTimeCheckInterceptor) + .addPathPatterns("/fcfs"); + } + /** * CORS 설정 메서드 * diff --git a/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java b/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java index eb586782..36f4a55f 100644 --- a/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java +++ b/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java @@ -98,7 +98,24 @@ public enum StaticText { // 공유 url BASE_URL("https://softeer.shop/"), - NON_USER_SHARE_URL("https://softeer.site"); + NON_USER_SHARE_URL("https://softeer.site"), + + // 선착순 + FCFS_QUIZ_DESCRIPTION("선착순 %s명에게 The new IONIQ 5 24시간 무료 렌트권 증정"), + + FCFS_WINNER_TITLE("선착순 %s명 안에 들었어요!"), + FCFS_WINNER_SUBTITLE("[ 더뉴 아이오닉 5 24시간 렌트 이용권 + 신차 구입 10% 할인권 ]"), + FCFS_WINNER_CODE_WORD("코드"), + FCFS_WINNER_EXPIRY_DATE("사용기한 : %s년 %s ~ %s"), + FCFS_WINNER_CAUTION("본 이벤트는 (주)쏘카와 함께하며, 쏘카 회원가입 및 로그인 후 이용 가능합니다.\n" + + "이벤트 참여를 위해 쏘카 어플리케이션에서 추가적인 절차가 요구될 수 있습니다.\n" + + "이벤트 경품 수령을 위해 등록된 전화번호로 영업일 기준 3~5일 내 안내가 진행될 예정입니다."), + + FCFS_LOSER_TITLE("다음 주에 다시 도전해보세요"), + FCFS_LOSER_SUBTITLE("아쉽게도 선착순 순위에 들지 못했어요"), + FCFS_LOSER_CAUTION("본 이벤트는 (주)쏘카와 함께하며, 쏘카 회원가입 및 로그인 후 이용 가능합니다.\n" + + "이벤트 참여를 위해 쏘카 어플리케이션에서 추가적인 절차가 요구될 수 있습니다."); + private final String text; diff --git a/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java b/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java index e5738de7..8dfd5ace 100644 --- a/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java +++ b/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java @@ -28,6 +28,7 @@ public class StaticResourcesUtil { private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("a h", Locale.KOREAN); private final DecimalFormat decimalFormat = new DecimalFormat("#,###"); + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M월 d일"); private final StaticResourcesRepository staticResourcesRepository; private final DrawSettingManager drawSettingManager; @@ -74,6 +75,12 @@ public void loadInitialData() { return enumValue.format(decimalFormat.format(totalDrawWinner)); case REMAIN_DRAW_COUNT: return enumValue.format(decimalFormat.format(remainDrawCount)); + case FCFS_QUIZ_DESCRIPTION, FCFS_WINNER_TITLE: + return enumValue.format(fcfsSettingManager.getFcfsWinnerNum()); + case FCFS_WINNER_EXPIRY_DATE: + return enumValue.format(firstFcfsSetting.getStartTime().getYear(), + firstFcfsSetting.getStartTime().format(dateFormatter), + drawSettingManager.getEndDate().plusDays(14).format(dateFormatter)); default: return enumValue.getText();