diff --git a/src/main/java/com/example/solidconnection/application/domain/Application.java b/src/main/java/com/example/solidconnection/application/domain/Application.java index b16e6433f..44dcc52f1 100644 --- a/src/main/java/com/example/solidconnection/application/domain/Application.java +++ b/src/main/java/com/example/solidconnection/application/domain/Application.java @@ -54,6 +54,9 @@ public class Application { @ManyToOne private UniversityInfoForApply secondChoiceUniversity; + @ManyToOne + private UniversityInfoForApply thirdChoiceUniversity; + @ManyToOne private SiteUser siteUser; @@ -77,12 +80,14 @@ public void updateGpaAndLanguageTest( public void updateUniversityChoice( UniversityInfoForApply firstChoiceUniversity, UniversityInfoForApply secondChoiceUniversity, + UniversityInfoForApply thirdChoiceUniversity, String nicknameForApply) { if (this.firstChoiceUniversity != null) { this.updateCount++; } this.firstChoiceUniversity = firstChoiceUniversity; this.secondChoiceUniversity = secondChoiceUniversity; + this.thirdChoiceUniversity = thirdChoiceUniversity; this.nicknameForApply = nicknameForApply; } } diff --git a/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java b/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java index fb93b7ff5..2e3025137 100644 --- a/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java +++ b/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java @@ -12,5 +12,8 @@ public record ApplicationsResponse( List firstChoice, @ArraySchema(arraySchema = @Schema(description = "2지망 대학에 지원한 지원자 목록")) - List secondChoice) { + List secondChoice, + + @ArraySchema(arraySchema = @Schema(description = "3지망 대학에 지원한 지원자 목록")) + List thirdChoice) { } diff --git a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java index b179404c8..a76799571 100644 --- a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java +++ b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java @@ -11,5 +11,7 @@ public record UniversityChoiceRequest( Long firstChoiceUniversityId, @Schema(description = "2지망 대학교의 지원 정보 ID (선택사항)", example = "2", nullable = true) - Long secondChoiceUniversityId) { -} + Long secondChoiceUniversityId, + + @Schema(description = "3지망 대학교의 지원 정보 ID (선택사항)", example = "3", nullable = true) + Long thirdChoiceUniversityId) {} diff --git a/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java b/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java index 3cbf7c88f..34b714438 100644 --- a/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java +++ b/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java @@ -26,6 +26,8 @@ public interface ApplicationRepository extends JpaRepository List findAllBySecondChoiceUniversityAndVerifyStatus(UniversityInfoForApply secondChoiceUniversity, VerifyStatus verifyStatus); + List findAllByThirdChoiceUniversityAndVerifyStatus(UniversityInfoForApply thirdChoiceUniversity, VerifyStatus verifyStatus); + default Application getApplicationBySiteUser(SiteUser siteUser) { return findBySiteUser(siteUser) .orElseThrow(() -> new CustomException(APPLICATION_NOT_FOUND)); diff --git a/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java b/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java index 104114c5c..793cf28ca 100644 --- a/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java +++ b/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java @@ -55,7 +55,8 @@ public ApplicationsResponse getApplicants(String email, String regionCode, Strin // 1지망, 2지망 지원자들을 조회한다. List firstChoiceApplicants = getFirstChoiceApplicants(universities, siteUser); List secondChoiceApplicants = getSecondChoiceApplicants(universities, siteUser); - return new ApplicationsResponse(firstChoiceApplicants, secondChoiceApplicants); + List thirdChoiceApplicants = getThirdChoiceApplicants(universities, siteUser); + return new ApplicationsResponse(firstChoiceApplicants, secondChoiceApplicants, thirdChoiceApplicants); } private void validateSiteUserCanViewApplicants(SiteUser siteUser) { @@ -81,6 +82,14 @@ private List getSecondChoiceApplicants(List getThirdChoiceApplicants(List universities, SiteUser siteUser) { + return getApplicantsByChoice( + universities, + siteUser, + uia -> applicationRepository.findAllByThirdChoiceUniversityAndVerifyStatus(uia, VerifyStatus.APPROVED) + ); + } + private List getApplicantsByChoice( List searchedUniversities, SiteUser siteUser, diff --git a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java index dc56e6da3..beec76a05 100644 --- a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java +++ b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java @@ -16,7 +16,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; import static com.example.solidconnection.custom.exception.ErrorCode.APPLY_UPDATE_LIMIT_EXCEED; import static com.example.solidconnection.custom.exception.ErrorCode.CANT_APPLY_FOR_SAME_UNIVERSITY; @@ -61,7 +63,7 @@ public boolean submitScore(String email, ScoreRequest scoreRequest) { /* * 지망 대학교를 제출한다. - * - 첫번째 지망과 두번째 지망이 같은지 검증한다. + * - 지망 대학중 중복된 대학교가 있는지 검증한다. * - 지원 정보 제출 내역이 없다면, 지금의 프로세스(성적 제출 후 지망대학 제출)에 벗어나는 요청이므로 예외를 응답한다. * - 기존에 제출한 적이 있다면, 수정한다. * - 수정 횟수 제한을 초과하지 않았는지 검증한다. @@ -70,7 +72,7 @@ public boolean submitScore(String email, ScoreRequest scoreRequest) { * */ @Transactional public boolean submitUniversityChoice(String email, UniversityChoiceRequest universityChoiceRequest) { - validateFirstAndSecondChoiceIdDifferent(universityChoiceRequest); + validateNoDuplicateUniversityChoices(universityChoiceRequest); Application application = applicationRepository.findBySiteUser_Email(email) .orElseThrow(() -> new CustomException(SCORE_SHOULD_SUBMITTED_FIRST)); @@ -78,9 +80,11 @@ public boolean submitUniversityChoice(String email, UniversityChoiceRequest univ .getUniversityInfoForApplyByIdAndTerm(universityChoiceRequest.firstChoiceUniversityId(), term); UniversityInfoForApply secondChoiceUniversity = universityInfoForApplyRepository .getUniversityInfoForApplyByIdAndTerm(universityChoiceRequest.secondChoiceUniversityId(), term); + UniversityInfoForApply thirdChoiceUniversity = universityInfoForApplyRepository + .getUniversityInfoForApplyByIdAndTerm(universityChoiceRequest.thirdChoiceUniversityId(), term); validateUpdateLimitNotExceed(application); - application.updateUniversityChoice(firstChoiceUniversity, secondChoiceUniversity, getRandomNickname()); + application.updateUniversityChoice(firstChoiceUniversity, secondChoiceUniversity, thirdChoiceUniversity, getRandomNickname()); return true; } @@ -98,10 +102,14 @@ private void validateUpdateLimitNotExceed(Application application) { } } - private void validateFirstAndSecondChoiceIdDifferent(UniversityChoiceRequest universityChoiceRequest) { - if (Objects.equals( - universityChoiceRequest.firstChoiceUniversityId(), - universityChoiceRequest.secondChoiceUniversityId())) { + private void validateNoDuplicateUniversityChoices(UniversityChoiceRequest universityChoiceRequest) { + Set uniqueUniversityIds = new HashSet<>(); + + uniqueUniversityIds.add(universityChoiceRequest.firstChoiceUniversityId()); + uniqueUniversityIds.add(universityChoiceRequest.secondChoiceUniversityId()); + uniqueUniversityIds.add(universityChoiceRequest.thirdChoiceUniversityId()); + + if (uniqueUniversityIds.size() < 3) { throw new CustomException(CANT_APPLY_FOR_SAME_UNIVERSITY); } } diff --git a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java index 0a9df0b61..b46ac83cc 100644 --- a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java @@ -48,7 +48,7 @@ public enum ErrorCode { INVALID_TEST_TYPE(HttpStatus.BAD_REQUEST.value(), "지원하지 않은 어학 시험 종류입니다."), APPLICATION_NOT_APPROVED(HttpStatus.BAD_REQUEST.value(), "성적표가 인증되지 않았습니다."), APPLY_UPDATE_LIMIT_EXCEED(HttpStatus.BAD_REQUEST.value(), "지원 정보 수정은 " + APPLICATION_UPDATE_COUNT_LIMIT + "회까지만 가능합니다."), - CANT_APPLY_FOR_SAME_UNIVERSITY(HttpStatus.BAD_REQUEST.value(), "1, 2지망에 동일한 대학교를 입력할 수 없습니다."), + CANT_APPLY_FOR_SAME_UNIVERSITY(HttpStatus.BAD_REQUEST.value(), "1, 2, 3지망에 동일한 대학교를 입력할 수 없습니다."), CAN_NOT_CHANGE_NICKNAME_YET(HttpStatus.BAD_REQUEST.value(), "마지막 닉네임 변경으로부터 " + MIN_DAYS_BETWEEN_NICKNAME_CHANGES + "일이 지나지 않았습니다."), // community diff --git a/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java b/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java index 6ad77f58b..d609aa121 100644 --- a/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java +++ b/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java @@ -66,10 +66,10 @@ public void setUpUserAndToken() { 사용자1_지원정보 = new Application(사용자1, gpa, languageTest); 사용자2_지원정보 = new Application(사용자2, gpa, languageTest); 사용자3_지원정보 = new Application(사용자3, gpa, languageTest); - 나의_지원정보.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, "0"); - 사용자1_지원정보.updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, "1"); - 사용자2_지원정보.updateUniversityChoice(메이지대학_지원_정보, 그라츠대학_지원_정보, "2"); - 사용자3_지원정보.updateUniversityChoice(네바다주립대학_라스베이거스_지원_정보, 그라츠공과대학_지원_정보, "3"); + 나의_지원정보.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 린츠_카톨릭대학_지원_정보, "0"); + 사용자1_지원정보.updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, 그라츠공과대학_지원_정보, "1"); + 사용자2_지원정보.updateUniversityChoice(메이지대학_지원_정보, 그라츠대학_지원_정보, 서던덴마크대학교_지원_정보, "2"); + 사용자3_지원정보.updateUniversityChoice(네바다주립대학_라스베이거스_지원_정보, 그라츠공과대학_지원_정보, 메이지대학_지원_정보, "3"); 나의_지원정보.setVerifyStatus(VerifyStatus.APPROVED); 사용자1_지원정보.setVerifyStatus(VerifyStatus.APPROVED); 사용자2_지원정보.setVerifyStatus(VerifyStatus.APPROVED); @@ -89,6 +89,7 @@ public void setUpUserAndToken() { List firstChoiceApplicants = response.firstChoice(); List secondChoiceApplicants = response.secondChoice(); + List thirdChoiceApplicants = response.thirdChoice(); assertThat(firstChoiceApplicants).containsAnyElementsOf(List.of( UniversityApplicantsResponse.of(괌대학_A_지원_정보, @@ -110,6 +111,16 @@ public void setUpUserAndToken() { UniversityApplicantsResponse.of(그라츠대학_지원_정보, List.of(ApplicantResponse.of(사용자2_지원정보, false))) )); + assertThat(thirdChoiceApplicants).containsAnyElementsOf(List.of( + UniversityApplicantsResponse.of(린츠_카톨릭대학_지원_정보, + List.of(ApplicantResponse.of(나의_지원정보, true))), + UniversityApplicantsResponse.of(서던덴마크대학교_지원_정보, + List.of(ApplicantResponse.of(사용자2_지원정보, false))), + UniversityApplicantsResponse.of(그라츠공과대학_지원_정보, + List.of(ApplicantResponse.of(사용자1_지원정보, false))), + UniversityApplicantsResponse.of(메이지대학_지원_정보, + List.of(ApplicantResponse.of(사용자3_지원정보, false))) + )); } @Test diff --git a/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java b/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java index f5443f805..0cbe37f35 100644 --- a/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java +++ b/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java @@ -119,7 +119,7 @@ public void setUpUserAndToken() { applicationRepository.save(new Application(siteUser, firstRequest.toGpa(), firstRequest.toLanguageTest())); // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId()); + UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); RestAssured.given() .header("Authorization", "Bearer " + accessToken) .body(request) @@ -135,6 +135,7 @@ public void setUpUserAndToken() { () -> assertThat(application.getSiteUser().getId()).isEqualTo(siteUser.getId()), () -> assertThat(application.getFirstChoiceUniversity().getId()).isEqualTo(request.firstChoiceUniversityId()), () -> assertThat(application.getSecondChoiceUniversity().getId()).isEqualTo(request.secondChoiceUniversityId()), + () -> assertThat(application.getThirdChoiceUniversity().getId()).isEqualTo(request.thirdChoiceUniversityId()), () -> assertThat(application.getNicknameForApply()).isNotNull(), () -> assertThat(application.getVerifyStatus()).isEqualTo(VerifyStatus.PENDING), () -> assertThat(application.getUpdateCount()).isZero()); @@ -146,11 +147,11 @@ public void setUpUserAndToken() { ScoreRequest firstRequest = new ScoreRequest(LanguageTestType.TOEFL_IBT, "80", "languageTestReportUrl", 4.0, 4.5, "gpaReportUrl"); applicationRepository.save(new Application(siteUser, firstRequest.toGpa(), firstRequest.toLanguageTest())) - .updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, "nickname"); + .updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "nickname"); Application initialApplication = applicationRepository.getApplicationBySiteUser(siteUser); // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId()); + UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); RestAssured.given() .header("Authorization", "Bearer " + accessToken) .body(request) @@ -166,6 +167,7 @@ public void setUpUserAndToken() { () -> assertThat(updatedApplication.getSiteUser().getId()).isEqualTo(siteUser.getId()), () -> assertThat(updatedApplication.getFirstChoiceUniversity().getId()).isEqualTo(request.firstChoiceUniversityId()), () -> assertThat(updatedApplication.getSecondChoiceUniversity().getId()).isEqualTo(request.secondChoiceUniversityId()), + () -> assertThat(updatedApplication.getThirdChoiceUniversity().getId()).isEqualTo(request.thirdChoiceUniversityId()), () -> assertThat(updatedApplication.getNicknameForApply()).isNotNull(), () -> assertThat(updatedApplication.getVerifyStatus()).isEqualTo(initialApplication.getVerifyStatus()), () -> assertThat(updatedApplication.getUpdateCount()).isEqualTo(initialApplication.getUpdateCount())); @@ -181,12 +183,12 @@ public void setUpUserAndToken() { // setUp - 지망 대학을 한계까지 수정 for (int i = 0; i <= APPLICATION_UPDATE_COUNT_LIMIT; i++) { - initialApplication.updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, "nickname"); + initialApplication.updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "nickname"); applicationRepository.save(initialApplication); } // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId()); + UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); ErrorResponse errorResponse = RestAssured.given().log().all() .header("Authorization", "Bearer " + accessToken) .body(request) @@ -202,7 +204,41 @@ public void setUpUserAndToken() { @Test void 일지망_대학과_이지망_대학이_같으면_예외_응답을_반환한다() { // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 그라츠대학_지원_정보.getId()); + UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 그라츠대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); + ErrorResponse errorResponse = RestAssured.given() + .header("Authorization", "Bearer " + accessToken) + .body(request) + .contentType("application/json") + .log().all() + .post("/application/university") + .then().log().all() + .statusCode(HttpStatus.BAD_REQUEST.value()) + .extract().as(ErrorResponse.class); + + assertThat(errorResponse.message()).isEqualTo(CANT_APPLY_FOR_SAME_UNIVERSITY.getMessage()); + } + + @Test + void 일지망_대학과_삼지망_대학이_같으면_예외_응답을_반환한다() { + // request - body 생성 및 요청 + UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 그라츠대학_지원_정보.getId()); + ErrorResponse errorResponse = RestAssured.given() + .header("Authorization", "Bearer " + accessToken) + .body(request) + .contentType("application/json") + .log().all() + .post("/application/university") + .then().log().all() + .statusCode(HttpStatus.BAD_REQUEST.value()) + .extract().as(ErrorResponse.class); + + assertThat(errorResponse.message()).isEqualTo(CANT_APPLY_FOR_SAME_UNIVERSITY.getMessage()); + } + + @Test + void 이지망_대학과_삼지망_대학이_같으면_예외_응답을_반환한다() { + // request - body 생성 및 요청 + UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId()); ErrorResponse errorResponse = RestAssured.given() .header("Authorization", "Bearer " + accessToken) .body(request) diff --git a/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java b/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java index d0749f1f9..b4447247a 100644 --- a/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java +++ b/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java @@ -87,7 +87,7 @@ public void setUpUserAndToken() { void 성적과_대학을_모두_제출하고_승인을_기대라는_상태를_반환한다() { // setUp - 성적과 대학을 모두 제출한 상태 Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest()); - application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, "닉네임"); + application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "닉네임"); applicationRepository.save(application); // request - 요청 @@ -108,7 +108,7 @@ public void setUpUserAndToken() { void 성적과_대학을_모두_제출했지만_승인이_반려된_상태를_반환한다() { // setUp - 성적과 대학을 모두 제출했지만, 승인 거절 Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest()); - application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, "닉네임"); + application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 네바다주립대학_라스베이거스_지원_정보,"닉네임"); application.setVerifyStatus(VerifyStatus.REJECTED); applicationRepository.save(application); @@ -130,7 +130,7 @@ public void setUpUserAndToken() { void 성적과_대학을_모두_제출했으며_승인이_된_상태를_반환한다() { // setUp - 성적과 대학을 모두 제출했으며, 승인이 된 상태 Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest()); - application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, "닉네임"); + application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "닉네임"); application.setVerifyStatus(VerifyStatus.APPROVED); applicationRepository.save(application);