From a1356ce9bf14efb31a921b7f383a1e9408317010 Mon Sep 17 00:00:00 2001 From: Youth <109585620+Youthhing@users.noreply.github.com> Date: Tue, 28 May 2024 18:21:12 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Chore:=20yaml=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85=20=EA=B3=BC=EC=A0=95=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Chore: update code-deploy-app-name * Chore: set overwrite * Chore: 배포 스크립트 분기 로그 추가 * Chore: 브랜치 확인을 위한 경로 이동 스크립트 추가 * Chore: 작업 디렉토리 신뢰를 위한 git 설정 * Chore: jar파일 경로 구체화 * Chore: jar파일 생성 전 build를 선행 작업으로 추가 * Chore: 정상 build 후 JAR파일 이름을 변경하는 방식으로 수정 * Chore: test server jdbc url 수정 * Chore: test server jdbc url 수정 * Chore: Github action에 키를 주입하는 방식 변경 * Chore: application.yml 환경 변수 세팅 단계 추가 * Chore: application.yml 환경 변수 세팅 단계 추가 --- .github/workflows/deploy.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8dcc1c5d..cb5513c0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,7 +10,7 @@ env: CODE_DEPLOY_APP_NAME: cotato-deploy DEPLOYMENT_GROUP_NAME: cotato-deploy-group RESOURCE_PATH: ./src/main/resources/application-prod.yml - BASE_RESOURCE_PATH: ./src/main/resource/application.yml + BASE_RESOURCE_PATH: ./src/main/resources/application.yml jobs: build: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eb886793..83843098 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ env: CODE_DEPLOY_APP_NAME: cotato-deploy DEPLOYMENT_GROUP_NAME: cotato-deploy-group-test RESOURCE_PATH: ./src/main/resources/application-stage.yml - BASE_RESOURCE_PATH: ./src/main/resource/application.yml + BASE_RESOURCE_PATH: ./src/main/resources/application.yml jobs: build: From 2a5c59cd163f27652604f978a86bec15177e0cdf Mon Sep 17 00:00:00 2001 From: Youth <109585620+Youthhing@users.noreply.github.com> Date: Thu, 30 May 2024 17:29:31 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Feature:=20=EA=B5=90=EC=9C=A1=20=EA=B2=B0?= =?UTF-8?q?=EC=8A=B9=EC=A7=84=EC=B6=9C=EC=9E=90,=20=EC=9A=B0=EC=8A=B9?= =?UTF-8?q?=EC=9E=90=20=EA=B3=84=EC=82=B0,=20=EC=9E=AC=EC=A0=84=EC=86=A1?= =?UTF-8?q?=20API=20=EA=B5=AC=ED=98=84=20=20(#19)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Chore: update code-deploy-app-name * Chore: set overwrite * Chore: 배포 스크립트 분기 로그 추가 * Chore: 브랜치 확인을 위한 경로 이동 스크립트 추가 * Chore: 작업 디렉토리 신뢰를 위한 git 설정 * Chore: jar파일 경로 구체화 * Chore: jar파일 생성 전 build를 선행 작업으로 추가 * Chore: 정상 build 후 JAR파일 이름을 변경하는 방식으로 수정 * Chore: test server jdbc url 수정 * Chore: test server jdbc url 수정 * Chore: Github action에 키를 주입하는 방식 변경 * Chore: application.yml 환경 변수 세팅 단계 추가 * Chore: application.yml 환경 변수 세팅 단계 추가 * docs: Update Feature Issue Template * docs: Update Fix Issue Template * docs: PR 템플릿 생성 * docs: PR 템플릿 이모지 제거 * Feature: 교육 결승진출자, 우승자 계산, 재전송 API 구현 (#3) * feat: 교육 결승진출자 계산, 재전송 API 구현 * feat: 교육 결승진출자 계산, 재전송 API 구현 * feat: kingking member, winner 계산 + 전송 API 구현 * feat: 이미 우승자가 계산됐으면 exception 발생 * refactor: 코드 리뷰를 기반으로 코드 수정 * refactor: 컨트롤러, 서비스 메소드 위치 변경 --------- Co-authored-by: GiHun Nam <52378919+gikhoon@users.noreply.github.com> --- .../ISSUE_TEMPLATE/feature-issue-template.md | 22 +++++ .github/ISSUE_TEMPLATE/fix-issue-template.md | 28 +++++++ .github/pull_request_template.md | 9 +++ .../controller/EducationController.java | 24 +++++- .../socket/controller/SocketController.java | 16 ++++ .../socket/dto/EducationResultResponse.java | 13 +++ .../api/socket/dto/QuizStopResponse.java | 6 +- .../cotato/csquiz/common/error/ErrorCode.java | 4 + .../common/websocket/WebSocketHandler.java | 22 +++-- .../repository/KingMemberRepository.java | 2 + .../education/repository/QuizRepository.java | 5 ++ .../repository/WinnerRepository.java | 2 + .../education/service/EducationService.java | 29 ------- .../education/service/KingMemberService.java | 80 ++++++++++++++----- .../education/service/SocketService.java | 25 +++--- 15 files changed, 217 insertions(+), 70 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/feature-issue-template.md create mode 100644 .github/ISSUE_TEMPLATE/fix-issue-template.md create mode 100644 .github/pull_request_template.md create mode 100644 src/main/java/org/cotato/csquiz/api/socket/dto/EducationResultResponse.java diff --git a/.github/ISSUE_TEMPLATE/feature-issue-template.md b/.github/ISSUE_TEMPLATE/feature-issue-template.md new file mode 100644 index 00000000..6aeb303d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-issue-template.md @@ -0,0 +1,22 @@ +--- +name: Feature Issue Template +about: Feature 브랜치 생성 전 작성해주세요 +title: "[Feature]" +labels: '' +assignees: '' + +--- + +## 🪶 추가할 기능 설명 + + +## ✅ 작업 내용 + +- [ ] 구현 내용 1 +- [ ] 구현 내용 2 + +## 스크린샷 (선택) + +## 🔗 참고한 링크 (선택) + +## ETC diff --git a/.github/ISSUE_TEMPLATE/fix-issue-template.md b/.github/ISSUE_TEMPLATE/fix-issue-template.md new file mode 100644 index 00000000..d36e7632 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/fix-issue-template.md @@ -0,0 +1,28 @@ +--- +name: Fix Issue Template +about: Fix 브랜치 생성 전 작성해주세요 +title: "[Fix]" +labels: '' +assignees: '' + +--- + +## ⚠️ 발생한 에러 + + +## 에러가 발생한 상황 + +**Given** : +**When** : +**Then** : + +## ✅ 수정한 내용 + +- [ ] 수정 내용 1 +- [ ] 수정 내용 2 + + + +## 📡 예상 결과 + +## 🔗 참고한 자료 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..323248bb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,9 @@ +## 연관된 이슈 + +이슈링크(url): + + +## ✅ 작업 내용 + + +## 🗣 ️리뷰 요구 사항 \ No newline at end of file diff --git a/src/main/java/org/cotato/csquiz/api/education/controller/EducationController.java b/src/main/java/org/cotato/csquiz/api/education/controller/EducationController.java index edf68c03..83851622 100644 --- a/src/main/java/org/cotato/csquiz/api/education/controller/EducationController.java +++ b/src/main/java/org/cotato/csquiz/api/education/controller/EducationController.java @@ -13,6 +13,7 @@ import org.cotato.csquiz.api.education.dto.WinnerInfoResponse; import org.cotato.csquiz.api.quiz.dto.KingMemberInfo; import org.cotato.csquiz.domain.education.service.EducationService; +import org.cotato.csquiz.domain.education.service.KingMemberService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -30,6 +31,7 @@ public class EducationController { private final EducationService educationService; + private final KingMemberService kingMemberService; @GetMapping public ResponseEntity> findEducationListByGeneration( @@ -60,15 +62,29 @@ public ResponseEntity findEducationId(@RequestParam(" return ResponseEntity.ok().body(educationService.findEducationIdOfQuizId(quizId)); } - @GetMapping("/result/kings") + @GetMapping("/kings") public ResponseEntity> findFinalKingMembers(@RequestParam("educationId") Long educationId) { log.info("[{} 교육 결승진출자 조회 컨트롤러]", educationId); - return ResponseEntity.ok().body(educationService.findKingMemberInfo(educationId)); + return ResponseEntity.ok().body(kingMemberService.findKingMemberInfo(educationId)); } - @GetMapping("/result/winner") + @PostMapping("/kings") + public ResponseEntity calculateKingMembers(@RequestParam("educationId") Long educationId) { + log.info("[{} 교육 결승진출자 계산하기]", educationId); + kingMemberService.saveKingMember(educationId); + return ResponseEntity.noContent().build(); + } + + @GetMapping("/winner") public ResponseEntity findWinner(@RequestParam("educationId") Long educationId) { log.info("[{} 교육 우승자 조회 컨트롤러]", educationId); - return ResponseEntity.ok().body(educationService.findWinner(educationId)); + return ResponseEntity.ok().body(kingMemberService.findWinner(educationId)); + } + + @PostMapping("/winner") + public ResponseEntity calculateWinner(@RequestParam("educationId") Long educationId) { + log.info("[{} 교육 우승자 계산]", educationId); + kingMemberService.calculateWinner(educationId); + return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/org/cotato/csquiz/api/socket/controller/SocketController.java b/src/main/java/org/cotato/csquiz/api/socket/controller/SocketController.java index f5a5b7c0..a3f15a05 100644 --- a/src/main/java/org/cotato/csquiz/api/socket/controller/SocketController.java +++ b/src/main/java/org/cotato/csquiz/api/socket/controller/SocketController.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -68,4 +69,19 @@ public ResponseEntity stopAllQuiz(@RequestBody @Valid EducationCloseReques public ResponseEntity makeSocketToken(@RequestHeader("Authorization") String authorizationHeader) { return ResponseEntity.ok(socketService.createSocketToken(authorizationHeader)); } + + + @PostMapping("/kings") + public ResponseEntity sendKingCommand(@RequestParam("educationId") Long educationId) { + log.info("[{} 교육 결승진출자 재전송하기]", educationId); + socketService.sendKingCommand(educationId); + return ResponseEntity.noContent().build(); + } + + @PostMapping("/winner") + public ResponseEntity sendWinnerCommand(@RequestParam("educationId") Long educationId) { + log.info("[{} 교육 결승진출자 재전송하기]", educationId); + socketService.sendWinnerCommand(educationId); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/org/cotato/csquiz/api/socket/dto/EducationResultResponse.java b/src/main/java/org/cotato/csquiz/api/socket/dto/EducationResultResponse.java new file mode 100644 index 00000000..21650e14 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/socket/dto/EducationResultResponse.java @@ -0,0 +1,13 @@ +package org.cotato.csquiz.api.socket.dto; + +import org.cotato.csquiz.domain.education.entity.Education; + +public record EducationResultResponse( + String command, + Long educationId +) { + public static EducationResultResponse of(String command, Long educationId) { + return new EducationResultResponse(command, educationId); + } + +} diff --git a/src/main/java/org/cotato/csquiz/api/socket/dto/QuizStopResponse.java b/src/main/java/org/cotato/csquiz/api/socket/dto/QuizStopResponse.java index d1d78ac5..c35a477a 100644 --- a/src/main/java/org/cotato/csquiz/api/socket/dto/QuizStopResponse.java +++ b/src/main/java/org/cotato/csquiz/api/socket/dto/QuizStopResponse.java @@ -4,9 +4,11 @@ public record QuizStopResponse( String command, Long quizId ) { - public static QuizStopResponse from(String command, Long quizId) { + public static final String STOP_COMMAND = "stop"; + + public static QuizStopResponse from(Long quizId) { return new QuizStopResponse( - command, + STOP_COMMAND, quizId ); } diff --git a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java index cddde6a1..97f12139 100644 --- a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java +++ b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java @@ -56,8 +56,12 @@ public enum ErrorCode { SUBJECT_INVALID(HttpStatus.BAD_REQUEST, "E-000", "교육 주제는 NULL이거나 비어있을 수 없습니다."), + KING_MEMBER_EXIST(HttpStatus.CONFLICT, "K-301", "이미 킹킹 멤버가 존재합니다"), + ALREADY_REPLY_CORRECT(HttpStatus.BAD_REQUEST, "R-301", "해당 사용자는 이미 정답 처리되었습니다."), + LAST_QUIZ_SCORER_NOT_EXIST(HttpStatus.CONFLICT, "W-201", "아직 마지막 문제 득점자가 없습니다"), + WINNER_EXIST(HttpStatus.CONFLICT, "W-301", "이미 우승자가 존재합니다"), // 500 오류 -> 서버측에서 처리가 실패한 부분들 WEBSOCKET_SEND_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "S-001", "소캣 메세지 전송 실패"), IMAGE_PROCESSING_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-002", "이미지 처리에 실패했습니다."), diff --git a/src/main/java/org/cotato/csquiz/common/websocket/WebSocketHandler.java b/src/main/java/org/cotato/csquiz/common/websocket/WebSocketHandler.java index 2b72604d..a0ffa8c2 100644 --- a/src/main/java/org/cotato/csquiz/common/websocket/WebSocketHandler.java +++ b/src/main/java/org/cotato/csquiz/common/websocket/WebSocketHandler.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.cotato.csquiz.api.socket.dto.CsQuizStopResponse; +import org.cotato.csquiz.api.socket.dto.EducationResultResponse; import org.cotato.csquiz.api.socket.dto.QuizStartResponse; import org.cotato.csquiz.api.socket.dto.QuizStatusResponse; import org.cotato.csquiz.api.socket.dto.QuizStopResponse; @@ -118,14 +119,23 @@ public void startQuiz(Long quizId) { } public void stopQuiz(Quiz quiz) { - String command = ""; - if (quiz.getNumber() == 9) { - command = KING_COMMAND; + QuizStopResponse response = QuizStopResponse.from(quiz.getId()); + for (WebSocketSession clientSession : CLIENTS.values()) { + sendMessage(clientSession, response); } - if (quiz.getNumber() == 10) { - command = WINNER_COMMAND; + } + + public void sendKingMemberCommand(Long educationId) { + EducationResultResponse response = EducationResultResponse.of(KING_COMMAND, educationId); + + for (WebSocketSession clientSession : CLIENTS.values()) { + sendMessage(clientSession, response); } - QuizStopResponse response = QuizStopResponse.from(command, quiz.getId()); + } + + public void sendWinnerCommand(Long educationId) { + EducationResultResponse response = EducationResultResponse.of(WINNER_COMMAND, educationId); + for (WebSocketSession clientSession : CLIENTS.values()) { sendMessage(clientSession, response); } diff --git a/src/main/java/org/cotato/csquiz/domain/education/repository/KingMemberRepository.java b/src/main/java/org/cotato/csquiz/domain/education/repository/KingMemberRepository.java index 80841862..1162d428 100644 --- a/src/main/java/org/cotato/csquiz/domain/education/repository/KingMemberRepository.java +++ b/src/main/java/org/cotato/csquiz/domain/education/repository/KingMemberRepository.java @@ -7,4 +7,6 @@ public interface KingMemberRepository extends JpaRepository { List findAllByEducation(Education education); + + boolean existsByEducation(Education education); } diff --git a/src/main/java/org/cotato/csquiz/domain/education/repository/QuizRepository.java b/src/main/java/org/cotato/csquiz/domain/education/repository/QuizRepository.java index 078cb08f..dee1e5ed 100644 --- a/src/main/java/org/cotato/csquiz/domain/education/repository/QuizRepository.java +++ b/src/main/java/org/cotato/csquiz/domain/education/repository/QuizRepository.java @@ -1,5 +1,6 @@ package org.cotato.csquiz.domain.education.repository; +import org.cotato.csquiz.domain.education.entity.Education; import org.cotato.csquiz.domain.education.entity.Quiz; import org.cotato.csquiz.domain.education.enums.QuizStatus; import java.util.List; @@ -29,4 +30,8 @@ public interface QuizRepository extends JpaRepository { @Modifying @Query("select q from Quiz q where q.education.id in :educationIds") List findAllByEducationIdsInQuery(@Param("educationIds") List educationIds); + + Optional findByEducationIdAndNumber(Long educationId, Integer i); + + Optional findFirstByEducationOrderByNumberDesc(Education education); } diff --git a/src/main/java/org/cotato/csquiz/domain/education/repository/WinnerRepository.java b/src/main/java/org/cotato/csquiz/domain/education/repository/WinnerRepository.java index 3af17527..c36b5476 100644 --- a/src/main/java/org/cotato/csquiz/domain/education/repository/WinnerRepository.java +++ b/src/main/java/org/cotato/csquiz/domain/education/repository/WinnerRepository.java @@ -7,4 +7,6 @@ public interface WinnerRepository extends JpaRepository { Optional findByEducation(Education education); + + boolean existsByEducation(Education education); } diff --git a/src/main/java/org/cotato/csquiz/domain/education/service/EducationService.java b/src/main/java/org/cotato/csquiz/domain/education/service/EducationService.java index 02572c8e..615d9514 100644 --- a/src/main/java/org/cotato/csquiz/domain/education/service/EducationService.java +++ b/src/main/java/org/cotato/csquiz/domain/education/service/EducationService.java @@ -36,11 +36,8 @@ @Slf4j public class EducationService { - private final MemberService memberService; private final EducationRepository educationRepository; - private final KingMemberRepository kingMemberRepository; private final QuizRepository quizRepository; - private final WinnerRepository winnerRepository; private final SessionRepository sessionRepository; @Transactional @@ -97,32 +94,6 @@ public List findEducationListByGeneration(Long generationI .toList(); } - public List findKingMemberInfo(Long educationId) { - Education findEducation = educationRepository.findById(educationId) - .orElseThrow(() -> new EntityNotFoundException("해당 교육을 찾을 수 없습니다.")); - List kingMembers = kingMemberRepository.findAllByEducation(findEducation); - validateIsEmpty(kingMembers); - return kingMembers.stream() - .map(kingMember -> memberService.findById(kingMember.getMemberId())) - .map(member -> KingMemberInfo.from(member, memberService.findBackFourNumber(member))) - .toList(); - } - - private void validateIsEmpty(List kingMembers) { - if (kingMembers.isEmpty()) { - throw new EntityNotFoundException("아직 결승 진출자가 결정되지 않았습니다."); - } - } - - public WinnerInfoResponse findWinner(Long educationId) { - Education findEducation = educationRepository.findById(educationId) - .orElseThrow(() -> new EntityNotFoundException("해당 교육을 찾을 수 없습니다.")); - Winner findWinner = winnerRepository.findByEducation(findEducation) - .orElseThrow(() -> new EntityNotFoundException("해당 교육의 우승자를 찾을 수 없습니다.")); - Member findMember = memberService.findById(findWinner.getMemberId()); - return WinnerInfoResponse.of(findWinner, findMember, memberService.findBackFourNumber(findMember)); - } - public EducationIdOfQuizResponse findEducationIdOfQuizId(Long quizId) { Quiz quiz = quizRepository.findById(quizId) .orElseThrow(() -> new EntityNotFoundException("해당 문제를 찾을 수 없습니다.")); diff --git a/src/main/java/org/cotato/csquiz/domain/education/service/KingMemberService.java b/src/main/java/org/cotato/csquiz/domain/education/service/KingMemberService.java index 61315924..6f6de88d 100644 --- a/src/main/java/org/cotato/csquiz/domain/education/service/KingMemberService.java +++ b/src/main/java/org/cotato/csquiz/domain/education/service/KingMemberService.java @@ -8,11 +8,16 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.cotato.csquiz.api.education.dto.WinnerInfoResponse; +import org.cotato.csquiz.api.quiz.dto.KingMemberInfo; +import org.cotato.csquiz.common.error.ErrorCode; +import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.domain.education.entity.Education; import org.cotato.csquiz.domain.education.entity.KingMember; import org.cotato.csquiz.domain.education.entity.Quiz; import org.cotato.csquiz.domain.education.entity.Scorer; import org.cotato.csquiz.domain.education.entity.Winner; +import org.cotato.csquiz.domain.education.repository.EducationRepository; import org.cotato.csquiz.domain.education.repository.QuizRepository; import org.cotato.csquiz.domain.education.repository.ScorerRepository; import org.cotato.csquiz.domain.auth.entity.Member; @@ -35,13 +40,20 @@ public class KingMemberService { private final KingMemberRepository kingMemberRepository; private final ScorerRepository scorerRepository; private final WinnerRepository winnerRepository; + private final EducationRepository educationRepository; - public List calculateKingMember(Education education) { - List members = findKingMembersFromEducation(education); + @Transactional + public void saveKingMember(Long educationId) { + Education education = findEducationById(educationId); + + checkKingMemberExist(education); - return members.stream() + List kingMembers = findKingMembersFromEducation(education).stream() .map(member -> KingMember.of(member, education)) .toList(); + + kingMemberRepository.saveAll(kingMembers); + saveWinnerIfKingMemberIsOne(education); } private List findKingMembersFromEducation(Education education) { @@ -64,13 +76,7 @@ private List findKingMembers(List scorers) { .toList(); } - @Transactional - public void saveKingMembers(List kingMembers) { - kingMemberRepository.saveAll(kingMembers); - } - - @Transactional - public void saveWinnerIfKingMemberIsOne(Education education) { + private void saveWinnerIfKingMemberIsOne(Education education) { List kingMembers = kingMemberRepository.findAllByEducation(education); if (kingMembers.size() == 1) { Member findMember = memberRepository.findById(kingMembers.get(0).getMemberId()) @@ -80,13 +86,18 @@ public void saveWinnerIfKingMemberIsOne(Education education) { } @Transactional - public void saveWinnerIfNoWinnerExist(Quiz quiz) { - Education education = quiz.getEducation(); - if (isWinnerExist(education)) { - Scorer findScorer = scorerRepository.findByQuizId(quiz.getId()) - .orElseThrow(() -> new EntityNotFoundException("해당 퀴즈엔 득점자가 존재하지 않습니다.")); - saveWinner(findScorer.getMemberId(), education); + public void calculateWinner(Long educationId) { + Education education = findEducationById(educationId); + if (winnerRepository.existsByEducation(education)) { + throw new AppException(ErrorCode.WINNER_EXIST); } + + Quiz quiz = quizRepository.findFirstByEducationOrderByNumberDesc(education) + .orElseThrow(() -> new EntityNotFoundException("마지막 문제가 없습니다")); + Scorer lastQuizScorer = scorerRepository.findByQuizId(quiz.getId()) + .orElseThrow(() -> new EntityNotFoundException("마지막 퀴즈 득점자가 존재하지 않습니다.")); + + saveWinner(lastQuizScorer.getMemberId(), education); } @Transactional @@ -95,7 +106,40 @@ public void saveWinner(final Long memberId, final Education education) { winnerRepository.save(winner); } - public boolean isWinnerExist(Education education) { - return winnerRepository.findByEducation(education).isPresent(); + public List findKingMemberInfo(Long educationId) { + Education findEducation = educationRepository.findById(educationId) + .orElseThrow(() -> new EntityNotFoundException("해당 교육을 찾을 수 없습니다.")); + List kingMembers = kingMemberRepository.findAllByEducation(findEducation); + validateIsEmpty(kingMembers); + return kingMembers.stream() + .map(kingMember -> memberService.findById(kingMember.getMemberId())) + .map(member -> KingMemberInfo.from(member, memberService.findBackFourNumber(member))) + .toList(); + } + + private void validateIsEmpty(List kingMembers) { + if (kingMembers.isEmpty()) { + throw new EntityNotFoundException("아직 결승 진출자가 결정되지 않았습니다."); + } + } + + public WinnerInfoResponse findWinner(Long educationId) { + Education findEducation = educationRepository.findById(educationId) + .orElseThrow(() -> new EntityNotFoundException("해당 교육을 찾을 수 없습니다.")); + Winner findWinner = winnerRepository.findByEducation(findEducation) + .orElseThrow(() -> new EntityNotFoundException("해당 교육의 우승자를 찾을 수 없습니다.")); + Member findMember = memberService.findById(findWinner.getMemberId()); + return WinnerInfoResponse.of(findWinner, findMember, memberService.findBackFourNumber(findMember)); + } + + private Education findEducationById(Long educationId) { + return educationRepository.findById(educationId) + .orElseThrow(() -> new EntityNotFoundException("해당 교육 id:" + educationId + " 찾다가 에러 발생했습니다.")); + } + + private void checkKingMemberExist(Education education) { + if (kingMemberRepository.existsByEducation(education)) { + throw new AppException(ErrorCode.KING_MEMBER_EXIST); + } } } diff --git a/src/main/java/org/cotato/csquiz/domain/education/service/SocketService.java b/src/main/java/org/cotato/csquiz/domain/education/service/SocketService.java index 4f60e9a4..6e3f8e9b 100644 --- a/src/main/java/org/cotato/csquiz/domain/education/service/SocketService.java +++ b/src/main/java/org/cotato/csquiz/domain/education/service/SocketService.java @@ -19,8 +19,12 @@ import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.common.error.ErrorCode; import org.cotato.csquiz.common.websocket.WebSocketHandler; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; @Service @RequiredArgsConstructor @@ -31,7 +35,6 @@ public class SocketService { private final WebSocketHandler webSocketHandler; private final QuizRepository quizRepository; private final EducationRepository educationRepository; - private final KingMemberService kingMemberService; private final JwtTokenProvider jwtTokenProvider; @@ -106,16 +109,8 @@ public void stopQuizSolve(QuizSocketRequest request) { checkEducationOpen(quiz.getEducation()); quiz.updateStart(QuizStatus.QUIZ_OFF); - if (quiz.getNumber() == 9) { - List kingMembers = kingMemberService.calculateKingMember(quiz.getEducation()); - kingMemberService.saveKingMembers(kingMembers); - kingMemberService.saveWinnerIfKingMemberIsOne(quiz.getEducation()); - webSocketHandler.stopQuiz(quiz); - } - if (quiz.getNumber() == 10) { - kingMemberService.saveWinnerIfNoWinnerExist(quiz); - webSocketHandler.stopQuiz(quiz); - } + + webSocketHandler.stopQuiz(quiz); } @Transactional @@ -171,4 +166,12 @@ private Education findEducationById(Long educationId) { return educationRepository.findById(educationId) .orElseThrow(() -> new EntityNotFoundException("해당 교육을 찾을 수 없습니다.")); } + + public void sendKingCommand(Long educationId) { + webSocketHandler.sendKingMemberCommand(educationId); + } + + public void sendWinnerCommand(Long educationId) { + webSocketHandler.sendWinnerCommand(educationId); + } }