From 0994bb9c4d00f5f7a8f121234b7a647e5c685bf4 Mon Sep 17 00:00:00 2001 From: sukangpunch Date: Tue, 30 Dec 2025 18:01:24 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=EC=9D=98=20?= =?UTF-8?q?=EB=A9=98=ED=86=A0=20=EC=A7=80=EC=9B=90=20=EC=9D=B4=EB=A0=A5=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminMentorApplicationController.java | 10 +++++++ .../dto/MentorApplicationHistoryResponse.java | 14 +++++++++ .../AdminMentorApplicationService.java | 29 +++++++++++++++++++ .../MentorApplicationRepository.java | 4 +++ src/main/resources/secret | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryResponse.java diff --git a/src/main/java/com/example/solidconnection/admin/controller/AdminMentorApplicationController.java b/src/main/java/com/example/solidconnection/admin/controller/AdminMentorApplicationController.java index b8fe6974..5895a81d 100644 --- a/src/main/java/com/example/solidconnection/admin/controller/AdminMentorApplicationController.java +++ b/src/main/java/com/example/solidconnection/admin/controller/AdminMentorApplicationController.java @@ -2,12 +2,14 @@ import com.example.solidconnection.admin.dto.MentorApplicationAssignUniversityRequest; import com.example.solidconnection.admin.dto.MentorApplicationCountResponse; +import com.example.solidconnection.admin.dto.MentorApplicationHistoryResponse; import com.example.solidconnection.admin.dto.MentorApplicationRejectRequest; import com.example.solidconnection.admin.dto.MentorApplicationSearchCondition; import com.example.solidconnection.admin.dto.MentorApplicationSearchResponse; import com.example.solidconnection.admin.service.AdminMentorApplicationService; import com.example.solidconnection.common.response.PageResponse; import jakarta.validation.Valid; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -73,4 +75,12 @@ public ResponseEntity assignUniversity( adminMentorApplicationService.assignUniversity(mentorApplicationId, universityId); return ResponseEntity.ok().build(); } + + @GetMapping("/{site-user-id}/mentor-application-history") + public ResponseEntity> getMentorApplicationHistory( + @PathVariable("site-user-id") Long siteUserId + ){ + List response = adminMentorApplicationService.findMentorApplicationHistory(siteUserId); + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryResponse.java b/src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryResponse.java new file mode 100644 index 00000000..46f7493d --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryResponse.java @@ -0,0 +1,14 @@ +package com.example.solidconnection.admin.dto; + +import com.example.solidconnection.mentor.domain.MentorApplicationStatus; +import java.time.ZonedDateTime; + +public record MentorApplicationHistoryResponse( + long id, + MentorApplicationStatus mentorApplicationStatus, + String rejectedReason, + ZonedDateTime createdAt, + int applicationOrder +) { + +} diff --git a/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java b/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java index d22d9af7..f41b30c6 100644 --- a/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java +++ b/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java @@ -1,8 +1,10 @@ package com.example.solidconnection.admin.service; import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_APPLICATION_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.USER_NOT_FOUND; import com.example.solidconnection.admin.dto.MentorApplicationCountResponse; +import com.example.solidconnection.admin.dto.MentorApplicationHistoryResponse; import com.example.solidconnection.admin.dto.MentorApplicationRejectRequest; import com.example.solidconnection.admin.dto.MentorApplicationSearchCondition; import com.example.solidconnection.admin.dto.MentorApplicationSearchResponse; @@ -10,8 +12,12 @@ import com.example.solidconnection.mentor.domain.MentorApplication; import com.example.solidconnection.mentor.domain.MentorApplicationStatus; import com.example.solidconnection.mentor.repository.MentorApplicationRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; import com.example.solidconnection.university.domain.University; import com.example.solidconnection.university.repository.UniversityRepository; +import java.util.List; +import java.util.stream.IntStream; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -24,6 +30,7 @@ public class AdminMentorApplicationService { private final MentorApplicationRepository mentorApplicationRepository; private final UniversityRepository universityRepository; + private final SiteUserRepository siteUserRepository; @Transactional(readOnly = true) public Page searchMentorApplications( @@ -79,4 +86,26 @@ public void assignUniversity( mentorApplication.assignUniversity(university.getId()); } + + @Transactional(readOnly = true) + public List findMentorApplicationHistory(Long siteUserId) { + SiteUser siteUser = siteUserRepository.findById(siteUserId) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + + long totalCount = mentorApplicationRepository.countBySiteUserId(siteUserId); + + List mentorApplications = mentorApplicationRepository.findTop5BySiteUserIdOrderByCreatedAtDesc(siteUser.getId()); + + return IntStream.range(0, mentorApplications.size()) + .mapToObj(index -> { + MentorApplication app = mentorApplications.get(index); + return new MentorApplicationHistoryResponse( + app.getId(), + app.getMentorApplicationStatus(), + app.getRejectedReason(), + app.getCreatedAt(), + (int) totalCount - index + ); + }).toList(); + } } diff --git a/src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java b/src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java index 144b5461..61339819 100644 --- a/src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java +++ b/src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java @@ -14,4 +14,8 @@ public interface MentorApplicationRepository extends JpaRepository findBySiteUserIdAndMentorApplicationStatus(long siteUserId, MentorApplicationStatus mentorApplicationStatus); long countByMentorApplicationStatus(MentorApplicationStatus mentorApplicationStatus); + + List findTop5BySiteUserIdOrderByCreatedAtDesc(long siteUserId); + + long countBySiteUserId(long siteUserId); } diff --git a/src/main/resources/secret b/src/main/resources/secret index 29524e2d..8300cdec 160000 --- a/src/main/resources/secret +++ b/src/main/resources/secret @@ -1 +1 @@ -Subproject commit 29524e2d6dad2042400de0370a11893029aacff2 +Subproject commit 8300cdecaebfc28fd657064a00a44815a7bb2eee From 8895ee1cda5d515903c1e82318ada516af1f60a0 Mon Sep 17 00:00:00 2001 From: sukangpunch Date: Tue, 30 Dec 2025 18:03:25 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=EB=A7=A4=EA=B0=9C=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=ED=83=80=EC=9E=85=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: long 타입을 Long 으로 수정 --- .../admin/service/AdminMentorApplicationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java b/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java index f41b30c6..dfa71b56 100644 --- a/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java +++ b/src/main/java/com/example/solidconnection/admin/service/AdminMentorApplicationService.java @@ -50,7 +50,7 @@ public void approveMentorApplication(Long mentorApplicationId) { @Transactional public void rejectMentorApplication( - long mentorApplicationId, + Long mentorApplicationId, MentorApplicationRejectRequest request ) { MentorApplication mentorApplication = mentorApplicationRepository.findById(mentorApplicationId) From 9e43bc3f4971db75d0866020b5ab5a4a84b2c598 Mon Sep 17 00:00:00 2001 From: sukangpunch Date: Fri, 2 Jan 2026 20:03:31 +0900 Subject: [PATCH 3/3] =?UTF-8?q?test:=20=EB=A9=98=ED=86=A0=20=EC=A7=80?= =?UTF-8?q?=EC=9B=90=EC=84=9C=20=EC=9D=B4=EB=A0=A5=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: MentorApplicationFixtureBuilder 에 rejectedReason 필드 및 빌더 메서드 추가 --- .../AdminMentorApplicationServiceTest.java | 104 ++++++++++++++++++ .../fixture/MentorApplicationFixture.java | 2 + .../MentorApplicationFixtureBuilder.java | 9 ++ 3 files changed, 115 insertions(+) diff --git a/src/test/java/com/example/solidconnection/admin/service/AdminMentorApplicationServiceTest.java b/src/test/java/com/example/solidconnection/admin/service/AdminMentorApplicationServiceTest.java index ae40cb5d..4a3c1ad9 100644 --- a/src/test/java/com/example/solidconnection/admin/service/AdminMentorApplicationServiceTest.java +++ b/src/test/java/com/example/solidconnection/admin/service/AdminMentorApplicationServiceTest.java @@ -5,11 +5,13 @@ import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_APPLICATION_NOT_OTHER_STATUS; import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_APPLICATION_UNIVERSITY_NOT_SELECTED; import static com.example.solidconnection.common.exception.ErrorCode.UNIVERSITY_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.USER_NOT_FOUND; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; import static org.junit.jupiter.api.Assertions.assertAll; import com.example.solidconnection.admin.dto.MentorApplicationCountResponse; +import com.example.solidconnection.admin.dto.MentorApplicationHistoryResponse; import com.example.solidconnection.admin.dto.MentorApplicationRejectRequest; import com.example.solidconnection.admin.dto.MentorApplicationSearchCondition; import com.example.solidconnection.admin.dto.MentorApplicationSearchResponse; @@ -509,4 +511,106 @@ class 멘토_지원서에_대학_매핑 { .hasMessage(UNIVERSITY_NOT_FOUND.getMessage()); } } + + @Nested + class 멘토_지원서_이력_조회 { + + @Test + void 사용자의_멘토_지원서_이력을_최신_생성_내림차순으로_조회한다() { + // given + SiteUser user = siteUserFixture.사용자(); + University university = universityFixture.메이지_대학(); + MentorApplication app1 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app2 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app3 = mentorApplicationFixture.승인된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + + // when + List response = adminMentorApplicationService.findMentorApplicationHistory(user.getId()); + + // then + assertAll( + () -> assertThat(response).hasSize(3), + () -> assertThat(response) + .extracting(MentorApplicationHistoryResponse::id) + .containsExactly(app3.getId(), app2.getId(), app1.getId()), + () -> assertThat(response) + .extracting(MentorApplicationHistoryResponse::applicationOrder) + .containsExactly(3,2,1) + ); + } + + @Test + void 지원서가_5개를_초과하면_최신_5개만_최신_생성_내림차순으로_조회한다() { + // given + SiteUser user = siteUserFixture.사용자(); + University university = universityFixture.메이지_대학(); + MentorApplication app1 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app2 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app3 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app4 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app5 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app6 = mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + MentorApplication app7 = mentorApplicationFixture.승인된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + + // when + List response = adminMentorApplicationService.findMentorApplicationHistory(user.getId()); + + // then + assertAll( + () -> assertThat(response).hasSize(5), + () -> assertThat(response) + .extracting(MentorApplicationHistoryResponse::id) + .containsExactly(app7.getId(), app6.getId(), app5.getId(), app4.getId(), app3.getId()), + () -> assertThat(response) + .extracting(MentorApplicationHistoryResponse::applicationOrder) + .containsExactly(7,6,5,4,3) + ); + } + + @Test + void 지원서_이력이_없으면_빈_목록을_반환한다() { + // given + SiteUser user = siteUserFixture.사용자(); + + // when + List response = adminMentorApplicationService.findMentorApplicationHistory(user.getId()); + + // then + assertThat(response).isEmpty(); + } + + @Test + void 응답에_지원서_상태와_거절_사유가_포함된다() { + // given + SiteUser user = siteUserFixture.사용자(); + University university = universityFixture.메이지_대학(); + mentorApplicationFixture.거절된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + mentorApplicationFixture.승인된_멘토신청(user.getId(), UniversitySelectType.CATALOG, university.getId()); + + // when + List response = adminMentorApplicationService.findMentorApplicationHistory(user.getId()); + + // then + assertAll( + () -> assertThat(response).hasSize(2), + () -> assertThat(response.get(0).mentorApplicationStatus()).isEqualTo(MentorApplicationStatus.APPROVED), + () -> assertThat(response.get(0).rejectedReason()).isNull(), + () -> assertThat(response.get(0).applicationOrder()).isEqualTo(2), + () -> assertThat(response.get(1).mentorApplicationStatus()).isEqualTo(MentorApplicationStatus.REJECTED), + () -> assertThat(response.get(1).rejectedReason()).isNotNull(), + () -> assertThat(response.get(1).applicationOrder()).isEqualTo(1) + ); + } + + @Test + void 존재하지_않는_사용자_이력을_조회하면_예외_응답을_반환한다() { + // given + long nonExistentUserId = 99999L; + + // when & then + assertThatCode(() -> adminMentorApplicationService.findMentorApplicationHistory(nonExistentUserId)) + .isInstanceOf(CustomException.class) + .hasMessage(USER_NOT_FOUND.getMessage()); + } + } } diff --git a/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixture.java b/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixture.java index 0baf62e2..6a715375 100644 --- a/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixture.java +++ b/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixture.java @@ -18,6 +18,7 @@ public class MentorApplicationFixture { private static final String DEFAULT_COUNTRY_CODE = "US"; private static final String DEFAULT_PROOF_URL = "/mentor-proof.pdf"; private static final ExchangeStatus DEFAULT_EXCHANGE_STATUS = ExchangeStatus.AFTER_EXCHANGE; + private static final String REJECTED_REASON = "pdf 파일 안열림"; public MentorApplication 대기중_멘토신청( long siteUserId, @@ -64,6 +65,7 @@ public class MentorApplicationFixture { .universitySelectType(selectType) .mentorProofUrl(DEFAULT_PROOF_URL) .termId(termFixture.현재_학기("2025-1").getId()) + .rejectedReason(REJECTED_REASON) .exchangeStatus(DEFAULT_EXCHANGE_STATUS) .mentorApplicationStatus(MentorApplicationStatus.REJECTED) .create(); diff --git a/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixtureBuilder.java b/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixtureBuilder.java index fd2a74ff..93e5e24b 100644 --- a/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixtureBuilder.java +++ b/src/test/java/com/example/solidconnection/mentor/fixture/MentorApplicationFixtureBuilder.java @@ -21,6 +21,7 @@ public class MentorApplicationFixtureBuilder { private UniversitySelectType universitySelectType = UniversitySelectType.OTHER; private String mentorProofUrl = "/mentor-proof.pdf"; private long termId; + private String rejectedReason = null; private ExchangeStatus exchangeStatus = ExchangeStatus.AFTER_EXCHANGE; private MentorApplicationStatus mentorApplicationStatus = MentorApplicationStatus.PENDING; @@ -58,6 +59,11 @@ public MentorApplicationFixtureBuilder termId(long termId) { return this; } + public MentorApplicationFixtureBuilder rejectedReason(String rejectedReason) { + this.rejectedReason = rejectedReason; + return this; + } + public MentorApplicationFixtureBuilder exchangeStatus(ExchangeStatus exchangeStatus) { this.exchangeStatus = exchangeStatus; return this; @@ -79,6 +85,9 @@ public MentorApplication create() { exchangeStatus ); ReflectionTestUtils.setField(mentorApplication, "mentorApplicationStatus", mentorApplicationStatus); + if(rejectedReason != null) { + ReflectionTestUtils.setField(mentorApplication, "rejectedReason", rejectedReason); + } return mentorApplicationRepository.save(mentorApplication); } }