diff --git a/aics-admin/src/main/java/kgu/developers/admin/graduationUser/application/GraduationUserAdminFacade.java b/aics-admin/src/main/java/kgu/developers/admin/graduationUser/application/GraduationUserAdminFacade.java index 3a63044d..33e0d978 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/graduationUser/application/GraduationUserAdminFacade.java +++ b/aics-admin/src/main/java/kgu/developers/admin/graduationUser/application/GraduationUserAdminFacade.java @@ -23,6 +23,8 @@ import kgu.developers.domain.graduationUser.application.query.GraduationUserQueryService; import kgu.developers.domain.graduationUser.domain.GraduationType; import kgu.developers.domain.graduationUser.domain.GraduationUser; +import kgu.developers.domain.graduationUser.exception.GraduationTypeNotSelectedException; +import kgu.developers.domain.graduationUser.exception.GraudationUserSubmissionMismatchException; import kgu.developers.domain.thesis.application.command.ThesisCommandService; import kgu.developers.domain.thesis.application.query.ThesisQueryService; import kgu.developers.domain.thesis.domain.Thesis; @@ -224,4 +226,36 @@ public GraduationUserBatchDisapproveResponse disapproveGraduationUsers(Graduatio return GraduationUserBatchDisapproveResponse.from(disapprovedUserIds); } + + public Long approveSubmission(Long graduationUserId, Long submissionId) { + GraduationUser graduationUser = graduationUserQueryService.getById(graduationUserId); + validateSubmissionOwner(graduationUser, submissionId); + if(graduationUser.getGraduationType() == GraduationType.CERTIFICATE) { + certificateCommandService.approve(submissionId); + } else if(graduationUser.getGraduationType() == GraduationType.THESIS) { + thesisCommandService.approve(submissionId); + } + return graduationUserId; + } + + public Long disapproveSubmission(Long graduationUserId, Long submissionId) { + GraduationUser graduationUser = graduationUserQueryService.getById(graduationUserId); + validateSubmissionOwner(graduationUser, submissionId); + if(graduationUser.getGraduationType() == GraduationType.CERTIFICATE) { + certificateCommandService.disapprove(submissionId); + } else if(graduationUser.getGraduationType() == GraduationType.THESIS) { + thesisCommandService.disapprove(submissionId); + } + return graduationUserId; + } + + private void validateSubmissionOwner(GraduationUser graduationUser, Long submissionId) { + if(graduationUser.getGraduationType() == GraduationType.CERTIFICATE) { + if(graduationUser.getCertificateId() != submissionId) throw new GraudationUserSubmissionMismatchException(); + } else if(graduationUser.getGraduationType() == GraduationType.THESIS) { + if(graduationUser.getMidThesisId() != submissionId && graduationUser.getFinalThesisId() != submissionId) throw new GraudationUserSubmissionMismatchException(); + } else { + throw new GraduationTypeNotSelectedException(); + } + } } diff --git a/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminController.java index 0e5e552a..febdcb84 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminController.java @@ -162,4 +162,45 @@ ResponseEntity disapproveGraduationUsers( required = true ) @Valid @RequestBody GraduationUserBatchDisapproveRequest request ); + + @Operation(summary = "제출 단일 승인 API", description = """ + - Description : 이 API는 선택한 졸업 대상자의 특정 논문/자격증을 승인합니다. + - Assignee : 장영후 + """) + @ApiResponse( + responseCode = "200", + content = @Content(schema = @Schema(implementation = GraduationUserPersistResponse.class)) + ) + ResponseEntity approveSubmission( + @Parameter( + description = "졸업 대상자 ID는 URL 경로 변수 입니다.", + example = "1", + required = true + ) @Positive @PathVariable Long graduationUserId, + @Parameter( + description = "논문/자격증 ID는 URL 경로 변수 입니다.", + example = "1", + required = true + ) @Positive @PathVariable Long submissionId + ); + + @Operation(summary = "제출 승인 취소 API", description = """ + - Description : 이 API는 선택한 졸업 대상자의 특정 논문/자격증을 승인 취소합니다. + - Assignee : 장영후 + """) + @ApiResponse( + responseCode = "200", + content = @Content(schema = @Schema(implementation = GraduationUserPersistResponse.class))) + ResponseEntity disapproveSubmission( + @Parameter( + description = "졸업 대상자 ID는 URL 경로 변수 입니다.", + example = "1", + required = true + ) @Positive @PathVariable Long graduationUserId, + @Parameter( + description = "논문/자격증 ID는 URL 경로 변수 입니다.", + example = "1", + required = true + ) @Positive @PathVariable Long submissionId + ); } diff --git a/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminControllerImpl.java b/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminControllerImpl.java index 32caf841..eeff7653 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminControllerImpl.java +++ b/aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminControllerImpl.java @@ -135,4 +135,24 @@ public ResponseEntity disapproveGraduatio GraduationUserBatchDisapproveResponse response = graduationUserAdminFacade.disapproveGraduationUsers(request); return ResponseEntity.ok(response); } + + @Override + @PatchMapping("/approve/{graduationUserId}/{submissionId}") + public ResponseEntity approveSubmission( + @Positive @PathVariable Long graduationUserId, + @Positive @PathVariable Long submissionId + ) { + Long approvedGraduationuserId = graduationUserAdminFacade.approveSubmission(graduationUserId,submissionId); + return ResponseEntity.ok(GraduationUserPersistResponse.of(approvedGraduationuserId)); + } + + @Override + @PatchMapping("/disapprove/{graduationUserId}/{submissionId}") + public ResponseEntity disapproveSubmission( + @Positive @PathVariable Long graduationUserId, + @Positive @PathVariable Long submissionId + ) { + Long disapprovedGraduationuserId = graduationUserAdminFacade.disapproveSubmission(graduationUserId,submissionId); + return ResponseEntity.ok(GraduationUserPersistResponse.of(disapprovedGraduationuserId)); + } } diff --git a/aics-admin/src/testFixtures/java/graduationUser/application/GraduationUserAdminFacadeTest.java b/aics-admin/src/testFixtures/java/graduationUser/application/GraduationUserAdminFacadeTest.java index 4cbf9c76..9899151a 100644 --- a/aics-admin/src/testFixtures/java/graduationUser/application/GraduationUserAdminFacadeTest.java +++ b/aics-admin/src/testFixtures/java/graduationUser/application/GraduationUserAdminFacadeTest.java @@ -319,10 +319,10 @@ public void approveGraduationUsers_Success() { @DisplayName("disapproveGraduationUsers는 여러 GraduationUser의 제출 승인을 취소한다.") public void disapproveGraduationUsers_Success() { // given - // 먼저 승인된 상태로 만듦 - fakeCertificateRepository.save(Certificate.of(1L, 1L, 1L, true, null, null, null)); - fakeThesisRepository.save(Thesis.of(1L, 1L, 1L, true, null, null, null)); - fakeThesisRepository.save(Thesis.of(2L, 1L, 2L, true, null, null, null)); + GraduationUserBatchApproveRequest approveRequest = GraduationUserBatchApproveRequest.builder() + .ids(Arrays.asList(1L, 2L)) + .build(); + graduationUserAdminFacade.approveGraduationUsers(approveRequest); List graduationUserIds = Arrays.asList(1L, 2L); GraduationUserBatchDisapproveRequest request = GraduationUserBatchDisapproveRequest.builder() @@ -343,9 +343,6 @@ public void disapproveGraduationUsers_Success() { @DisplayName("disapproveGraduationUsers는 이미 승인이 취소된 유저는 결과 목록에 포함하지 않는다.") public void disapproveGraduationUsers_AlreadyDisapproved() { // given - // 이미 승인 취소 상태로 만듦 - fakeCertificateRepository.save(Certificate.of(1L, 1L, 1L, false, null, null, null)); - List graduationUserIds = List.of(1L); GraduationUserBatchDisapproveRequest request = GraduationUserBatchDisapproveRequest.builder() .ids(graduationUserIds) @@ -375,4 +372,68 @@ public void disapproveGraduationUsers_NoSubmission() { // then assertEquals(0, response.disapprovedIds().size()); } + + @Test + @DisplayName("approveSubmission은 자격증 타입 GraduationUser의 자격증 제출을 단일 승인한다.") + public void approveSubmission_CertificateType_Success() { + // given + Long graduationUserId = 1L; + Long submissionId = 1L; // certificateId + + // when + Long result = graduationUserAdminFacade.approveSubmission(graduationUserId, submissionId); + + // then + assertEquals(graduationUserId, result); + assertEquals(true, fakeCertificateRepository.findApprovalByIdAndDeletedAtIsNull(1L).get()); + } + + @Test + @DisplayName("approveSubmission은 논문 타입 GraduationUser의 논문 제출을 단일 승인한다.") + public void approveSubmission_ThesisType_Success() { + // given + Long graduationUserId = 2L; + Long submissionId = 1L; // midThesisId + + // when + Long result = graduationUserAdminFacade.approveSubmission(graduationUserId, submissionId); + + // then + assertEquals(graduationUserId, result); + assertEquals(true, fakeThesisRepository.findApprovalByIdAndDeletedAtIsNull(1L).get()); + assertEquals(false, fakeThesisRepository.findApprovalByIdAndDeletedAtIsNull(2L).get()); + } + + @Test + @DisplayName("disapproveSubmission은 자격증 타입 GraduationUser의 자격증 제출 승인을 단일 취소한다.") + public void disapproveSubmission_CertificateType_Success() { + // given + Long graduationUserId = 1L; + Long submissionId = 1L; // certificateId + graduationUserAdminFacade.approveSubmission(graduationUserId, submissionId); + + // when + Long result = graduationUserAdminFacade.disapproveSubmission(graduationUserId, submissionId); + + // then + assertEquals(graduationUserId, result); + assertEquals(false, fakeCertificateRepository.findApprovalByIdAndDeletedAtIsNull(1L).get()); + } + + @Test + @DisplayName("disapproveSubmission은 논문 타입 GraduationUser의 논문 제출 승인을 단일 취소한다.") + public void disapproveSubmission_ThesisType_Success() { + // given + Long graduationUserId = 2L; + Long submissionId = 2L; // finalThesisId + graduationUserAdminFacade.approveSubmission(graduationUserId, submissionId); + + // when + Long result = graduationUserAdminFacade.disapproveSubmission(graduationUserId, submissionId); + + // then + assertEquals(graduationUserId, result); + assertEquals(false, fakeThesisRepository.findApprovalByIdAndDeletedAtIsNull(2L).get()); + assertEquals(false, fakeThesisRepository.findApprovalByIdAndDeletedAtIsNull(1L).get()); + } } diff --git a/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationTypeNotSelectedException.java b/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationTypeNotSelectedException.java new file mode 100644 index 00000000..9670b2af --- /dev/null +++ b/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationTypeNotSelectedException.java @@ -0,0 +1,11 @@ +package kgu.developers.domain.graduationUser.exception; + +import kgu.developers.common.exception.CustomException; + +import static kgu.developers.domain.graduationUser.exception.GraduationUserDomainExceptionCode.GRADUATION_TYPE_NOT_SELECTED; + +public class GraduationTypeNotSelectedException extends CustomException { + public GraduationTypeNotSelectedException() { + super(GRADUATION_TYPE_NOT_SELECTED); + } +} diff --git a/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationUserDomainExceptionCode.java b/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationUserDomainExceptionCode.java index a6771534..3b1aff92 100644 --- a/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationUserDomainExceptionCode.java +++ b/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraduationUserDomainExceptionCode.java @@ -19,6 +19,8 @@ public enum GraduationUserDomainExceptionCode implements ExceptionCode { GRADUATION_USER_ID_DUPLICATED(CONFLICT, "이미 동일한 학번의 졸업 대상자 정보가 존재합니다."), GRADUATION_USER_EXCEL_GENERATION_FAILED(INTERNAL_SERVER_ERROR, "졸업 대상자 엑셀 파일의 생성 중 오류가 발생했습니다."), GRADUATION_TYPE_SUBMISSION_PERIOD_CLOSED(BAD_REQUEST, "현재 졸업 방식을 제출하는 기간이 아닙니다."), + GRADUATION_TYPE_NOT_SELECTED(NOT_FOUND, "해당 졸업 대상자는 졸업 방식을 선택하지 않았습니다."), + GRADUATION_USER_SUBMISSION_MISMATCH(BAD_REQUEST, "해당 제출물은 해당 졸업 대상자가 제출하지 않았습니다."), ; private final HttpStatus status; diff --git a/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraudationUserSubmissionMismatchException.java b/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraudationUserSubmissionMismatchException.java new file mode 100644 index 00000000..2051155f --- /dev/null +++ b/aics-domain/src/main/java/kgu/developers/domain/graduationUser/exception/GraudationUserSubmissionMismatchException.java @@ -0,0 +1,11 @@ +package kgu.developers.domain.graduationUser.exception; + +import kgu.developers.common.exception.CustomException; + +import static kgu.developers.domain.graduationUser.exception.GraduationUserDomainExceptionCode.GRADUATION_USER_SUBMISSION_MISMATCH; + +public class GraudationUserSubmissionMismatchException extends CustomException { + public GraudationUserSubmissionMismatchException() { + super(GRADUATION_USER_SUBMISSION_MISMATCH); + } +}