Skip to content

Commit 6c7ddd4

Browse files
authored
Merge pull request #219 from GDGoCINHA/develop
[FEAT]: 코어 리쿠르트 지원자 조회 API 추가
2 parents de3958f + 2727aff commit 6c7ddd4

File tree

6 files changed

+179
-0
lines changed

6 files changed

+179
-0
lines changed

src/main/java/inha/gdgoc/domain/core/recruit/controller/CoreRecruitController.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
11
package inha.gdgoc.domain.core.recruit.controller;
22

33
import inha.gdgoc.domain.core.recruit.dto.request.CoreRecruitApplicationRequest;
4+
import inha.gdgoc.domain.core.recruit.dto.response.CoreRecruitApplicantDetailResponse;
5+
import inha.gdgoc.domain.core.recruit.dto.response.CoreRecruitApplicantSummaryResponse;
46
import inha.gdgoc.domain.core.recruit.service.CoreRecruitApplicationService;
7+
import inha.gdgoc.domain.core.recruit.entity.CoreRecruitApplication;
8+
import inha.gdgoc.domain.core.recruit.controller.message.CoreRecruitApplicationMessage;
59
import inha.gdgoc.global.dto.response.ApiResponse;
10+
import inha.gdgoc.global.dto.response.PageMeta;
611
import jakarta.validation.Valid;
712
import lombok.RequiredArgsConstructor;
13+
import io.swagger.v3.oas.annotations.Operation;
14+
import io.swagger.v3.oas.annotations.Parameter;
15+
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
816
import org.springframework.http.ResponseEntity;
17+
import org.springframework.security.access.prepost.PreAuthorize;
18+
import org.springframework.data.domain.Page;
19+
import org.springframework.data.domain.Pageable;
20+
import org.springframework.data.domain.PageRequest;
21+
import org.springframework.data.domain.Sort;
22+
import org.springframework.data.domain.Sort.Direction;
23+
import org.springframework.web.bind.annotation.GetMapping;
24+
import org.springframework.web.bind.annotation.PathVariable;
925
import org.springframework.web.bind.annotation.PostMapping;
1026
import org.springframework.web.bind.annotation.RequestBody;
1127
import org.springframework.web.bind.annotation.RequestMapping;
28+
import org.springframework.web.bind.annotation.RequestParam;
1229
import org.springframework.web.bind.annotation.RestController;
30+
import io.swagger.v3.oas.annotations.tags.Tag;
1331

32+
@Tag(name = "Core Recruit - Applicants", description = "코어 리쿠르트 지원자 조회 API")
1433
@RestController
1534
@RequestMapping("/api/v1/core-recruit")
1635
@RequiredArgsConstructor
@@ -27,6 +46,59 @@ public ResponseEntity<ApiResponse<CreateResponse, Void>> create(
2746
Long id = service.create(request);
2847
return ResponseEntity.ok(ApiResponse.ok("OK", new CreateResponse(id, "OK")));
2948
}
49+
50+
@Operation(
51+
summary = "코어 리쿠르트 지원자 목록 조회",
52+
description = "전체 목록 또는 이름 검색 결과를 반환합니다.",
53+
security = { @SecurityRequirement(name = "BearerAuth") }
54+
)
55+
@PreAuthorize("hasRole('ADMIN')")
56+
@GetMapping("/applicants")
57+
public ResponseEntity<ApiResponse<java.util.List<CoreRecruitApplicantSummaryResponse>, PageMeta>> getApplicants(
58+
@Parameter(description = "검색어(이름 부분 일치). 없으면 전체 조회", example = "홍길동")
59+
@RequestParam(required = false) String question,
60+
61+
@Parameter(description = "페이지(0부터 시작)", example = "0")
62+
@RequestParam(defaultValue = "0") int page,
63+
64+
@Parameter(description = "페이지 크기", example = "20")
65+
@RequestParam(defaultValue = "20") int size,
66+
67+
@Parameter(description = "정렬 필드", example = "createdAt")
68+
@RequestParam(defaultValue = "createdAt") String sort,
69+
70+
@Parameter(description = "정렬 방향 ASC/DESC", example = "DESC")
71+
@RequestParam(defaultValue = "DESC") String dir
72+
) {
73+
Direction direction = "ASC".equalsIgnoreCase(dir) ? Direction.ASC : Direction.DESC;
74+
Pageable pageable = PageRequest.of(page, size, Sort.by(direction, sort));
75+
76+
Page<CoreRecruitApplication> pageResult = service.findApplicantsPage(question, pageable);
77+
78+
java.util.List<CoreRecruitApplicantSummaryResponse> list = pageResult
79+
.map(CoreRecruitApplicantSummaryResponse::from)
80+
.getContent();
81+
PageMeta meta = PageMeta.of(pageResult);
82+
83+
return ResponseEntity.ok(
84+
ApiResponse.ok(CoreRecruitApplicationMessage.APPLICANT_LIST_RETRIEVED_SUCCESS, list, meta)
85+
);
86+
}
87+
88+
@Operation(
89+
summary = "코어 리쿠르트 지원자 상세 조회",
90+
security = { @SecurityRequirement(name = "BearerAuth") }
91+
)
92+
@PreAuthorize("hasRole('ADMIN')")
93+
@GetMapping("/applicants/{id}")
94+
public ResponseEntity<ApiResponse<CoreRecruitApplicantDetailResponse, Void>> getApplicant(
95+
@PathVariable Long id
96+
) {
97+
CoreRecruitApplicantDetailResponse response = service.getApplicantDetail(id);
98+
return ResponseEntity.ok(
99+
ApiResponse.ok(CoreRecruitApplicationMessage.APPLICANT_RETRIEVED_SUCCESS, response)
100+
);
101+
}
30102
}
31103

