diff --git a/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java b/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java index d6695df28..8baf7255f 100644 --- a/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java +++ b/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java @@ -1,13 +1,8 @@ package com.example.solidconnection.application.controller; -import com.example.solidconnection.application.dto.ApplicationSubmissionResponse; -import com.example.solidconnection.application.dto.ApplicationsResponse; -import com.example.solidconnection.application.dto.ScoreRequest; -import com.example.solidconnection.application.dto.UniversityChoiceRequest; -import com.example.solidconnection.application.dto.VerifyStatusResponse; +import com.example.solidconnection.application.dto.*; import com.example.solidconnection.application.service.ApplicationQueryService; import com.example.solidconnection.application.service.ApplicationSubmissionService; -import com.example.solidconnection.application.service.VerifyStatusQueryService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -28,28 +23,18 @@ public class ApplicationController implements ApplicationControllerSwagger { private final ApplicationSubmissionService applicationSubmissionService; private final ApplicationQueryService applicationQueryService; - private final VerifyStatusQueryService verifyStatusQueryService; - @PostMapping("/score") - public ResponseEntity submitScore( + // 지원서 제출하기 api + @PostMapping() + public ResponseEntity apply( Principal principal, - @Valid @RequestBody ScoreRequest scoreRequest) { - boolean result = applicationSubmissionService.submitScore(principal.getName(), scoreRequest); + @Valid @RequestBody ApplyRequest applyRequest) { + boolean result = applicationSubmissionService.apply(principal.getName(), applyRequest); return ResponseEntity .status(HttpStatus.OK) .body(new ApplicationSubmissionResponse(result)); } - @PostMapping("/university") - public ResponseEntity submitUniversityChoice( - Principal principal, - @Valid @RequestBody UniversityChoiceRequest universityChoiceRequest) { - boolean result = applicationSubmissionService.submitUniversityChoice(principal.getName(), universityChoiceRequest); - return ResponseEntity - .status(HttpStatus.OK) - .body(new ApplicationSubmissionResponse(result)); - } - @GetMapping public ResponseEntity getApplicants( Principal principal, @@ -69,11 +54,4 @@ public ResponseEntity getApplicantsForUserCompetitors( return ResponseEntity .ok(result); } - - @GetMapping("/status") - public ResponseEntity getApplicationVerifyStatus(Principal principal) { - VerifyStatusResponse result = verifyStatusQueryService.getVerifyStatus(principal.getName()); - return ResponseEntity - .ok(result); - } } diff --git a/src/main/java/com/example/solidconnection/application/controller/ApplicationControllerSwagger.java b/src/main/java/com/example/solidconnection/application/controller/ApplicationControllerSwagger.java index f531923ac..3b93dea4c 100644 --- a/src/main/java/com/example/solidconnection/application/controller/ApplicationControllerSwagger.java +++ b/src/main/java/com/example/solidconnection/application/controller/ApplicationControllerSwagger.java @@ -1,10 +1,6 @@ package com.example.solidconnection.application.controller; -import com.example.solidconnection.application.dto.ApplicationSubmissionResponse; import com.example.solidconnection.application.dto.ApplicationsResponse; -import com.example.solidconnection.application.dto.ScoreRequest; -import com.example.solidconnection.application.dto.UniversityChoiceRequest; -import com.example.solidconnection.application.dto.VerifyStatusResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; @@ -12,10 +8,8 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirements; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestParam; -import io.swagger.v3.oas.annotations.parameters.RequestBody; import java.security.Principal; @@ -25,53 +19,6 @@ @SecurityRequirements @SecurityRequirement(name = ACCESS_TOKEN) public interface ApplicationControllerSwagger { - - @Operation( - summary = "대학 성적과 어학 성적 제출", - requestBody = @RequestBody( - description = "대학 성적과 어학 성적", - required = true, - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ScoreRequest.class) - ) - ), - responses = { - @ApiResponse( - responseCode = "200", - description = "대학 성적과 어학 성적 제출 성공", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ApplicationSubmissionResponse.class) - ) - ) - } - ) - ResponseEntity submitScore(Principal principal, @Valid @RequestBody ScoreRequest scoreRequest); - - @Operation( - summary = "지망 대학 제출", - requestBody = @RequestBody( - description = "지망 대학", - required = true, - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = UniversityChoiceRequest.class) - ) - ), - responses = { - @ApiResponse( - responseCode = "200", - description = "지망 대학 제출 성공", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ApplicationSubmissionResponse.class) - ) - ) - } - ) - ResponseEntity submitUniversityChoice(Principal principal, @Valid @RequestBody UniversityChoiceRequest universityChoiceRequest); - @Operation( summary = "지원자 목록 조회", responses = { @@ -86,19 +33,4 @@ public interface ApplicationControllerSwagger { } ) ResponseEntity getApplicants(Principal principal, @RequestParam(required = false) String region, @RequestParam(required = false) String keyword); - - @Operation( - summary = "성적 승인 상태 확인", - responses = { - @ApiResponse( - responseCode = "200", - description = "성적 승인 상태 반환", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = VerifyStatusResponse.class) - ) - ) - } - ) - ResponseEntity getApplicationVerifyStatus(Principal principal); } 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 085141f22..0c56fd7f5 100644 --- a/src/main/java/com/example/solidconnection/application/domain/Application.java +++ b/src/main/java/com/example/solidconnection/application/domain/Application.java @@ -3,15 +3,7 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.VerifyStatus; import com.example.solidconnection.university.domain.UniversityInfoForApply; -import jakarta.persistence.Column; -import jakarta.persistence.Embedded; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -51,16 +43,19 @@ public class Application { @Column(length = 50, nullable = false) private String term; - @ManyToOne + @Column(columnDefinition = "TINYINT(1) NOT NULL DEFAULT 0") + private Boolean isDelete; + + @ManyToOne(fetch = FetchType.LAZY) private UniversityInfoForApply firstChoiceUniversity; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) private UniversityInfoForApply secondChoiceUniversity; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) private UniversityInfoForApply thirdChoiceUniversity; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) private SiteUser siteUser; public Application( @@ -76,14 +71,53 @@ public Application( this.verifyStatus = PENDING; } - public void updateGpaAndLanguageTest( + public Application( + SiteUser siteUser, + Gpa gpa, + LanguageTest languageTest, + String term, + Integer updateCount, + UniversityInfoForApply firstChoiceUniversity, + UniversityInfoForApply secondChoiceUniversity, + UniversityInfoForApply thirdChoiceUniversity, + String nicknameForApply) { + this.siteUser = siteUser; + this.gpa = gpa; + this.languageTest = languageTest; + this.term = term; + this.updateCount = updateCount; + this.firstChoiceUniversity = firstChoiceUniversity; + this.secondChoiceUniversity = secondChoiceUniversity; + this.thirdChoiceUniversity = thirdChoiceUniversity; + this.nicknameForApply = nicknameForApply; + this.verifyStatus = PENDING; + } + + public Application( + SiteUser siteUser, Gpa gpa, - LanguageTest languageTest) { + LanguageTest languageTest, + String term, + UniversityInfoForApply firstChoiceUniversity, + UniversityInfoForApply secondChoiceUniversity, + UniversityInfoForApply thirdChoiceUniversity, + String nicknameForApply) { + this.siteUser = siteUser; this.gpa = gpa; this.languageTest = languageTest; + this.term = term; + this.updateCount = 0; + this.firstChoiceUniversity = firstChoiceUniversity; + this.secondChoiceUniversity = secondChoiceUniversity; + this.thirdChoiceUniversity = thirdChoiceUniversity; + this.nicknameForApply = nicknameForApply; this.verifyStatus = PENDING; } + public void setIsDeleteTrue() { + this.isDelete = true; + } + public void updateUniversityChoice( UniversityInfoForApply firstChoiceUniversity, UniversityInfoForApply secondChoiceUniversity, diff --git a/src/main/java/com/example/solidconnection/application/domain/Gpa.java b/src/main/java/com/example/solidconnection/application/domain/Gpa.java index 82803dae9..85b12d047 100644 --- a/src/main/java/com/example/solidconnection/application/domain/Gpa.java +++ b/src/main/java/com/example/solidconnection/application/domain/Gpa.java @@ -3,6 +3,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; @@ -10,6 +11,7 @@ @AllArgsConstructor @NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) @Embeddable +@EqualsAndHashCode(of = {"gpa", "gpaCriteria", "gpaReportUrl"}) public class Gpa { @Column(nullable = false, name = "gpa") diff --git a/src/main/java/com/example/solidconnection/application/domain/LanguageTest.java b/src/main/java/com/example/solidconnection/application/domain/LanguageTest.java index a1e579ad8..4295372d4 100644 --- a/src/main/java/com/example/solidconnection/application/domain/LanguageTest.java +++ b/src/main/java/com/example/solidconnection/application/domain/LanguageTest.java @@ -6,6 +6,7 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; @@ -13,6 +14,7 @@ @AllArgsConstructor @NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) @Embeddable +@EqualsAndHashCode(of = {"languageTestType", "languageTestScore", "languageTestReportUrl"}) public class LanguageTest { @Column(nullable = false, name = "language_test_type", length = 10) diff --git a/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java b/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java new file mode 100644 index 000000000..3a5d7f2f5 --- /dev/null +++ b/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java @@ -0,0 +1,18 @@ +package com.example.solidconnection.application.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "지원서 제출") +public record ApplyRequest( + @NotNull(message = "gpa score id를 입력해주세요.") + @Schema(description = "지원하는 유저의 gpa score id", example = "1") + Long gpaScoreId, + + @NotNull(message = "language test score id를 입력해주세요.") + @Schema(description = "지원하는 유저의 language test score id", example = "1") + Long languageTestScoreId, + + UniversityChoiceRequest universityChoiceRequest +) { +} 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 8f30c196c..a3bca9dc2 100644 --- a/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java +++ b/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java @@ -6,6 +6,8 @@ import com.example.solidconnection.type.VerifyStatus; import com.example.solidconnection.university.domain.UniversityInfoForApply; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @@ -18,9 +20,8 @@ public interface ApplicationRepository extends JpaRepository boolean existsByNicknameForApply(String nicknameForApply); - Optional findTop1BySiteUser_EmailOrderByTermDesc(String email); - - Optional findBySiteUserAndTerm(SiteUser siteUser, String term); + @Query("SELECT a FROM Application a WHERE a.siteUser = :siteUser AND a.term = :term AND a.isDelete = false") + Optional findBySiteUserAndTerm(@Param("siteUser") SiteUser siteUser, @Param("term") String term); List findAllByFirstChoiceUniversityAndVerifyStatusAndTerm(UniversityInfoForApply firstChoiceUniversity, VerifyStatus verifyStatus, String term); 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 b23b876c7..6b263996e 100644 --- a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java +++ b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java @@ -1,15 +1,17 @@ package com.example.solidconnection.application.service; -import com.example.solidconnection.application.domain.Application; -import com.example.solidconnection.application.domain.Gpa; -import com.example.solidconnection.application.domain.LanguageTest; -import com.example.solidconnection.application.dto.ScoreRequest; +import com.example.solidconnection.application.domain.*; +import com.example.solidconnection.application.dto.ApplyRequest; import com.example.solidconnection.application.dto.UniversityChoiceRequest; import com.example.solidconnection.application.repository.ApplicationRepository; -import com.example.solidconnection.cache.annotation.DefaultCacheOut; +import com.example.solidconnection.score.repository.GpaScoreRepository; +import com.example.solidconnection.score.repository.LanguageTestScoreRepository; import com.example.solidconnection.custom.exception.CustomException; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.score.domain.LanguageTestScore; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.type.VerifyStatus; import com.example.solidconnection.university.domain.UniversityInfoForApply; import com.example.solidconnection.university.repository.UniversityInfoForApplyRepository; import lombok.RequiredArgsConstructor; @@ -30,63 +32,26 @@ public class ApplicationSubmissionService { private final ApplicationRepository applicationRepository; private final UniversityInfoForApplyRepository universityInfoForApplyRepository; private final SiteUserRepository siteUserRepository; + private final GpaScoreRepository gpaScoreRepository; + private final LanguageTestScoreRepository languageTestScoreRepository; @Value("${university.term}") private String term; - /* - * 학점과 영어 성적을 제출한다. - * - 금학기에 제출한 적이 있다면, 수정한다. - * - 성적을 제출한적이 한번도 없거나 제출한적이 있지만 금학기에 제출한 적이 없다면 새로 등록한다. - * - 수정을 하고 나면, 성적 승인 상태(verifyStatus)를 PENDING 상태로 변경한다. - * */ + // 학점 및 어학성적이 모두 유효한 경우에만 지원서 등록이 가능하다. + // 기존에 있던 status field 우선 APRROVED로 입력시킨다. @Transactional - @DefaultCacheOut(key = "application:query", cacheManager = "customCacheManager", prefix = true) - public boolean submitScore(String email, ScoreRequest scoreRequest) { + public boolean apply(String email, ApplyRequest applyRequest) { SiteUser siteUser = siteUserRepository.getByEmail(email); - Gpa gpa = scoreRequest.toGpa(); - LanguageTest languageTest = scoreRequest.toLanguageTest(); - - applicationRepository.findBySiteUserAndTerm(siteUser, term) - .ifPresentOrElse( - // 금학기에 성적 제출 이력이 있는 경우 - application -> application.updateGpaAndLanguageTest(gpa, languageTest), - () -> { - // 성적 제출한적이 한번도 없는 경우 && 성적 제출한적이 있지만 금학기에 없는 경우 - applicationRepository.save(new Application(siteUser, gpa, languageTest, term)); - } - ); - return true; - } - - /* - * 지망 대학교를 제출한다. - * - 지망 대학중 중복된 대학교가 있는지 검증한다. - * - 지원 정보 제출 내역이 없다면, 지금의 프로세스(성적 제출 후 지망대학 제출)에 벗어나는 요청이므로 예외를 응답한다. - * - 기존에 제출한 적이 있다면, 수정한다. - * - 수정 횟수 제한을 초과하지 않았는지 검증한다. - * - 새로운 '제출 닉네임'을 부여한다. (악의적으로 타인의 변경 기록을 추적하는 것을 막기 위해) - * - 성적 승인 상태(verifyStatus) 는 변경하지 않는다. - * */ - @Transactional - @DefaultCacheOut(key = "application:query", cacheManager = "customCacheManager", prefix = true) - public boolean submitUniversityChoice(String email, UniversityChoiceRequest universityChoiceRequest) { + UniversityChoiceRequest universityChoiceRequest = applyRequest.universityChoiceRequest(); validateUniversityChoices(universityChoiceRequest); - // 성적 제출한 적이 한번도 없는 경우 - Application existingApplication = applicationRepository.findTop1BySiteUser_EmailOrderByTermDesc(email) - .orElseThrow(() -> new CustomException(SCORE_SHOULD_SUBMITTED_FIRST)); + Long gpaScoreId = applyRequest.gpaScoreId(); + Long languageTestScoreId = applyRequest.languageTestScoreId(); + GpaScore gpaScore = getValidGpaScore(siteUser, gpaScoreId); + LanguageTestScore languageTestScore = getValidLanguageTestScore(siteUser, languageTestScoreId); - Application application = Optional.of(existingApplication) - .filter(app -> !app.getTerm().equals(term)) - .map(app -> { - // 성적 제출한 적이 있지만 금학기에 없는 경우, 이전 성적으로 새 Application 객체를 등록 - SiteUser siteUser = siteUserRepository.getByEmail(email); - return applicationRepository.save(new Application(siteUser, app.getGpa(), app.getLanguageTest(), term)); - }) - .orElse(existingApplication); // 금학기에 이미 성적 제출한 경우 기존 객체 사용 - - validateUpdateLimitNotExceed(application); + Optional application = applicationRepository.findBySiteUserAndTerm(siteUser, term); UniversityInfoForApply firstChoiceUniversity = universityInfoForApplyRepository .getUniversityInfoForApplyByIdAndTerm(universityChoiceRequest.firstChoiceUniversityId(), term); @@ -96,10 +61,44 @@ public boolean submitUniversityChoice(String email, UniversityChoiceRequest univ UniversityInfoForApply thirdChoiceUniversity = Optional.ofNullable(universityChoiceRequest.thirdChoiceUniversityId()) .map(id -> universityInfoForApplyRepository.getUniversityInfoForApplyByIdAndTerm(id, term)) .orElse(null); - application.updateUniversityChoice(firstChoiceUniversity, secondChoiceUniversity, thirdChoiceUniversity, getRandomNickname()); + + if (application.isEmpty()) { + Application newApplication = new Application(siteUser, gpaScore.getGpa(), languageTestScore.getLanguageTest(), + term, firstChoiceUniversity, secondChoiceUniversity, thirdChoiceUniversity, getRandomNickname()); + newApplication.setVerifyStatus(VerifyStatus.APPROVED); + applicationRepository.save(newApplication); + } else { + Application before = application.get(); + validateUpdateLimitNotExceed(before); + before.setIsDeleteTrue(); // 기존 이력 soft delete 수행한다. + + Application newApplication = new Application(siteUser, gpaScore.getGpa(), languageTestScore.getLanguageTest(), + term, before.getUpdateCount() + 1, firstChoiceUniversity, secondChoiceUniversity, thirdChoiceUniversity, getRandomNickname()); + newApplication.setVerifyStatus(VerifyStatus.APPROVED); + applicationRepository.save(newApplication); + } return true; } + private GpaScore getValidGpaScore(SiteUser siteUser, Long gpaScoreId) { + GpaScore gpaScore = gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScoreId) + .orElseThrow(() -> new CustomException(INVALID_GPA_SCORE)); + if (gpaScore.getVerifyStatus() != VerifyStatus.APPROVED) { + throw new CustomException(INVALID_GPA_SCORE_STATUS); + } + return gpaScore; + } + + private LanguageTestScore getValidLanguageTestScore(SiteUser siteUser, Long languageTestScoreId) { + LanguageTestScore languageTestScore = languageTestScoreRepository + .findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScoreId) + .orElseThrow(() -> new CustomException(INVALID_LANGUAGE_TEST_SCORE)); + if (languageTestScore.getVerifyStatus() != VerifyStatus.APPROVED) { + throw new CustomException(INVALID_LANGUAGE_TEST_SCORE_STATUS); + } + return languageTestScore; + } + private String getRandomNickname() { String randomNickname = NicknameCreator.createRandomNickname(); while (applicationRepository.existsByNicknameForApply(randomNickname)) { diff --git a/src/main/java/com/example/solidconnection/application/service/VerifyStatusQueryService.java b/src/main/java/com/example/solidconnection/application/service/VerifyStatusQueryService.java deleted file mode 100644 index 33bb340d9..000000000 --- a/src/main/java/com/example/solidconnection/application/service/VerifyStatusQueryService.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.example.solidconnection.application.service; - -import com.example.solidconnection.application.domain.Application; -import com.example.solidconnection.application.dto.VerifyStatusResponse; -import com.example.solidconnection.application.repository.ApplicationRepository; -import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import com.example.solidconnection.type.VerifyStatus; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Optional; - -import static com.example.solidconnection.application.service.VerifyStatusQueryService.ApplicationStatusResponse.NOT_SUBMITTED; -import static com.example.solidconnection.application.service.VerifyStatusQueryService.ApplicationStatusResponse.SCORE_SUBMITTED; -import static com.example.solidconnection.application.service.VerifyStatusQueryService.ApplicationStatusResponse.SUBMITTED_APPROVED; -import static com.example.solidconnection.application.service.VerifyStatusQueryService.ApplicationStatusResponse.SUBMITTED_PENDING; -import static com.example.solidconnection.application.service.VerifyStatusQueryService.ApplicationStatusResponse.SUBMITTED_REJECTED; - -@RequiredArgsConstructor -@Service -public class VerifyStatusQueryService { - - private final ApplicationRepository applicationRepository; - private final SiteUserRepository siteUserRepository; - - @Value("${university.term}") - private String term; - - /* - * 지원 상태를 조회한다. - * 학기별로 상태가 관리된다. - * */ - @Transactional(readOnly = true) - public VerifyStatusResponse getVerifyStatus(String email) { - SiteUser siteUser = siteUserRepository.getByEmail(email); - Optional application = applicationRepository.findBySiteUserAndTerm(siteUser,term); - - // 아무것도 제출 안함 - if (application.isEmpty()) { - return new VerifyStatusResponse(NOT_SUBMITTED.name(), 0); - } - - int updateCount = application.get().getUpdateCount(); - - // 제출한 상태 - if (application.get().getVerifyStatus() == VerifyStatus.PENDING) { - // 성적만 제출 - if (application.get().getFirstChoiceUniversity() == null) { - return new VerifyStatusResponse(SCORE_SUBMITTED.name(), 0); - } - // 성적 승인 대기 중 - return new VerifyStatusResponse(SUBMITTED_PENDING.name(), updateCount); - } - - // 성적 승인 반려 - if (application.get().getVerifyStatus() == VerifyStatus.REJECTED) { - return new VerifyStatusResponse(SUBMITTED_REJECTED.name(), updateCount); - } - - // 성적 승인 완료 - return new VerifyStatusResponse(SUBMITTED_APPROVED.name(), updateCount); - } - - public enum ApplicationStatusResponse { - NOT_SUBMITTED, // 어떤 것도 제출하지 않음 - COLLEGE_SUBMITTED, // 지망 대학만 제출 - SCORE_SUBMITTED, // 성적만 제출 - SUBMITTED_PENDING, // 성적 인증 대기 중 - SUBMITTED_REJECTED, // 성적 인증 승인 완료 - SUBMITTED_APPROVED // 성적 인증 반려 - } -} 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 f9e1e45b1..1a3aa8df7 100644 --- a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java @@ -66,6 +66,13 @@ public enum ErrorCode { INVALID_POST_LIKE(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 게시글 좋아요입니다."), DUPLICATE_POST_LIKE(HttpStatus.BAD_REQUEST.value(), "이미 좋아요한 게시글입니다."), + // score + INVALID_GPA_SCORE(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 학점입니다."), + INVALID_GPA_SCORE_STATUS(HttpStatus.BAD_REQUEST.value(), "학점이 승인되지 않았습니다."), + INVALID_LANGUAGE_TEST_SCORE(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 어학성적입니다."), + INVALID_LANGUAGE_TEST_SCORE_STATUS(HttpStatus.BAD_REQUEST.value(), "어학성적이 승인되지 않았습니다."), + USER_DO_NOT_HAVE_GPA(HttpStatus.BAD_REQUEST.value(), "해당 유저의 학점을 찾을 수 없음"), + // general JSON_PARSING_FAILED(HttpStatus.BAD_REQUEST.value(), "JSON 파싱을 할 수 없습니다."), JWT_EXCEPTION(HttpStatus.BAD_REQUEST.value(), "JWT 토큰을 처리할 수 없습니다."), diff --git a/src/main/java/com/example/solidconnection/score/controller/ScoreController.java b/src/main/java/com/example/solidconnection/score/controller/ScoreController.java new file mode 100644 index 000000000..7bd0edaf2 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/controller/ScoreController.java @@ -0,0 +1,56 @@ +package com.example.solidconnection.score.controller; + +import com.example.solidconnection.score.dto.*; +import com.example.solidconnection.score.service.ScoreService; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; + +import static com.example.solidconnection.config.swagger.SwaggerConfig.ACCESS_TOKEN; + +@RestController +@RequestMapping("/score") +@RequiredArgsConstructor +@SecurityRequirements +@SecurityRequirement(name = ACCESS_TOKEN) +public class ScoreController { + + private final ScoreService scoreService; + + // 학점을 등록하는 api + @PostMapping("/gpa") + public ResponseEntity submitGpaScore( + Principal principal, + @Valid @RequestBody GpaScoreRequest gpaScoreRequest) { + Long id = scoreService.submitGpaScore(principal.getName(), gpaScoreRequest); + return ResponseEntity.ok(id); + } + + // 어학성적을 등록하는 api + @PostMapping("/languageTest") + public ResponseEntity submitLanguageTestScore( + Principal principal, + @Valid @RequestBody LanguageTestScoreRequest languageTestScoreRequest) { + Long id = scoreService.submitLanguageTestScore(principal.getName(), languageTestScoreRequest); + return ResponseEntity.ok(id); + } + + // 학점 상태를 확인하는 api + @GetMapping("/gpa") + public ResponseEntity getGpaScoreStatus(Principal principal) { + GpaScoreStatusResponse gpaScoreStatus = scoreService.getGpaScoreStatus(principal.getName()); + return ResponseEntity.ok(gpaScoreStatus); + } + + // 어학 성적 상태를 확인하는 api + @GetMapping("/languageTest") + public ResponseEntity getLanguageTestScoreStatus(Principal principal) { + LanguageTestScoreStatusResponse languageTestScoreStatus = scoreService.getLanguageTestScoreStatus(principal.getName()); + return ResponseEntity.ok(languageTestScoreStatus); + } +} diff --git a/src/main/java/com/example/solidconnection/score/domain/GpaScore.java b/src/main/java/com/example/solidconnection/score/domain/GpaScore.java new file mode 100644 index 000000000..2747f8c88 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/domain/GpaScore.java @@ -0,0 +1,53 @@ +package com.example.solidconnection.score.domain; + +import com.example.solidconnection.application.domain.Gpa; +import com.example.solidconnection.entity.common.BaseEntity; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.type.VerifyStatus; +import jakarta.persistence.*; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDate; + +@Getter +@Entity +@NoArgsConstructor +@EqualsAndHashCode +public class GpaScore extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Embedded + private Gpa gpa; + + private LocalDate issueDate; + + @Setter + @Column(columnDefinition = "varchar(50) not null default 'PENDING'") + @Enumerated(EnumType.STRING) + private VerifyStatus verifyStatus; + + private String rejectedReason; + + @ManyToOne + private SiteUser siteUser; + + public GpaScore(Gpa gpa, SiteUser siteUser, LocalDate issueDate) { + this.gpa = gpa; + this.siteUser = siteUser; + this.issueDate = issueDate; + this.verifyStatus = VerifyStatus.PENDING; + this.rejectedReason = null; + } + + public void setSiteUser(SiteUser siteUser) { + if (this.siteUser != null) { + this.siteUser.getGpaScoreList().remove(this); + } + this.siteUser = siteUser; + siteUser.getGpaScoreList().add(this); + } +} diff --git a/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java b/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java new file mode 100644 index 000000000..bc16bc4e4 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java @@ -0,0 +1,52 @@ +package com.example.solidconnection.score.domain; + +import com.example.solidconnection.application.domain.LanguageTest; +import com.example.solidconnection.entity.common.BaseEntity; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.type.VerifyStatus; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDate; + +@Getter +@Entity +@NoArgsConstructor +@AllArgsConstructor +public class LanguageTestScore extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Embedded + private LanguageTest languageTest; + + private LocalDate issueDate; + + @Setter + @Column(columnDefinition = "varchar(50) not null default 'PENDING'") + @Enumerated(EnumType.STRING) + private VerifyStatus verifyStatus; + + private String rejectedReason; + + @ManyToOne + private SiteUser siteUser; + + public LanguageTestScore(LanguageTest languageTest, LocalDate issueDate, SiteUser siteUser) { + this.languageTest = languageTest; + this.issueDate = issueDate; + this.verifyStatus = VerifyStatus.PENDING; + this.siteUser = siteUser; + } + + public void setSiteUser(SiteUser siteUser) { + if (this.siteUser != null) { + this.siteUser.getLanguageTestScoreList().remove(this); + } + this.siteUser = siteUser; + siteUser.getLanguageTestScoreList().add(this); + } +} diff --git a/src/main/java/com/example/solidconnection/score/dto/GpaScoreRequest.java b/src/main/java/com/example/solidconnection/score/dto/GpaScoreRequest.java new file mode 100644 index 000000000..b655f6143 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/dto/GpaScoreRequest.java @@ -0,0 +1,34 @@ +package com.example.solidconnection.score.dto; + +import com.example.solidconnection.application.domain.Gpa; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import java.time.LocalDate; + +@Schema(description = "대학 성적과 어학 시험 성적") +public record GpaScoreRequest( + @NotNull(message = "학점을 입력해주세요.") + @Schema(description = "GPA", example = "3.5", required = true) + Double gpa, + + @NotNull(message = "학점 기준을 입력해주세요.") + @Schema(description = "GPA 계산 기준", example = "4.0", required = true) + Double gpaCriteria, + + @NotNull(message = "발급일자를 입력해주세요.") + @Schema(description = "발급일자", example = "2024-10-06", required = true) + LocalDate issueDate, + + @NotBlank(message = "대학 성적 증명서를 첨부해주세요.") + @Schema(description = "대학 성적 증명서 URL", example = "http://example.com/gpa-report.pdf", required = true) + String gpaReportUrl) { + + public Gpa toGpa() { + return new Gpa( + this.gpa, + this.gpaCriteria, + this.gpaReportUrl); + } +} diff --git a/src/main/java/com/example/solidconnection/score/dto/GpaScoreStatus.java b/src/main/java/com/example/solidconnection/score/dto/GpaScoreStatus.java new file mode 100644 index 000000000..0361cf0e7 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/dto/GpaScoreStatus.java @@ -0,0 +1,25 @@ +package com.example.solidconnection.score.dto; + +import com.example.solidconnection.application.domain.Gpa; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.type.VerifyStatus; + +import java.time.LocalDate; + +public record GpaScoreStatus( + Long id, + Gpa gpa, + LocalDate issueDate, + VerifyStatus verifyStatus, + String rejectedReason +) { + public static GpaScoreStatus from(GpaScore gpaScore) { + return new GpaScoreStatus( + gpaScore.getId(), + gpaScore.getGpa(), + gpaScore.getIssueDate(), + gpaScore.getVerifyStatus(), + gpaScore.getRejectedReason() + ); + } +} diff --git a/src/main/java/com/example/solidconnection/score/dto/GpaScoreStatusResponse.java b/src/main/java/com/example/solidconnection/score/dto/GpaScoreStatusResponse.java new file mode 100644 index 000000000..06fdba0d3 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/dto/GpaScoreStatusResponse.java @@ -0,0 +1,8 @@ +package com.example.solidconnection.score.dto; + +import java.util.List; + +public record GpaScoreStatusResponse( + List gpaScoreStatusList +) { +} diff --git a/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreRequest.java b/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreRequest.java new file mode 100644 index 000000000..36687b6c2 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreRequest.java @@ -0,0 +1,37 @@ +package com.example.solidconnection.score.dto; + + +import com.example.solidconnection.application.domain.LanguageTest; +import com.example.solidconnection.type.LanguageTestType; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import java.time.LocalDate; + +@Schema(description = "대학 성적과 어학 시험 성적") +public record LanguageTestScoreRequest( + @NotNull(message = "어학 종류를 입력해주세요.") + @Schema(description = "어학 시험 종류", example = "TOEFL", required = true) + LanguageTestType languageTestType, + + @NotBlank(message = "어학 점수를 입력해주세요.") + @Schema(description = "어학 시험 점수", example = "115", required = true) + String languageTestScore, + + @NotNull(message = "발급일자를 입력해주세요.") + @Schema(description = "발급일자", example = "2024-10-06", required = true) + LocalDate issueDate, + + @NotBlank(message = "어학 증명서를 첨부해주세요.") + @Schema(description = "어학 증명서 URL", example = "http://example.com/test-report.pdf", required = true) + String languageTestReportUrl) { + + public LanguageTest toLanguageTest() { + return new LanguageTest( + this.languageTestType, + this.languageTestScore, + this.languageTestReportUrl + ); + } +} diff --git a/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreStatus.java b/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreStatus.java new file mode 100644 index 000000000..2d1d8fcb1 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreStatus.java @@ -0,0 +1,25 @@ +package com.example.solidconnection.score.dto; + +import com.example.solidconnection.application.domain.LanguageTest; +import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.type.VerifyStatus; + +import java.time.LocalDate; + +public record LanguageTestScoreStatus( + Long id, + LanguageTest languageTest, + LocalDate issueDate, + VerifyStatus verifyStatus, + String rejectedReason +) { + public static LanguageTestScoreStatus from(LanguageTestScore languageTestScore) { + return new LanguageTestScoreStatus( + languageTestScore.getId(), + languageTestScore.getLanguageTest(), + languageTestScore.getIssueDate(), + languageTestScore.getVerifyStatus(), + languageTestScore.getRejectedReason() + ); + } +} diff --git a/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreStatusResponse.java b/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreStatusResponse.java new file mode 100644 index 000000000..3d4f74894 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/dto/LanguageTestScoreStatusResponse.java @@ -0,0 +1,9 @@ +package com.example.solidconnection.score.dto; + + +import java.util.List; + +public record LanguageTestScoreStatusResponse( + List languageTestScoreStatusList +) { +} diff --git a/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java b/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java new file mode 100644 index 000000000..c5fbb2847 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java @@ -0,0 +1,15 @@ +package com.example.solidconnection.score.repository; + +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.siteuser.domain.SiteUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface GpaScoreRepository extends JpaRepository { + Optional findGpaScoreBySiteUser(SiteUser siteUser); + + Optional findGpaScoreBySiteUserAndId(SiteUser siteUser, Long id); +} diff --git a/src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java b/src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java new file mode 100644 index 000000000..8e6ca3967 --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java @@ -0,0 +1,17 @@ +package com.example.solidconnection.score.repository; + +import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.type.LanguageTestType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface LanguageTestScoreRepository extends JpaRepository { + + Optional findLanguageTestScoreBySiteUserAndLanguageTest_LanguageTestType(SiteUser siteUser, LanguageTestType languageTestType); + + Optional findLanguageTestScoreBySiteUserAndId(SiteUser siteUser, Long id); +} diff --git a/src/main/java/com/example/solidconnection/score/service/ScoreService.java b/src/main/java/com/example/solidconnection/score/service/ScoreService.java new file mode 100644 index 000000000..b2d9ad29e --- /dev/null +++ b/src/main/java/com/example/solidconnection/score/service/ScoreService.java @@ -0,0 +1,73 @@ +package com.example.solidconnection.score.service; + +import com.example.solidconnection.application.domain.LanguageTest; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.score.dto.*; +import com.example.solidconnection.score.repository.GpaScoreRepository; +import com.example.solidconnection.score.repository.LanguageTestScoreRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ScoreService { + + private final GpaScoreRepository gpaScoreRepository; + private final LanguageTestScoreRepository languageTestScoreRepository; + private final SiteUserRepository siteUserRepository; + + @Transactional + public Long submitGpaScore(String email, GpaScoreRequest gpaScoreRequest) { + SiteUser siteUser = siteUserRepository.getByEmail(email); + + GpaScore newGpaScore = new GpaScore(gpaScoreRequest.toGpa(), siteUser, gpaScoreRequest.issueDate()); + newGpaScore.setSiteUser(siteUser); + GpaScore savedNewGpaScore = gpaScoreRepository.save(newGpaScore); // 저장 후 반환된 객체 + return savedNewGpaScore.getId(); // 저장된 GPA Score의 ID 반환 + } + + @Transactional + public Long submitLanguageTestScore(String email, LanguageTestScoreRequest languageTestScoreRequest) { + SiteUser siteUser = siteUserRepository.getByEmail(email); + LanguageTest languageTest = languageTestScoreRequest.toLanguageTest(); + + LanguageTestScore newScore = new LanguageTestScore( + languageTest, languageTestScoreRequest.issueDate(), siteUser); + newScore.setSiteUser(siteUser); + LanguageTestScore savedNewScore = languageTestScoreRepository.save(newScore); // 새로 저장한 객체 + return savedNewScore.getId(); // 저장된 객체의 ID 반환 + } + + @Transactional(readOnly = true) + public GpaScoreStatusResponse getGpaScoreStatus(String email) { + SiteUser siteUser = siteUserRepository.getByEmail(email); + List gpaScoreStatusList = + Optional.ofNullable(siteUser.getGpaScoreList()) + .map(scores -> scores.stream() + .map(GpaScoreStatus::from) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); + return new GpaScoreStatusResponse(gpaScoreStatusList); + } + + @Transactional(readOnly = true) + public LanguageTestScoreStatusResponse getLanguageTestScoreStatus(String email) { + SiteUser siteUser = siteUserRepository.getByEmail(email); + List languageTestScoreStatusList = + Optional.ofNullable(siteUser.getLanguageTestScoreList()) + .map(scores -> scores.stream() + .map(LanguageTestScoreStatus::from) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); + return new LanguageTestScoreStatusResponse(languageTestScoreStatusList); + } +} diff --git a/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java b/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java index f3c870ceb..47a071b04 100644 --- a/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java +++ b/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java @@ -3,6 +3,8 @@ import com.example.solidconnection.comment.domain.Comment; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.post.domain.PostLike; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.score.domain.LanguageTestScore; import com.example.solidconnection.type.Gender; import com.example.solidconnection.type.PreparationStatus; import com.example.solidconnection.type.Role; @@ -65,6 +67,13 @@ public class SiteUser { @OneToMany(mappedBy = "siteUser", cascade = CascadeType.ALL, orphanRemoval = true) private List postLikeList = new ArrayList<>(); + @OneToMany(mappedBy = "siteUser", cascade = CascadeType.ALL, orphanRemoval = true) + private List languageTestScoreList = new ArrayList<>(); + + @OneToMany(mappedBy = "siteUser", cascade = CascadeType.ALL, orphanRemoval = true) + private List gpaScoreList = new ArrayList<>(); + + public SiteUser( String email, String nickname, diff --git a/src/main/java/com/example/solidconnection/university/domain/University.java b/src/main/java/com/example/solidconnection/university/domain/University.java index c3021385e..8e31dfa4a 100644 --- a/src/main/java/com/example/solidconnection/university/domain/University.java +++ b/src/main/java/com/example/solidconnection/university/domain/University.java @@ -2,12 +2,7 @@ import com.example.solidconnection.entity.Country; import com.example.solidconnection.entity.Region; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java b/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java deleted file mode 100644 index a12612071..000000000 --- a/src/test/java/com/example/solidconnection/e2e/ApplicationSubmissionTest.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.example.solidconnection.e2e; - -import com.example.solidconnection.application.domain.Application; -import com.example.solidconnection.application.dto.ScoreRequest; -import com.example.solidconnection.application.dto.UniversityChoiceRequest; -import com.example.solidconnection.application.repository.ApplicationRepository; -import com.example.solidconnection.config.token.TokenService; -import com.example.solidconnection.config.token.TokenType; -import com.example.solidconnection.custom.response.ErrorResponse; -import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import com.example.solidconnection.type.LanguageTestType; -import com.example.solidconnection.type.VerifyStatus; -import io.restassured.RestAssured; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; - -import static com.example.solidconnection.application.service.ApplicationSubmissionService.APPLICATION_UPDATE_COUNT_LIMIT; -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; -import static com.example.solidconnection.e2e.DynamicFixture.createSiteUserByEmail; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; - -@DisplayName("지원 정보 제출 테스트") -class ApplicationSubmissionTest extends UniversityDataSetUpEndToEndTest { - - @Autowired - private ApplicationRepository applicationRepository; - - @Autowired - private SiteUserRepository siteUserRepository; - - @Autowired - private TokenService tokenService; - - private final String email = "email@email.com"; - private String accessToken; - private SiteUser siteUser; - - @BeforeEach - public void setUpUserAndToken() { - // setUp - 회원 정보 저장 - siteUser = siteUserRepository.save(createSiteUserByEmail(email)); - - // setUp - 엑세스 토큰 생성과 리프레시 토큰 생성 및 저장 - accessToken = tokenService.generateToken(email, TokenType.ACCESS); - String refreshToken = tokenService.generateToken(email, TokenType.REFRESH); - tokenService.saveToken(refreshToken, TokenType.REFRESH); - } - - @Test - void 대학교_성적과_어학성적을_처음으로_제출한다() { - // request - body 생성 및 요청 - ScoreRequest request = new ScoreRequest(LanguageTestType.TOEFL_IBT, "80", - "languageTestReportUrl", 4.0, 4.5, "gpaReportUrl"); - RestAssured.given() - .header("Authorization", "Bearer " + accessToken) - .body(request) - .contentType("application/json") - .log().all() - .post("/application/score") - .then().log().all() - .statusCode(HttpStatus.OK.value()); - - Application application = applicationRepository.getApplicationBySiteUserAndTerm(siteUser,term); - assertAll("대학교 성적과 어학 성적을 저장한다.", - () -> assertThat(application.getId()).isNotNull(), - () -> assertThat(application.getSiteUser().getId()).isEqualTo(siteUser.getId()), - () -> assertThat(application.getLanguageTest().getLanguageTestType()).isEqualTo(request.languageTestType()), - () -> assertThat(application.getLanguageTest().getLanguageTestScore()).isEqualTo(request.languageTestScore()), - () -> assertThat(application.getLanguageTest().getLanguageTestReportUrl()).isEqualTo(request.languageTestReportUrl()), - () -> assertThat(application.getGpa().getGpa()).isEqualTo(request.gpa()), - () -> assertThat(application.getGpa().getGpaReportUrl()).isEqualTo(request.gpaReportUrl()), - () -> assertThat(application.getVerifyStatus()).isEqualTo(VerifyStatus.PENDING), - () -> assertThat(application.getUpdateCount()).isZero()); - } - - @Test - void 대학교_성적과_어학성적을_다시_제출한다() { - // setUp - 성적 정보 저장 - ScoreRequest firstRequest = new ScoreRequest(LanguageTestType.TOEFL_IBT, "80", - "languageTestReportUrl", 4.0, 4.5, "gpaReportUrl"); - applicationRepository.save(new Application(siteUser, firstRequest.toGpa(), firstRequest.toLanguageTest(),term)); - - // request - body 생성 및 요청 - ScoreRequest secondRequest = new ScoreRequest(LanguageTestType.TOEFL_IBT, "90", - "languageTestReportUrl", 4.1, 4.5, "gpaReportUrl"); - RestAssured.given() - .header("Authorization", "Bearer " + accessToken) - .body(secondRequest) - .contentType("application/json") - .log().all() - .post("/application/score") - .then().log().all() - .statusCode(HttpStatus.OK.value()); - - Application updatedApplication = applicationRepository.getApplicationBySiteUserAndTerm(siteUser,term); - assertAll("대학교 성적과 어학 성적을 수정한다. 이때 수정 횟수는 증가하지 않고, 성적 승인 상태는 PENDING 으로 바뀐다.", - () -> assertThat(updatedApplication.getId()).isNotNull(), - () -> assertThat(updatedApplication.getSiteUser().getId()).isEqualTo(siteUser.getId()), - () -> assertThat(updatedApplication.getLanguageTest().getLanguageTestType()).isEqualTo(secondRequest.languageTestType()), - () -> assertThat(updatedApplication.getLanguageTest().getLanguageTestScore()).isEqualTo(secondRequest.languageTestScore()), - () -> assertThat(updatedApplication.getLanguageTest().getLanguageTestReportUrl()).isEqualTo(secondRequest.languageTestReportUrl()), - () -> assertThat(updatedApplication.getGpa().getGpa()).isEqualTo(secondRequest.gpa()), - () -> assertThat(updatedApplication.getGpa().getGpaReportUrl()).isEqualTo(secondRequest.gpaReportUrl()), - () -> assertThat(updatedApplication.getVerifyStatus()).isEqualTo(VerifyStatus.PENDING), - () -> assertThat(updatedApplication.getUpdateCount()).isZero()); - } - - @Test - void 성적_제출_후_지망_대학을_제출한다() { - // setUp - 성적 정보 저장 - ScoreRequest firstRequest = new ScoreRequest(LanguageTestType.TOEFL_IBT, "80", - "languageTestReportUrl", 4.0, 4.5, "gpaReportUrl"); - applicationRepository.save(new Application(siteUser, firstRequest.toGpa(), firstRequest.toLanguageTest(),term)); - - // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); - RestAssured.given() - .header("Authorization", "Bearer " + accessToken) - .body(request) - .contentType("application/json") - .log().all() - .post("/application/university") - .then().log().all() - .statusCode(HttpStatus.OK.value()); - - Application application = applicationRepository.getApplicationBySiteUserAndTerm(siteUser,term); - assertAll("지망 대학교를 저장한다.", - () -> assertThat(application.getId()).isNotNull(), - () -> 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()); - } - - @Test - void 지망_대학을_수정한다() { - // setUp - 성적 정보와 지망 대학 저장 - ScoreRequest firstRequest = new ScoreRequest(LanguageTestType.TOEFL_IBT, "80", - "languageTestReportUrl", 4.0, 4.5, "gpaReportUrl"); - applicationRepository.save(new Application(siteUser, firstRequest.toGpa(), firstRequest.toLanguageTest(),term)) - .updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "nickname"); - Application initialApplication = applicationRepository.getApplicationBySiteUserAndTerm(siteUser,term); - - // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); - RestAssured.given() - .header("Authorization", "Bearer " + accessToken) - .body(request) - .contentType("application/json") - .log().all() - .post("/application/university") - .then().log().all() - .statusCode(HttpStatus.OK.value()); - - Application updatedApplication = applicationRepository.getApplicationBySiteUserAndTerm(siteUser,term); - assertAll("지망 대학교를 수정한다. 이때 수정 횟수는 증가하고, 성적 승인 상태는 바뀌지 않는다.", - () -> assertThat(updatedApplication.getId()).isNotNull(), - () -> 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())); - } - - @Test - void 지망_대학을_최대_수정_가능_횟수보다_더_수정하려고하면_예외_응답을_반환한다() { - // setUp - 성적 정보와 지망 대학 저장 - ScoreRequest firstRequest = new ScoreRequest(LanguageTestType.TOEFL_IBT, "80", - "languageTestReportUrl", 4.0, 4.5, "gpaReportUrl"); - applicationRepository.save(new Application(siteUser, firstRequest.toGpa(), firstRequest.toLanguageTest(),term)); - Application initialApplication = applicationRepository.getApplicationBySiteUserAndTerm(siteUser,term); - - // setUp - 지망 대학을 한계까지 수정 - for (int i = 0; i <= APPLICATION_UPDATE_COUNT_LIMIT; i++) { - initialApplication.updateUniversityChoice(괌대학_A_지원_정보, 괌대학_B_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "nickname"); - applicationRepository.save(initialApplication); - } - - // request - body 생성 및 요청 - UniversityChoiceRequest request = new UniversityChoiceRequest(그라츠대학_지원_정보.getId(), 코펜하겐IT대학_지원_정보.getId(), 메이지대학_지원_정보.getId()); - ErrorResponse errorResponse = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .body(request) - .contentType("application/json") - .post("/application/university") - .then().log().all() - .statusCode(HttpStatus.BAD_REQUEST.value()) - .extract().as(ErrorResponse.class); - - assertThat(errorResponse.message()).isEqualTo(APPLY_UPDATE_LIMIT_EXCEED.getMessage()); - } - - @Test - void 일지망_대학과_이지망_대학이_같으면_예외_응답을_반환한다() { - // request - body 생성 및 요청 - 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) - .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()); - } -} diff --git a/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java b/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java deleted file mode 100644 index 856c4cdca..000000000 --- a/src/test/java/com/example/solidconnection/e2e/VerifyStatusQueryTest.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.example.solidconnection.e2e; - -import com.example.solidconnection.application.domain.Application; -import com.example.solidconnection.application.dto.VerifyStatusResponse; -import com.example.solidconnection.application.repository.ApplicationRepository; -import com.example.solidconnection.config.token.TokenService; -import com.example.solidconnection.config.token.TokenType; -import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import com.example.solidconnection.type.VerifyStatus; -import io.restassured.RestAssured; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import static com.example.solidconnection.e2e.DynamicFixture.createDummyGpa; -import static com.example.solidconnection.e2e.DynamicFixture.createDummyLanguageTest; -import static com.example.solidconnection.e2e.DynamicFixture.createSiteUserByEmail; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; - -@DisplayName("지원 상태 조회 테스트") -class VerifyStatusQueryTest extends UniversityDataSetUpEndToEndTest { - - @Autowired - private SiteUserRepository siteUserRepository; - - @Autowired - private TokenService tokenService; - - @Autowired - private ApplicationRepository applicationRepository; - - private String accessToken; - private SiteUser siteUser; - - @BeforeEach - public void setUpUserAndToken() { - // setUp - 회원 정보 저장 - String email = "email@email.com"; - siteUser = siteUserRepository.save(createSiteUserByEmail(email)); - - // setUp - 엑세스 토큰 생성과 리프레시 토큰 생성 및 저장 - accessToken = tokenService.generateToken(email, TokenType.ACCESS); - String refreshToken = tokenService.generateToken(email, TokenType.REFRESH); - tokenService.saveToken(refreshToken, TokenType.REFRESH); - } - - @Test - void 아무것도_제출하지_않은_상태를_반환한다() { - // request - 요청 - VerifyStatusResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().get("/application/status") - .then().log().all() - .statusCode(200) - .extract().as(VerifyStatusResponse.class); - - assertAll( - () -> assertThat(response.status()).isEqualTo("NOT_SUBMITTED"), - () -> assertThat(response.updateCount()).isZero() - ); - } - - @Test - void 성적만_제출한_상태를_반환한다() { - // setUp - 성적만 제출한 상태 - Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest(),term); - applicationRepository.save(application); - - // request - 요청 - VerifyStatusResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().get("/application/status") - .then().log().all() - .statusCode(200) - .extract().as(VerifyStatusResponse.class); - - assertAll( - () -> assertThat(response.status()).isEqualTo("SCORE_SUBMITTED"), - () -> assertThat(response.updateCount()).isZero() - ); - } - - @Test - void 성적과_대학을_모두_제출하고_승인을_기대라는_상태를_반환한다() { - // setUp - 성적과 대학을 모두 제출한 상태 - Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest(),term); - application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "닉네임"); - applicationRepository.save(application); - - // request - 요청 - VerifyStatusResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().get("/application/status") - .then().log().all() - .statusCode(200) - .extract().as(VerifyStatusResponse.class); - - assertAll( - () -> assertThat(response.status()).isEqualTo("SUBMITTED_PENDING"), - () -> assertThat(response.updateCount()).isZero() - ); - } - - @Test - void 성적과_대학을_모두_제출했지만_승인이_반려된_상태를_반환한다() { - // setUp - 성적과 대학을 모두 제출했지만, 승인 거절 - Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest(),term); - application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 네바다주립대학_라스베이거스_지원_정보,"닉네임"); - application.setVerifyStatus(VerifyStatus.REJECTED); - applicationRepository.save(application); - - // request - 요청 - VerifyStatusResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().get("/application/status") - .then().log().all() - .statusCode(200) - .extract().as(VerifyStatusResponse.class); - - assertAll( - () -> assertThat(response.status()).isEqualTo("SUBMITTED_REJECTED"), - () -> assertThat(response.updateCount()).isZero() - ); - } - - @Test - void 성적과_대학을_모두_제출했으며_승인이_된_상태를_반환한다() { - // setUp - 성적과 대학을 모두 제출했으며, 승인이 된 상태 - Application application = new Application(siteUser, createDummyGpa(), createDummyLanguageTest(),term); - application.updateUniversityChoice(괌대학_B_지원_정보, 괌대학_A_지원_정보, 네바다주립대학_라스베이거스_지원_정보, "닉네임"); - application.setVerifyStatus(VerifyStatus.APPROVED); - applicationRepository.save(application); - - // request - 요청 - VerifyStatusResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().get("/application/status") - .then().log().all() - .statusCode(200) - .extract().as(VerifyStatusResponse.class); - - assertAll( - () -> assertThat(response.status()).isEqualTo("SUBMITTED_APPROVED"), - () -> assertThat(response.updateCount()).isZero() - ); - } -} diff --git a/src/test/java/com/example/solidconnection/unit/repository/GpaScoreRepositoryTest.java b/src/test/java/com/example/solidconnection/unit/repository/GpaScoreRepositoryTest.java new file mode 100644 index 000000000..e3fa680c2 --- /dev/null +++ b/src/test/java/com/example/solidconnection/unit/repository/GpaScoreRepositoryTest.java @@ -0,0 +1,93 @@ +package com.example.solidconnection.unit.repository; + +import com.example.solidconnection.application.domain.Gpa; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.score.repository.GpaScoreRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.type.Gender; +import com.example.solidconnection.type.PreparationStatus; +import com.example.solidconnection.type.Role; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@ActiveProfiles("test") +@DisplayName("학점 레포지토리 테스트") +@Transactional +public class GpaScoreRepositoryTest { + @Autowired + private SiteUserRepository siteUserRepository; + @Autowired + private GpaScoreRepository gpaScoreRepository; + + private SiteUser siteUser; + + @BeforeEach + public void setUp() { + siteUser = createSiteUser(); + siteUserRepository.save(siteUser); + } + + private SiteUser createSiteUser() { + return new SiteUser( + "test@example.com", + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + } + + @Test + public void 사용자의_학점을_조회한다_기존이력_없을_때() { + Optional gpaScoreBySiteUser = gpaScoreRepository.findGpaScoreBySiteUser(siteUser); + assertThat(gpaScoreBySiteUser).isEqualTo(Optional.empty()); + } + + @Test + public void 사용자의_학점을_조회한다_기존이력_있을_때() { + GpaScore gpaScore = new GpaScore( + new Gpa(4.5, 4.5, "http://example.com/gpa-report.pdf"), + siteUser, + LocalDate.of(2024, 10, 10) + ); + gpaScore.setSiteUser(siteUser); + gpaScoreRepository.save(gpaScore); + + Optional gpaScoreBySiteUser = gpaScoreRepository.findGpaScoreBySiteUser(siteUser); + assertThat(gpaScoreBySiteUser).isEqualTo(Optional.of(gpaScore)); + } + + @Test + public void 아이디와_사용자정보로_사용자의_학점을_조회한다_기존이력_없을_때() { + Optional gpaScoreBySiteUser = gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, 1L); + assertThat(gpaScoreBySiteUser).isEqualTo(Optional.empty()); + } + + @Test + public void 아이디와_사용자정보로_사용자의_학점을_조회한다_기존이력_있을_때() { + GpaScore gpaScore = new GpaScore( + new Gpa(4.5, 4.5, "http://example.com/gpa-report.pdf"), + siteUser, + LocalDate.of(2024, 10, 10) + ); + gpaScore.setSiteUser(siteUser); + gpaScoreRepository.save(gpaScore); + + Optional gpaScoreBySiteUser = gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScore.getId()); + assertThat(gpaScoreBySiteUser).isEqualTo(Optional.of(gpaScore)); + } +} diff --git a/src/test/java/com/example/solidconnection/unit/repository/LanguageTestScoreRepositoryTest.java b/src/test/java/com/example/solidconnection/unit/repository/LanguageTestScoreRepositoryTest.java new file mode 100644 index 000000000..7369f20fa --- /dev/null +++ b/src/test/java/com/example/solidconnection/unit/repository/LanguageTestScoreRepositoryTest.java @@ -0,0 +1,98 @@ +package com.example.solidconnection.unit.repository; + +import com.example.solidconnection.application.domain.LanguageTest; +import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.score.repository.LanguageTestScoreRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.type.Gender; +import com.example.solidconnection.type.LanguageTestType; +import com.example.solidconnection.type.PreparationStatus; +import com.example.solidconnection.type.Role; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@ActiveProfiles("test") +@DisplayName("어학성적 레포지토리 테스트") +@Transactional +public class LanguageTestScoreRepositoryTest { + @Autowired + private SiteUserRepository siteUserRepository; + @Autowired + private LanguageTestScoreRepository languageTestScoreRepository; + + private SiteUser siteUser; + + @BeforeEach + public void setUp() { + siteUser = createSiteUser(); + siteUserRepository.save(siteUser); + } + + private SiteUser createSiteUser() { + return new SiteUser( + "test@example.com", + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + } + + @Test + public void 사용자의_어학성적을_조회한다_기존이력_없을_때() { + Optional languageTestScore = languageTestScoreRepository + .findLanguageTestScoreBySiteUserAndLanguageTest_LanguageTestType(siteUser, LanguageTestType.TOEIC); + assertThat(languageTestScore).isEqualTo(Optional.empty()); + } + + @Test + public void 사용자의_어학성적을_조회한다_기존이력_있을_때() { + LanguageTestScore languageTestScore = new LanguageTestScore( + new LanguageTest(LanguageTestType.TOEIC, "990", "http://example.com/gpa-report.pdf"), + LocalDate.of(2024, 10, 10), + siteUser + ); + languageTestScore.setSiteUser(siteUser); + languageTestScoreRepository.save(languageTestScore); + + Optional languageTestScore1 = languageTestScoreRepository + .findLanguageTestScoreBySiteUserAndLanguageTest_LanguageTestType(siteUser, LanguageTestType.TOEIC); + assertThat(languageTestScore1).isEqualTo(Optional.of(languageTestScore)); + } + + @Test + public void 아이디와_사용자정보로_사용자의_어학성적을_조회한다_기존이력_없을_때() { + Optional languageTestScore = languageTestScoreRepository + .findLanguageTestScoreBySiteUserAndId(siteUser, 1L); + assertThat(languageTestScore).isEqualTo(Optional.empty()); + } + + @Test + public void 아이디와_사용자정보로_사용자의_어학성적을_조회한다_기존이력_있을_때() { + LanguageTestScore languageTestScore = new LanguageTestScore( + new LanguageTest(LanguageTestType.TOEIC, "990", "http://example.com/gpa-report.pdf"), + LocalDate.of(2024, 10, 10), + siteUser + ); + languageTestScore.setSiteUser(siteUser); + languageTestScoreRepository.save(languageTestScore); + + Optional languageTestScore1 = languageTestScoreRepository + .findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScore.getId()); + assertThat(languageTestScore1).isEqualTo(Optional.of(languageTestScore)); + } +} diff --git a/src/test/java/com/example/solidconnection/unit/service/ApplicationServiceTest.java b/src/test/java/com/example/solidconnection/unit/service/ApplicationServiceTest.java index 7688478fc..dd87a383f 100644 --- a/src/test/java/com/example/solidconnection/unit/service/ApplicationServiceTest.java +++ b/src/test/java/com/example/solidconnection/unit/service/ApplicationServiceTest.java @@ -3,11 +3,16 @@ import com.example.solidconnection.application.domain.Application; import com.example.solidconnection.application.domain.Gpa; import com.example.solidconnection.application.domain.LanguageTest; -import com.example.solidconnection.application.dto.ScoreRequest; +import com.example.solidconnection.application.dto.ApplyRequest; import com.example.solidconnection.application.dto.UniversityChoiceRequest; import com.example.solidconnection.application.repository.ApplicationRepository; import com.example.solidconnection.application.service.ApplicationSubmissionService; import com.example.solidconnection.custom.exception.CustomException; +import com.example.solidconnection.custom.exception.ErrorCode; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.score.repository.GpaScoreRepository; +import com.example.solidconnection.score.repository.LanguageTestScoreRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; import com.example.solidconnection.type.*; @@ -16,19 +21,15 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.beans.factory.annotation.Value; +import java.time.LocalDate; import java.util.Optional; -import static com.example.solidconnection.custom.exception.ErrorCode.CANT_APPLY_FOR_SAME_UNIVERSITY; -import static com.example.solidconnection.custom.exception.ErrorCode.SCORE_SHOULD_SUBMITTED_FIRST; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -41,27 +42,28 @@ public class ApplicationServiceTest { @Mock ApplicationRepository applicationRepository; @Mock + UniversityInfoForApplyRepository universityInfoForApplyRepository; + @Mock SiteUserRepository siteUserRepository; @Mock - UniversityInfoForApplyRepository universityInfoForApplyRepository; + GpaScoreRepository gpaScoreRepository; + @Mock + LanguageTestScoreRepository languageTestScoreRepository; + @Value("${university.term}") + private String term; private SiteUser siteUser; - private Application application; - private Application applicationBeforeTerm; - - private String term = "2024-1"; - private String beforeTerm = "1999-1"; + private GpaScore gpaScore; + private LanguageTestScore languageTestScore; + private final long gpaScoreId = 1L; + private final long languageTestScoreId = 1L; + private final long firstChoiceUniversityId = 1L; + private final long secondChoiceUniversityId = 2L; + private final long thirdChoiceUniversityId = 3L; @BeforeEach void setUp() { - ReflectionTestUtils.setField(applicationSubmissionService, "term", term); // 테스트시 @value값 주입위함 - siteUser = createSiteUser(); - application = createApplication(term); - applicationBeforeTerm = createApplication(beforeTerm); - } - - private SiteUser createSiteUser() { - return new SiteUser( + siteUser = new SiteUser( "test@example.com", "nickname", "profileImageUrl", @@ -70,154 +72,188 @@ private SiteUser createSiteUser() { Role.MENTEE, Gender.MALE ); - } - - private Application createApplication(String term) { - return new Application( + gpaScore = new GpaScore( + new Gpa(4.3, 4.5, "gpaScoreUrl"), siteUser, - new Gpa(4.0, 4.5, "url"), - new LanguageTest(LanguageTestType.TOEIC, "900", "url"), - term + LocalDate.of(2024, 10, 30) + ); + languageTestScore = new LanguageTestScore( + new LanguageTest(LanguageTestType.TOEIC, "990", "languageTestScoreUrl"), + LocalDate.of(2024, 10, 30), + siteUser ); } @Test - void 성적을_제출한다_금학기_제출이력_없음() { + void 지원한다_기존_이력_없음() { // Given - ScoreRequest scoreRequest = new ScoreRequest( - LanguageTestType.TOEIC, "990", "url", 4.5, 4.5, "url" + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, secondChoiceUniversityId, thirdChoiceUniversityId) ); when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + gpaScore.setVerifyStatus(VerifyStatus.APPROVED); + when(gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScoreId)).thenReturn(Optional.of(gpaScore)); + languageTestScore.setVerifyStatus(VerifyStatus.APPROVED); + when(languageTestScoreRepository.findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScoreId)).thenReturn(Optional.of(languageTestScore)); when(applicationRepository.findBySiteUserAndTerm(siteUser, term)).thenReturn(Optional.empty()); // When - applicationSubmissionService.submitScore(siteUser.getEmail(), scoreRequest); + boolean result = applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); // Then + assertThat(result).isEqualTo(true); verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); - verify(applicationRepository, times(1)).findBySiteUserAndTerm(siteUser, term); + verify(gpaScoreRepository, times(1)).findGpaScoreBySiteUserAndId(siteUser, gpaScoreId); + verify(languageTestScoreRepository, times(1)).findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScoreId); verify(applicationRepository, times(1)).save(any(Application.class)); } @Test - void 성적을_제출한다_금학기_제출이력_있음() { + void 지원한다_기존_이력_있음() { // Given - ScoreRequest scoreRequest = new ScoreRequest( - LanguageTestType.TOEIC, "990", "url", 4.5, 4.5, "url" + Application beforeApplication = new Application( + siteUser, + new Gpa(4.5, 4.5, "beforeGpaScoreUrl"), + new LanguageTest(LanguageTestType.TOEIC, "900", "beforeLanguageTestUrl"), + term + ); + beforeApplication.setVerifyStatus(VerifyStatus.APPROVED); + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, secondChoiceUniversityId, thirdChoiceUniversityId) ); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); - when(applicationRepository.findBySiteUserAndTerm(siteUser, term)).thenReturn(Optional.of(application)); + gpaScore.setVerifyStatus(VerifyStatus.APPROVED); + when(gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, 1L)).thenReturn(Optional.of(gpaScore)); + languageTestScore.setVerifyStatus(VerifyStatus.APPROVED); + when(languageTestScoreRepository.findLanguageTestScoreBySiteUserAndId(siteUser, 1L)).thenReturn(Optional.of(languageTestScore)); + when(applicationRepository.findBySiteUserAndTerm(siteUser, term)).thenReturn(Optional.of(beforeApplication)); // When - applicationSubmissionService.submitScore(siteUser.getEmail(), scoreRequest); + boolean result = applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); // Then - assertEquals(application.getGpa().getGpa(), scoreRequest.gpa()); - assertEquals(application.getLanguageTest().getLanguageTestScore(), scoreRequest.languageTestScore()); + assertThat(result).isEqualTo(true); verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + verify(gpaScoreRepository, times(1)).findGpaScoreBySiteUserAndId(siteUser, gpaScoreId); + verify(languageTestScoreRepository, times(1)).findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScoreId); verify(applicationRepository, times(1)).findBySiteUserAndTerm(siteUser, term); - verify(applicationRepository, times(0)).save(any(Application.class)); + verify(universityInfoForApplyRepository, times(1)).getUniversityInfoForApplyByIdAndTerm(firstChoiceUniversityId, term); + verify(universityInfoForApplyRepository, times(1)).getUniversityInfoForApplyByIdAndTerm(secondChoiceUniversityId, term); + verify(universityInfoForApplyRepository, times(1)).getUniversityInfoForApplyByIdAndTerm(thirdChoiceUniversityId, term); + verify(applicationRepository, times(1)).save(any(Application.class)); } - /** - * 지망대학 제출 - */ @Test - void 지망대학_제출할_때_성적_제출이력이_없다면_예외_응답을_반환한다() { + void 지원할_때_존재하지_않는_학점이라면_예외_응답을_반환한다() { // given - UniversityChoiceRequest universityChoiceRequest = new UniversityChoiceRequest( - 1L, 2L, 3L + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, secondChoiceUniversityId, thirdChoiceUniversityId) ); - when(applicationRepository.findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail())) - .thenReturn(Optional.empty()); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScoreId)).thenReturn(Optional.empty()); // when, then CustomException exception = assertThrows(CustomException.class, () -> { - applicationSubmissionService.submitUniversityChoice(siteUser.getEmail(), universityChoiceRequest); + applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); }); assertThat(exception.getMessage()) - .isEqualTo(SCORE_SHOULD_SUBMITTED_FIRST.getMessage()); + .isEqualTo(ErrorCode.INVALID_GPA_SCORE.getMessage()); assertThat(exception.getCode()) - .isEqualTo(SCORE_SHOULD_SUBMITTED_FIRST.getCode()); + .isEqualTo(ErrorCode.INVALID_GPA_SCORE.getCode()); } @Test - void 지망대학_제출한다_이전학기_성적_제출이력_있음() { - // Given - UniversityChoiceRequest universityChoiceRequest = new UniversityChoiceRequest( - 1L, 2L, 3L + void 지원할_때_승인되지_않은_학점이라면_예외_응답을_반환한다() { + // given + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, secondChoiceUniversityId, thirdChoiceUniversityId) ); - when(applicationRepository.findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail())) - .thenReturn(Optional.of(applicationBeforeTerm)); when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + gpaScore.setVerifyStatus(VerifyStatus.REJECTED); + when(gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScoreId)).thenReturn(Optional.of(gpaScore)); - // When - applicationSubmissionService.submitUniversityChoice(siteUser.getEmail(), universityChoiceRequest); - - // Then - verify(applicationRepository, times(1)).findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail()); - verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); - verify(applicationRepository, times(1)).save(any(Application.class)); + // when, then + CustomException exception = assertThrows(CustomException.class, () -> { + applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); + }); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.INVALID_GPA_SCORE_STATUS.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.INVALID_GPA_SCORE_STATUS.getCode()); } @Test - void 지망대학_제출한다_금학기_성적_제출이력_있음() { - // Given - UniversityChoiceRequest universityChoiceRequest = new UniversityChoiceRequest( - 1L, 2L, 3L + void 지원할_때_존재하지_않는_어학성적이라면_예외_응답을_반환한다() { + // given + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, secondChoiceUniversityId, thirdChoiceUniversityId) ); - when(applicationRepository.findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail())) - .thenReturn(Optional.of(application)); - - // When - applicationSubmissionService.submitUniversityChoice(siteUser.getEmail(), universityChoiceRequest); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + gpaScore.setVerifyStatus(VerifyStatus.APPROVED); + when(gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScoreId)).thenReturn(Optional.of(gpaScore)); + when(languageTestScoreRepository.findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScoreId)).thenReturn(Optional.empty()); - // Then - verify(applicationRepository, times(1)).findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail()); - verify(siteUserRepository, times(0)).getByEmail(siteUser.getEmail()); - verify(applicationRepository, times(0)).save(any(Application.class)); + // when, then + CustomException exception = assertThrows(CustomException.class, () -> { + applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); + }); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.INVALID_LANGUAGE_TEST_SCORE.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.INVALID_LANGUAGE_TEST_SCORE.getCode()); } - @ParameterizedTest - @CsvSource({ - "1, 2, 3", - "1, , 3", - "1, 2, ", - "1, , " - }) - void 지망대학_제출할_때_2지망과_3지망은_NULL_허용한다(Long firstChoice, Long secondChoice, Long thirdChoice) { - // Given - UniversityChoiceRequest universityChoiceRequest = new UniversityChoiceRequest(firstChoice, secondChoice, thirdChoice); - when(applicationRepository.findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail())) - .thenReturn(Optional.of(application)); - - // When - applicationSubmissionService.submitUniversityChoice(siteUser.getEmail(), universityChoiceRequest); + @Test + void 지원할_때_승인되지_않은_어학성적이라면_예외_응답을_반환한다() { + // given + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, secondChoiceUniversityId, thirdChoiceUniversityId) + ); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + gpaScore.setVerifyStatus(VerifyStatus.APPROVED); + when(gpaScoreRepository.findGpaScoreBySiteUserAndId(siteUser, gpaScoreId)).thenReturn(Optional.of(gpaScore)); + languageTestScore.setVerifyStatus(VerifyStatus.REJECTED); + when(languageTestScoreRepository.findLanguageTestScoreBySiteUserAndId(siteUser, languageTestScoreId)).thenReturn(Optional.of(languageTestScore)); - // Then - verify(applicationRepository, times(1)).findTop1BySiteUser_EmailOrderByTermDesc(siteUser.getEmail()); - verify(siteUserRepository, times(0)).getByEmail(siteUser.getEmail()); - verify(applicationRepository, times(0)).save(any(Application.class)); + // when, then + CustomException exception = assertThrows(CustomException.class, () -> { + applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); + }); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.INVALID_LANGUAGE_TEST_SCORE_STATUS.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.INVALID_LANGUAGE_TEST_SCORE_STATUS.getCode()); } - @ParameterizedTest - @CsvSource({ - "1, 1, 1", - "1, 2, 1", - "1, 1, 2", - "1, , 1", - "1, 1, " - }) - void 지망대학_제출할_때_선택지가_중복된다면_예외_응답을_반환한다(Long firstChoice, Long secondChoice, Long thirdChoice) { + @Test + void 지원할_때_학교_선택이_중복되면_예외_응답을_반환한다() { // given - UniversityChoiceRequest universityChoiceRequest = new UniversityChoiceRequest(firstChoice, secondChoice, thirdChoice); + ApplyRequest applyRequest = new ApplyRequest( + gpaScoreId, + languageTestScoreId, + new UniversityChoiceRequest(firstChoiceUniversityId, firstChoiceUniversityId, firstChoiceUniversityId) + ); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); // when, then CustomException exception = assertThrows(CustomException.class, () -> { - applicationSubmissionService.submitUniversityChoice(siteUser.getEmail(), universityChoiceRequest); + applicationSubmissionService.apply(siteUser.getEmail(), applyRequest); }); assertThat(exception.getMessage()) - .isEqualTo(CANT_APPLY_FOR_SAME_UNIVERSITY.getMessage()); + .isEqualTo(ErrorCode.CANT_APPLY_FOR_SAME_UNIVERSITY.getMessage()); assertThat(exception.getCode()) - .isEqualTo(CANT_APPLY_FOR_SAME_UNIVERSITY.getCode()); + .isEqualTo(ErrorCode.CANT_APPLY_FOR_SAME_UNIVERSITY.getCode()); } } diff --git a/src/test/java/com/example/solidconnection/unit/service/ScoreServiceTest.java b/src/test/java/com/example/solidconnection/unit/service/ScoreServiceTest.java new file mode 100644 index 000000000..39deadb54 --- /dev/null +++ b/src/test/java/com/example/solidconnection/unit/service/ScoreServiceTest.java @@ -0,0 +1,201 @@ +package com.example.solidconnection.unit.service; + +import com.example.solidconnection.application.domain.Gpa; +import com.example.solidconnection.application.domain.LanguageTest; +import com.example.solidconnection.score.domain.GpaScore; +import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.score.dto.*; +import com.example.solidconnection.score.repository.GpaScoreRepository; +import com.example.solidconnection.score.repository.LanguageTestScoreRepository; +import com.example.solidconnection.score.service.ScoreService; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.type.Gender; +import com.example.solidconnection.type.LanguageTestType; +import com.example.solidconnection.type.PreparationStatus; +import com.example.solidconnection.type.Role; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDate; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@DisplayName("점수 서비스 테스트") +public class ScoreServiceTest { + @InjectMocks + ScoreService scoreService; + @Mock + GpaScoreRepository gpaScoreRepository; + @Mock + LanguageTestScoreRepository languageTestScoreRepository; + @Mock + SiteUserRepository siteUserRepository; + + private SiteUser siteUser; + private GpaScore beforeGpaScore; + private GpaScore beforeGpaScore2; + private LanguageTestScore beforeLanguageTestScore; + private LanguageTestScore beforeLanguageTestScore2; + + @BeforeEach + void setUp() { + siteUser = createSiteUser(); + beforeGpaScore = createBeforeGpaScore(siteUser, 4.5); + beforeGpaScore2 = createBeforeGpaScore(siteUser, 4.3); + beforeLanguageTestScore = createBeforeLanguageTestScore(siteUser); + beforeLanguageTestScore2 = createBeforeLanguageTestScore2(siteUser); + } + + private SiteUser createSiteUser() { + return new SiteUser( + "test@example.com", + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + } + + private GpaScore createBeforeGpaScore(SiteUser siteUser, Double gpa) { + return new GpaScore( + new Gpa(gpa, 4.5, "http://example.com/gpa-report.pdf"), + siteUser, + LocalDate.of(2024, 10, 20) + ); + } + + private LanguageTestScore createBeforeLanguageTestScore(SiteUser siteUser) { + return new LanguageTestScore( + new LanguageTest(LanguageTestType.TOEIC, "900", "http://example.com/gpa-report.pdf"), + LocalDate.of(2024, 10, 30), + siteUser + ); + } + + private LanguageTestScore createBeforeLanguageTestScore2(SiteUser siteUser) { + return new LanguageTestScore( + new LanguageTest(LanguageTestType.TOEFL_IBT, "100", "http://example.com/gpa-report.pdf"), + LocalDate.of(2024, 10, 30), + siteUser + ); + } + + @Test + void 학점을_등록한다_기존이력이_없을_때() { + // Given + GpaScoreRequest gpaScoreRequest = new GpaScoreRequest( + 4.5, 4.5, LocalDate.of(2024, 10, 20), "http://example.com/gpa-report.pdf" + ); + GpaScore newGpaScore = new GpaScore(gpaScoreRequest.toGpa(), siteUser, gpaScoreRequest.issueDate()); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(gpaScoreRepository.save(newGpaScore)).thenReturn(newGpaScore); + + // 새로운 gpa 저장하게된다. + scoreService.submitGpaScore(siteUser.getEmail(), gpaScoreRequest); + + // Then + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + verify(gpaScoreRepository, times(1)).save(any(GpaScore.class)); + } + + @Test + void 어학성적을_등록한다_기존이력이_없을_때() { + // Given + LanguageTestScoreRequest languageTestScoreRequest = new LanguageTestScoreRequest( + LanguageTestType.TOEIC, "900", + LocalDate.of(2024, 10, 30), "http://example.com/gpa-report.pdf" + ); + LanguageTest languageTest = languageTestScoreRequest.toLanguageTest(); + LanguageTestScore languageTestScore = new LanguageTestScore(languageTest, LocalDate.of(2024, 10, 30), siteUser); + + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(languageTestScoreRepository.save(any(LanguageTestScore.class))).thenReturn(languageTestScore); + + //when + scoreService.submitLanguageTestScore(siteUser.getEmail(), languageTestScoreRequest); + + // Then + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + verify(languageTestScoreRepository, times(1)).save(any(LanguageTestScore.class)); + } + + @Test + void 학점이력을_조회한다_제출이력이_있을_때() { + // Given + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + beforeGpaScore.setSiteUser(siteUser); + beforeGpaScore2.setSiteUser(siteUser); + + // when + GpaScoreStatusResponse gpaScoreStatusResponse = scoreService.getGpaScoreStatus(siteUser.getEmail()); + + // Then + List expectedStatusList = List.of( + GpaScoreStatus.from(beforeGpaScore), + GpaScoreStatus.from(beforeGpaScore2) + ); + assertThat(gpaScoreStatusResponse.gpaScoreStatusList()) + .hasSize(2) + .containsExactlyElementsOf(expectedStatusList); + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + } + + @Test + void 학점이력을_조회한다_제출이력이_없을_때() { + // Given + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + + // when + GpaScoreStatusResponse gpaScoreStatus = scoreService.getGpaScoreStatus(siteUser.getEmail()); + + // Then + assertThat(gpaScoreStatus.gpaScoreStatusList()).isEmpty(); + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + } + + + @Test + void 어학이력을_조회한다_제출이력이_있을_때() { + // Given + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + beforeLanguageTestScore.setSiteUser(siteUser); + beforeLanguageTestScore2.setSiteUser(siteUser); + + // when + LanguageTestScoreStatusResponse languageTestScoreStatus = scoreService.getLanguageTestScoreStatus(siteUser.getEmail()); + + // Then + List expectedStatusList = List.of( + LanguageTestScoreStatus.from(beforeLanguageTestScore), + LanguageTestScoreStatus.from(beforeLanguageTestScore2) + ); + assertThat(languageTestScoreStatus.languageTestScoreStatusList()) + .hasSize(2) + .containsExactlyElementsOf(expectedStatusList); + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + } + + @Test + void 어학이력을_조회한다_제출이력이_없을_때() { + // Given + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + + // when + LanguageTestScoreStatusResponse languageTestScoreStatus = scoreService.getLanguageTestScoreStatus(siteUser.getEmail()); + + // Then + assertThat(languageTestScoreStatus.languageTestScoreStatusList()).isEmpty(); + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + } +}