From 644c45d7fd4d0441586460072e3446c2faf52f09 Mon Sep 17 00:00:00 2001 From: JM Kim <106949557+CSE-Shaco@users.noreply.github.com> Date: Sat, 14 Feb 2026 21:30:25 +0900 Subject: [PATCH] feat(recruit-member): align answer input types and persist proof file upload --- .../controller/RecruitMemberController.java | 4 +-- .../recruit/member/enums/InputType.java | 36 +++++++++++++------ .../member/service/RecruitMemberService.java | 34 +++++++++++++----- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/main/java/inha/gdgoc/domain/recruit/member/controller/RecruitMemberController.java b/src/main/java/inha/gdgoc/domain/recruit/member/controller/RecruitMemberController.java index 3cdeae7..0121afe 100644 --- a/src/main/java/inha/gdgoc/domain/recruit/member/controller/RecruitMemberController.java +++ b/src/main/java/inha/gdgoc/domain/recruit/member/controller/RecruitMemberController.java @@ -71,7 +71,7 @@ public class RecruitMemberController { public ResponseEntity> recruitMemberAdd( @RequestBody Map applicationRequest ) { - recruitMemberService.addRecruitMember(applicationRequest); + recruitMemberService.addRecruitMember(applicationRequest, null); return ResponseEntity.ok(ApiResponse.ok(MEMBER_SAVE_SUCCESS)); } @@ -81,7 +81,7 @@ public ResponseEntity> recruitMemberAddMultipart( @RequestPart("request") Map applicationRequest, @RequestPart(value = "file", required = false) MultipartFile file ) { - recruitMemberService.addRecruitMember(applicationRequest); + recruitMemberService.addRecruitMember(applicationRequest, file); return ResponseEntity.ok(ApiResponse.ok(MEMBER_SAVE_SUCCESS)); } diff --git a/src/main/java/inha/gdgoc/domain/recruit/member/enums/InputType.java b/src/main/java/inha/gdgoc/domain/recruit/member/enums/InputType.java index 40db4f2..f2c7b2d 100644 --- a/src/main/java/inha/gdgoc/domain/recruit/member/enums/InputType.java +++ b/src/main/java/inha/gdgoc/domain/recruit/member/enums/InputType.java @@ -1,20 +1,37 @@ package inha.gdgoc.domain.recruit.member.enums; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; import lombok.Getter; @Getter public enum InputType { - APPLY_MOTIVATION("gdgUserMotive", "String"), - LIFE_STORY("gdgUserStory", "String"), + // Recruit Member INTERESTS("gdgInterest", "List"), - GDG_PERIOD("gdgPeriod", "List"), - ROUTE_TO_KNOW("gdgRoute", "String"), - WANT_TO_GET("gdgExpect", "String"), EXPECTED_ACTIVITY("gdgWish", "List"), - FEEDBACK("gdgFeedback", "String"); + FEEDBACK("gdgFeedback", "String"), + PROOF_FILE("proofFileUrl", "String"), + + // Recruit Core + CORE_MOTIVATION("motivation", "String"), + CORE_WISH("wish", "String"), + CORE_STRENGTHS("strengths", "String"), + CORE_PLEDGE("pledge", "String"), + CORE_FILE_URLS("fileUrls", "List"), + + // Legacy aliases (keep for existing DB rows / old payloads) + @Deprecated APPLY_MOTIVATION("gdgUserMotive", "String"), + @Deprecated LIFE_STORY("gdgUserStory", "String"), + @Deprecated GDG_PERIOD("gdgPeriod", "List"), + @Deprecated ROUTE_TO_KNOW("gdgRoute", "String"), + @Deprecated WANT_TO_GET("gdgExpect", "String"); private final String question; private final String dataType; + private static final Map LOOKUP = Arrays.stream(values()) + .collect(Collectors.toUnmodifiableMap(InputType::getQuestion, Function.identity(), (first, second) -> first)); InputType(String question, String dataType) { this.question = question; @@ -22,10 +39,9 @@ public enum InputType { } public static InputType fromQuestion(String question) { - for (InputType inputType : InputType.values()) { - if (inputType.question.equals(question)) { - return inputType; - } + InputType inputType = LOOKUP.get(question); + if (inputType != null) { + return inputType; } throw new IllegalArgumentException("Invalid question value: " + question); } diff --git a/src/main/java/inha/gdgoc/domain/recruit/member/service/RecruitMemberService.java b/src/main/java/inha/gdgoc/domain/recruit/member/service/RecruitMemberService.java index 8e2e972..c3e7028 100644 --- a/src/main/java/inha/gdgoc/domain/recruit/member/service/RecruitMemberService.java +++ b/src/main/java/inha/gdgoc/domain/recruit/member/service/RecruitMemberService.java @@ -4,6 +4,8 @@ import static inha.gdgoc.domain.recruit.member.exception.RecruitMemberErrorCode.RECRUIT_MEMBER_ALREADY_APPLIED; import com.fasterxml.jackson.databind.ObjectMapper; +import inha.gdgoc.domain.resource.enums.S3KeyType; +import inha.gdgoc.domain.resource.service.S3Service; import inha.gdgoc.domain.recruit.member.dto.request.ApplicationRequest; import inha.gdgoc.domain.recruit.member.dto.request.RecruitMemberMemoRequest; import inha.gdgoc.domain.recruit.member.dto.request.RecruitMemberRequest; @@ -28,6 +30,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; @RequiredArgsConstructor @Service @@ -37,9 +40,10 @@ public class RecruitMemberService { private final AnswerRepository answerRepository; private final ObjectMapper objectMapper; private final SemesterCalculator semesterCalculator; + private final S3Service s3Service; @Transactional - public void addRecruitMember(Map requestPayload) { + public void addRecruitMember(Map requestPayload, MultipartFile file) { RecruitMemberRequest memberRequest; Map answers; @@ -52,6 +56,12 @@ public void addRecruitMember(Map requestPayload) { answers = buildAnswersFromNumberedPayload(requestPayload); } + if (file != null && !file.isEmpty()) { + String key = uploadProofFile(file); + String proofFileUrl = s3Service.getS3FileUrl(key); + answers.put("proofFileUrl", proofFileUrl); + } + RecruitMember member = memberRequest .toEntity(semesterCalculator.currentSemester()); recruitMemberRepository.save(member); @@ -72,6 +82,14 @@ public void addRecruitMember(Map requestPayload) { answerRepository.saveAll(answerEntities); } + private String uploadProofFile(MultipartFile file) { + try { + return s3Service.upload(0L, S3KeyType.study, file); + } catch (Exception e) { + throw new RuntimeException("증빙 파일 업로드 중 오류가 발생했습니다.", e); + } + } + @Transactional public void addRecruitMemberMemo(RecruitMemberMemoRequest recruitMemberMemoRequest) { String cleanPhone = normalizePhoneNumber(recruitMemberMemoRequest.getPhoneNumber()); @@ -144,7 +162,7 @@ private RecruitMemberRequest buildMemberFromNumberedPayload(Map Map step3 = asMap(payload.get("3")); Map step4 = asMap(payload.get("4")); Map step5 = asMap(payload.get("5")); - Map step11 = asMap(payload.get("11")); + Map step6 = asMap(payload.get("6")); Map member = new HashMap<>(); member.put("name", step2.get("name")); @@ -155,20 +173,18 @@ private RecruitMemberRequest buildMemberFromNumberedPayload(Map member.put("gender", step4.get("gender")); member.put("birth", step4.get("birth")); member.put("major", step5.get("major")); - member.put("isPayed", step11.getOrDefault("isPayed", false)); + member.put("isPayed", step6.getOrDefault("isPayed", false)); return objectMapper.convertValue(member, RecruitMemberRequest.class); } private Map buildAnswersFromNumberedPayload(Map payload) { - Map step8 = asMap(payload.get("8")); - Map step9 = asMap(payload.get("9")); - Map step10 = asMap(payload.get("10")); + Map step6 = asMap(payload.get("6")); Map answers = new HashMap<>(); - putIfPresent(answers, "gdgInterest", step8.get("gdgInterest")); - putIfPresent(answers, "gdgWish", step9.get("gdgWish")); - putIfPresent(answers, "gdgFeedback", step10.get("gdgFeedback")); + putIfPresent(answers, "gdgInterest", step6.get("gdgInterest")); + putIfPresent(answers, "gdgWish", step6.get("gdgWish")); + putIfPresent(answers, "gdgFeedback", step6.get("gdgFeedback")); return answers; }