32104

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package inha.gdgoc.domain.core.recruit.controller.message;
2+
3+
public class CoreRecruitApplicationMessage {
4+
public static final String APPLICANT_LIST_RETRIEVED_SUCCESS = "성공적으로 코어 리쿠르트 지원자 목록을 조회했습니다.";
5+
public static final String APPLICANT_RETRIEVED_SUCCESS = "성공적으로 코어 리쿠르트 지원자 상세를 조회했습니다.";
6+
}
7+
8+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package inha.gdgoc.domain.core.recruit.dto.response;
2+
3+
import inha.gdgoc.domain.core.recruit.entity.CoreRecruitApplication;
4+
import java.time.Instant;
5+
import java.util.List;
6+
7+
public record CoreRecruitApplicantDetailResponse(
8+
Long id,
9+
String name,
10+
String studentId,
11+
String phone,
12+
String major,
13+
String email,
14+
String team,
15+
String motivation,
16+
String wish,
17+
String strengths,
18+
String pledge,
19+
List<String> fileUrls,
20+
Instant createdAt,
21+
Instant updatedAt
22+
) {
23+
24+
public static CoreRecruitApplicantDetailResponse from(CoreRecruitApplication entity) {
25+
return new CoreRecruitApplicantDetailResponse(
26+
entity.getId(),
27+
entity.getName(),
28+
entity.getStudentId(),
29+
entity.getPhone(),
30+
entity.getMajor(),
31+
entity.getEmail(),
32+
entity.getTeam(),
33+
entity.getMotivation(),
34+
entity.getWish(),
35+
entity.getStrengths(),
36+
entity.getPledge(),
37+
entity.getFileUrls(),
38+
entity.getCreatedAt(),
39+
entity.getUpdatedAt()
40+
);
41+
}
42+
}
43+
44+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package inha.gdgoc.domain.core.recruit.dto.response;
2+
3+
import inha.gdgoc.domain.core.recruit.entity.CoreRecruitApplication;
4+
import java.time.Instant;
5+
6+
public record CoreRecruitApplicantSummaryResponse(
7+
Long id,
8+
String name,
9+
String studentId,
10+
String major,
11+
String email,
12+
String phone,
13+
String team,
14+
Instant createdAt
15+
) {
16+
17+
public static CoreRecruitApplicantSummaryResponse from(CoreRecruitApplication entity) {
18+
return new CoreRecruitApplicantSummaryResponse(
19+
entity.getId(),
20+
entity.getName(),
21+
entity.getStudentId(),
22+
entity.getMajor(),
23+
entity.getEmail(),
24+
entity.getPhone(),
25+
entity.getTeam(),
26+
entity.getCreatedAt()
27+
);
28+
}
29+
}
30+
31+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package inha.gdgoc.domain.core.recruit.repository;
22

33
import inha.gdgoc.domain.core.recruit.entity.CoreRecruitApplication;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.Pageable;
46
import org.springframework.data.jpa.repository.JpaRepository;
57

68
public interface CoreRecruitApplicationRepository extends JpaRepository<CoreRecruitApplication, Long> {
9+
Page<CoreRecruitApplication> findByNameContainingIgnoreCase(String name, Pageable pageable);
710
}
811

912

src/main/java/inha/gdgoc/domain/core/recruit/service/CoreRecruitApplicationService.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package inha.gdgoc.domain.core.recruit.service;
22

33
import inha.gdgoc.domain.core.recruit.dto.request.CoreRecruitApplicationRequest;
4+
import inha.gdgoc.domain.core.recruit.dto.response.CoreRecruitApplicantDetailResponse;
5+
import inha.gdgoc.domain.core.recruit.dto.response.CoreRecruitApplicantSummaryResponse;
46
import inha.gdgoc.domain.core.recruit.entity.CoreRecruitApplication;
57
import inha.gdgoc.domain.core.recruit.repository.CoreRecruitApplicationRepository;
8+
import inha.gdgoc.global.exception.BusinessException;
9+
import inha.gdgoc.global.exception.GlobalErrorCode;
610
import lombok.RequiredArgsConstructor;
11+
import org.springframework.data.domain.Page;
12+
import org.springframework.data.domain.Pageable;
713
import org.springframework.stereotype.Service;
814
import org.springframework.transaction.annotation.Transactional;
915

@@ -31,6 +37,21 @@ public Long create(CoreRecruitApplicationRequest request) {
3137

3238
return repository.save(entity).getId();
3339
}
40+
41+
@Transactional(readOnly = true)
42+
public Page<CoreRecruitApplication> findApplicantsPage(String question, Pageable pageable) {
43+
if (question == null || question.isBlank()) {
44+
return repository.findAll(pageable);
45+
}
46+
return repository.findByNameContainingIgnoreCase(question, pageable);
47+
}
48+
49+
@Transactional(readOnly = true)
50+
public CoreRecruitApplicantDetailResponse getApplicantDetail(Long id) {
51+
CoreRecruitApplication app = repository.findById(id)
52+
.orElseThrow(() -> new BusinessException(GlobalErrorCode.RESOURCE_NOT_FOUND));
53+
return CoreRecruitApplicantDetailResponse.from(app);
54+
}
3455
}
3556

3657

0 commit comments

Comments
 (0)