-
Notifications
You must be signed in to change notification settings - Fork 1
[REFACTOR] #197: 기존 신입 멤버 가입 신청 및 조회 api 리팩토링 #202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
db0da7c
5f052cb
1bba2a1
b0ee8eb
687b0e1
7b3859c
ac03741
f314721
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,16 +6,20 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
| import static inha.gdgoc.domain.recruit.controller.message.RecruitMemberMessage.STUDENT_ID_DUPLICATION_CHECK_SUCCESS; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.dto.request.ApplicationRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.dto.request.CheckPhoneNumberRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.dto.request.CheckStudentIdRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.dto.response.CheckPhoneNumberResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.dto.response.CheckStudentIdResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.dto.response.SpecifiedMemberResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.domain.recruit.service.RecruitMemberService; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import inha.gdgoc.global.dto.response.ApiResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.validation.Valid; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.swagger.v3.oas.annotations.Operation; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.swagger.v3.oas.annotations.security.SecurityRequirement; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.validation.constraints.NotBlank; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.validation.constraints.Pattern; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.http.ResponseEntity; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.ModelAttribute; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.PathVariable; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.PostMapping; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.RequestBody; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -38,34 +42,45 @@ public ResponseEntity<ApiResponse<Void, Void>> recruitMemberAdd( | |||||||||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(ApiResponse.ok(MEMBER_SAVE_SUCCESS)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO valid 핸들러 추가 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO DTO로 응답 리팩토링, requestparam으로 변경하기 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/check/studentId") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<ApiResponse<Boolean, Void>> duplicatedStudentIdDetails( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @Valid @ModelAttribute CheckStudentIdRequest studentIdRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/studentId") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<ApiResponse<CheckStudentIdResponse, Void>> duplicatedStudentIdDetails( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @NotBlank(message = "학번은 필수 입력 값입니다.") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @Pattern(regexp = "^12[0-9]{6}$", message = "유효하지 않은 학번 값입니다.") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| String studentId | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean exists = recruitMemberService.isRegisteredStudentId(studentIdRequest.getStudentId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| CheckStudentIdResponse response = recruitMemberService.isRegisteredStudentId(studentId); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(ApiResponse.ok(STUDENT_ID_DUPLICATION_CHECK_SUCCESS, exists)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(ApiResponse.ok(STUDENT_ID_DUPLICATION_CHECK_SUCCESS, response)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [중요] 엔드포인트 경로 변경으로 인증 요구됨 + 일관성 깨짐
다음과 같이 경로를 복구/정렬하는 것을 권장합니다. - @GetMapping("/studentId")
+ @GetMapping("/check/studentId")대안으로 SecurityConfig의 permitAll에 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO DTO로 응답 리팩토링 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/check/phoneNumber") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<ApiResponse<Boolean, Void>> duplicatedPhoneNumberDetails( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @Valid @ModelAttribute CheckPhoneNumberRequest phoneNumberRequest | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<ApiResponse<CheckPhoneNumberResponse, Void>> duplicatedPhoneNumberDetails( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @NotBlank(message = "전화번호는 필수 입력 값입니다.") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @Pattern(regexp = "^010-\\d{4}-\\d{4}$", message = "전화번호 형식은 010-XXXX-XXXX 이어야 합니다.") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| String phoneNumber | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean exists = recruitMemberService.isRegisteredPhoneNumber(phoneNumberRequest.getPhoneNumber()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| CheckPhoneNumberResponse response = recruitMemberService | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .isRegisteredPhoneNumber(phoneNumber); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(ApiResponse.ok(PHONE_NUMBER_DUPLICATION_CHECK_SUCCESS, exists)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(ApiResponse.ok(PHONE_NUMBER_DUPLICATION_CHECK_SUCCESS, response)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO 코어 멤버 인증 리팩토링 (Authentication), requestparam으로 변경하기 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/recruit/member") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<ApiResponse<SpecifiedMemberResponse, Void>> getSpecifiedMember ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam Long userId | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @Operation(summary = "특정 멤버 가입 신청서 조회", security = { @SecurityRequirement(name = "BearerAuth") }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasRole('ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/recruit/members/{memberId}") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<ApiResponse<SpecifiedMemberResponse, Void>> getSpecifiedMember( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @PathVariable Long memberId | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SpecifiedMemberResponse response = recruitMemberService.findSpecifiedMember(userId); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SpecifiedMemberResponse response = recruitMemberService.findSpecifiedMember(memberId); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(ApiResponse.ok(MEMBER_RETRIEVED_SUCCESS, response)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO 전체 응답 조회 및 검색 | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO 입금 완료 | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO 입금 미완료 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package inha.gdgoc.domain.recruit.dto.response; | ||
|
|
||
| import com.fasterxml.jackson.core.type.TypeReference; | ||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import inha.gdgoc.domain.recruit.entity.Answer; | ||
| import inha.gdgoc.domain.recruit.enums.InputType; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public record AnswerResponse( | ||
| Long id, | ||
| InputType inputType, | ||
| Object responseValue | ||
| ) { | ||
| public static AnswerResponse from(Answer answer, ObjectMapper om) { | ||
| return new AnswerResponse( | ||
| answer.getId(), | ||
| answer.getInputType(), | ||
| toFriendlyValue(answer.getResponseValue(), om) | ||
| ); | ||
| } | ||
|
|
||
| private static Object toFriendlyValue(String json, ObjectMapper om) { | ||
| if (json == null || json.isBlank()) return null; | ||
| try { | ||
| JsonNode node = om.readTree(json); | ||
|
|
||
| if (node.isTextual()) { | ||
| return node.asText(); | ||
| } | ||
| if (node.isArray()) { | ||
| return om.convertValue(node, new TypeReference<List<Object>>() {}); | ||
| } | ||
| if (node.isObject()) { | ||
| return om.convertValue(node, new TypeReference<Map<String, Object>>() {}); | ||
| } | ||
| if (node.isNumber()) { | ||
| return node.numberValue(); | ||
| } | ||
| if (node.isBoolean()) { | ||
| return node.booleanValue(); | ||
| } | ||
| return null; | ||
| } catch (Exception e) { | ||
| return json; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package inha.gdgoc.domain.recruit.dto.response; | ||
|
|
||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import inha.gdgoc.domain.recruit.entity.Answer; | ||
| import java.util.List; | ||
|
|
||
| public record AnswersResponse( | ||
| List<AnswerResponse> answers | ||
| ) { | ||
| public static AnswersResponse from(List<Answer> entities, ObjectMapper objectMapper) { | ||
| return new AnswersResponse( | ||
| entities.stream() | ||
| .map(a -> AnswerResponse.from(a, objectMapper)) | ||
| .toList() | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package inha.gdgoc.domain.recruit.dto.response; | ||
|
|
||
| public record CheckPhoneNumberResponse(boolean isExists) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package inha.gdgoc.domain.recruit.dto.response; | ||
|
|
||
| public record CheckStudentIdResponse(boolean isExists) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,29 @@ | ||
| package inha.gdgoc.domain.recruit.dto.response; | ||
|
|
||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import inha.gdgoc.domain.recruit.entity.Answer; | ||
| import inha.gdgoc.domain.recruit.entity.RecruitMember; | ||
| import java.util.List; | ||
|
|
||
| public record SpecifiedMemberResponse( | ||
| String name, | ||
| String major, | ||
| String studentId, | ||
| boolean isPayed | ||
| boolean isPayed, | ||
| AnswersResponse answers | ||
| ) { | ||
|
|
||
| public static SpecifiedMemberResponse from(RecruitMember member) { | ||
| public static SpecifiedMemberResponse from( | ||
| RecruitMember member, | ||
| List<Answer> answers, | ||
| ObjectMapper objectMapper | ||
| ) { | ||
| return new SpecifiedMemberResponse( | ||
| member.getName(), | ||
| member.getMajor(), | ||
| member.getStudentId(), | ||
| Boolean.TRUE.equals(member.getIsPayed()) | ||
| Boolean.TRUE.equals(member.getIsPayed()), | ||
| AnswersResponse.from(answers, objectMapper) | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,15 @@ | ||
| package inha.gdgoc.domain.recruit.repository; | ||
|
|
||
| import inha.gdgoc.domain.recruit.entity.Answer; | ||
| import inha.gdgoc.domain.recruit.entity.RecruitMember; | ||
| import inha.gdgoc.domain.recruit.enums.SurveyType; | ||
| import java.util.List; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| public interface AnswerRepository extends JpaRepository<Answer, Long> { | ||
|
|
||
| List<Answer> findByRecruitMemberAndSurveyType( | ||
| RecruitMember recruitMember, | ||
| SurveyType surveyType | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
메서드 파라미터 검증 활성화를 위한 @validated 필요
컨트롤러에
@Validated가 없어@RequestParam의@NotBlank/@Pattern제약이 적용되지 않습니다. 클래스 레벨에 추가해 주세요.@RequestMapping("/api/v1") @RequiredArgsConstructor @RestController +@org.springframework.validation.annotation.Validated public class RecruitMemberController {Also applies to: 29-32
🤖 Prompt for AI Agents