Skip to content

Commit 8c73cd0

Browse files
authored
[FEAT] 제출 완료된 지원서 상세 조회 (#310)
* feat: 제출된 지원서 상세 조회 DTO 추가 * feat: 제출된 지원서 상세 조회 API 스펙 추가 * feat: 제출된 지원서 상세 조회 API 엔트포인트 추가 * feat: 제출된 지원서 상세 조회 비즈니스 로직 구 * test: 제출된 지원서 상세 조회 비즈니스 로직 테스트 추가 * style: 제출된 지원서 상세 조회 API 설명 수정 * style: 테스트 이름을 실제 동작과 일치하게 수 * style: 불필요한 주석 제거 * test: 제출된 지원서 상세 조회 시 예외 코드 검증 추가 * fix: 개행 처 * style: 테스트 메서드 이름을 명확하게 수정
1 parent fb7cc32 commit 8c73cd0

5 files changed

Lines changed: 144 additions & 16 deletions

File tree

src/main/java/org/ject/support/domain/admin/controller/SubmittedApplyApiSpec.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.validation.Valid;
66
import org.ject.support.domain.admin.dto.SubmittedApplyBulkDeleteRequest;
77
import org.ject.support.domain.admin.dto.SubmittedApplyCountResponse;
8+
import org.ject.support.domain.admin.dto.SubmittedApplyDetailResponse;
89
import org.ject.support.domain.admin.dto.SubmittedApplyResponse;
910
import org.ject.support.domain.member.JobFamily;
1011
import org.springframework.data.domain.Page;
@@ -28,10 +29,15 @@ public interface SubmittedApplyApiSpec {
2829
Page<SubmittedApplyResponse> findSubmittedApplies(@RequestParam(required = false) final JobFamily jobFamily,
2930
@PageableDefault(size = 15) final Pageable pageable);
3031

32+
@Operation(
33+
summary = "제출된 지원서 상세 조회",
34+
description = "전달한 ID에 해당하는 제출된 지원서의 상세 정보를 조회합니다.")
35+
SubmittedApplyDetailResponse findSubmittedApplyDetail(@PathVariable("applyId") final Long applyId);
36+
3137
@Operation(
3238
summary = "제출된 지원서 삭제",
3339
description = "선택한 제출된 지원서를 삭제합니다.")
34-
void deleteSubmittedApply(@PathVariable final Long applyId);
40+
void deleteSubmittedApply(@PathVariable("applyId") final Long applyId);
3541

3642
@Operation(
3743
summary = "제출된 지원서 다수 삭제",

src/main/java/org/ject/support/domain/admin/controller/SubmittedApplyController.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import lombok.RequiredArgsConstructor;
55
import org.ject.support.domain.admin.dto.SubmittedApplyBulkDeleteRequest;
66
import org.ject.support.domain.admin.dto.SubmittedApplyCountResponse;
7+
import org.ject.support.domain.admin.dto.SubmittedApplyDetailResponse;
78
import org.ject.support.domain.admin.dto.SubmittedApplyResponse;
89
import org.ject.support.domain.admin.service.SubmittedApplyService;
910
import org.ject.support.domain.member.JobFamily;
@@ -41,10 +42,17 @@ public Page<SubmittedApplyResponse> findSubmittedApplies(@RequestParam(required
4142
return submittedApplyService.findSubmittedApplies(jobFamily, pageable);
4243
}
4344

45+
@Override
46+
@GetMapping("/{applyId}")
47+
@PreAuthorize("hasRole('ROLE_ADMIN')")
48+
public SubmittedApplyDetailResponse findSubmittedApplyDetail(@PathVariable("applyId") final Long applyId) {
49+
return submittedApplyService.findSubmittedApplyDetail(applyId);
50+
}
51+
4452
@Override
4553
@DeleteMapping("/{applyId}")
4654
@PreAuthorize("hasRole('ROLE_ADMIN')")
47-
public void deleteSubmittedApply(@PathVariable final Long applyId) {
55+
public void deleteSubmittedApply(@PathVariable("applyId") final Long applyId) {
4856
submittedApplyService.deleteSubmittedApply(applyId);
4957
}
5058

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.ject.support.domain.admin.dto;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import org.ject.support.common.util.DateTimeUtil;
6+
import org.ject.support.domain.apply.domain.Apply;
7+
import org.ject.support.domain.apply.dto.ApplyPortfolioDto;
8+
import org.ject.support.domain.member.JobFamily;
9+
10+
public record SubmittedApplyDetailResponse(
11+
Long applyId,
12+
String name,
13+
String phoneNumber,
14+
String email,
15+
JobFamily jobFamily,
16+
String createdAt,
17+
String updatedAt,
18+
ApplicationFormResponse applicationFormResponse
19+
) {
20+
public static SubmittedApplyDetailResponse from(Apply apply,
21+
Map<String, String> answers,
22+
List<ApplyPortfolioDto> portfolios) {
23+
return new SubmittedApplyDetailResponse(
24+
apply.getId(),
25+
apply.getMember().getName(),
26+
apply.getMember().getPhoneNumber(),
27+
apply.getMember().getEmail(),
28+
apply.getMember().getJobFamily(),
29+
DateTimeUtil.formatWithDayOfWeek(apply.getCreatedAt()),
30+
DateTimeUtil.formatWithDayOfWeek(apply.getUpdatedAt()),
31+
ApplicationFormResponse.from(answers, portfolios)
32+
);
33+
}
34+
}

src/main/java/org/ject/support/domain/admin/service/SubmittedApplyService.java

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.ject.support.common.data.PageResponse;
88
import org.ject.support.common.util.String2MapSerializer;
99
import org.ject.support.domain.admin.dto.SubmittedApplyCountResponse;
10+
import org.ject.support.domain.admin.dto.SubmittedApplyDetailResponse;
1011
import org.ject.support.domain.admin.dto.SubmittedApplyResponse;
1112
import org.ject.support.domain.apply.domain.ApplicationForm;
1213
import org.ject.support.domain.apply.domain.Apply;
@@ -41,20 +42,11 @@ public Page<SubmittedApplyResponse> findSubmittedApplies(final JobFamily jobFami
4142
return PageResponse.from(content, pageable, applyPage.getTotalElements());
4243
}
4344

44-
private SubmittedApplyResponse toSubmittedApplyResponse(final Apply apply) {
45-
ApplicationForm applicationForm = apply.getApplicationForm();
46-
Map<String, String> content = Optional.ofNullable(applicationForm)
47-
.map(ApplicationForm::getContent)
48-
.map(string2MapSerializer::serializeAsMap)
49-
.orElse(Map.of());
50-
List<ApplyPortfolioDto> portfolios = Optional.ofNullable(applicationForm)
51-
.map(ApplicationForm::getPortfolios)
52-
.orElse(List.of())
53-
.stream()
54-
.map(ApplyPortfolioDto::from)
55-
.toList();
56-
57-
return SubmittedApplyResponse.from(apply, content, portfolios);
45+
@Transactional(readOnly = true)
46+
public SubmittedApplyDetailResponse findSubmittedApplyDetail(final Long applyId) {
47+
return applyRepository.findByIdAndStatusWithMember(applyId, Status.SUBMITTED)
48+
.map(this::toSubmittedApplyDetailResponse)
49+
.orElseThrow(() -> new ApplyException(ApplyErrorCode.NOT_FOUND_APPLY));
5850
}
5951

6052
@Transactional(readOnly = true)
@@ -83,6 +75,36 @@ public void deleteSubmittedApplies(final List<Long> applyIds) {
8375
applies.forEach(this::deleteProfileAndApplicationForm);
8476
}
8577

78+
private SubmittedApplyDetailResponse toSubmittedApplyDetailResponse(final Apply apply) {
79+
ApplicationForm submittedApplicationForm = apply.getApplicationForm();
80+
Map<String, String> content = extractContent(submittedApplicationForm);
81+
List<ApplyPortfolioDto> portfolios = extractPortfolios(submittedApplicationForm);
82+
return SubmittedApplyDetailResponse.from(apply, content, portfolios);
83+
}
84+
85+
private SubmittedApplyResponse toSubmittedApplyResponse(final Apply apply) {
86+
ApplicationForm applicationForm = apply.getApplicationForm();
87+
Map<String, String> content = extractContent(applicationForm);
88+
List<ApplyPortfolioDto> portfolios = extractPortfolios(applicationForm);
89+
return SubmittedApplyResponse.from(apply, content, portfolios);
90+
}
91+
92+
private Map<String, String> extractContent(final ApplicationForm applicationForm) {
93+
return Optional.ofNullable(applicationForm)
94+
.map(ApplicationForm::getContent)
95+
.map(string2MapSerializer::serializeAsMap)
96+
.orElse(Map.of());
97+
}
98+
99+
private List<ApplyPortfolioDto> extractPortfolios(final ApplicationForm applicationForm) {
100+
return Optional.ofNullable(applicationForm)
101+
.map(ApplicationForm::getPortfolios)
102+
.orElse(List.of())
103+
.stream()
104+
.map(ApplyPortfolioDto::from)
105+
.toList();
106+
}
107+
86108
private void ensureSubmitted(final Apply apply) {
87109
if (apply.isNotSubmitted()) {
88110
throw new ApplyException(ApplyErrorCode.NOT_FOUND_SUBMITTED_APPLICATION_FORM);

src/test/java/org/ject/support/domain/admin/service/SubmittedApplyServiceTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,62 @@ void setUp() {
284284
verify(applyRepository).findSubmittedApplies(jobFamily, pageable);
285285
}
286286

287+
@Test
288+
void 존재하지_않는_제출된_지원서를_상세조회할_경우_예외가_발생() {
289+
// given
290+
var applyId = submittedApply.getId() + 1L;
291+
given(applyRepository.findByIdAndStatusWithMember(applyId, Status.SUBMITTED))
292+
.willReturn(Optional.empty());
293+
294+
// expected
295+
assertThatThrownBy(() -> submittedApplyService.findSubmittedApplyDetail(applyId))
296+
.isInstanceOf(ApplyException.class)
297+
.hasFieldOrPropertyWithValue("errorCode", ApplyErrorCode.NOT_FOUND_APPLY);
298+
}
299+
300+
@Test
301+
void 상세조회하려는_제출된_지원서가_null인_경우_빈_응답을_반환() {
302+
// given
303+
var applyId = submittedApply.getId() + 1L;
304+
var member2 = Member.builder()
305+
.name("김젝트2")
306+
.build();
307+
var apply2 = Apply.builder()
308+
.id(applyId)
309+
.status(Status.SUBMITTED)
310+
.applicationForm(null)
311+
.member(member2)
312+
.recruit(submittedApply.getRecruit())
313+
.build();
314+
315+
given(applyRepository.findByIdAndStatusWithMember(applyId, Status.SUBMITTED))
316+
.willReturn(Optional.of(apply2));
317+
318+
// when
319+
var actual = submittedApplyService.findSubmittedApplyDetail(applyId);
320+
// expected
321+
assertThat(actual.applyId()).isEqualTo(applyId);
322+
assertThat(actual.applicationFormResponse().answers()).isEmpty(); // 빈 Map 확인
323+
assertThat(actual.applicationFormResponse().portfolios()).isEmpty();
324+
}
325+
326+
@Test
327+
void 제출된_지원서를_상세조회() {
328+
// given
329+
given(applyRepository.findByIdAndStatusWithMember(
330+
submittedApply.getId(),
331+
Status.SUBMITTED
332+
)).willReturn(Optional.of(submittedApply));
333+
334+
// when
335+
var actual = submittedApplyService.findSubmittedApplyDetail(submittedApply.getId());
336+
337+
// then
338+
verify(applyRepository).findByIdAndStatusWithMember(
339+
submittedApply.getId(),
340+
Status.SUBMITTED
341+
);
342+
assertThat(actual.applyId()).isEqualTo(submittedApply.getId());
343+
}
344+
287345
}

0 commit comments

Comments
 (0)