From a0cd6a842762065bd335d996f20da0bf3ab5df3e Mon Sep 17 00:00:00 2001 From: koseonje Date: Mon, 3 Feb 2025 15:03:53 +0900 Subject: [PATCH] =?UTF-8?q?[DDING-86]=20=EB=8F=99=EC=95=84=EB=A6=AC=20?= =?UTF-8?q?=EC=A7=80=EC=9B=90=20=ED=8F=BC=EC=A7=80=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?API=20=EA=B5=AC=ED=98=84=20(#231)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../club/service/GeneralClubService.java | 3 +- .../domain/form/api/CentralFormApi.java | 14 +++ .../controller/CentralFormController.java | 10 +++ .../dto/request/UpdateFormRequest.java | 88 +++++++++++++++++++ .../ddingdongBE/domain/form/entity/Form.java | 18 +++- .../domain/form/entity/FormField.java | 11 ++- .../form/repository/FormFieldRepository.java | 3 + .../service/FacadeCentralFormService.java | 3 + .../service/FacadeCentralFormServiceImpl.java | 26 +++++- .../domain/form/service/FormFieldService.java | 5 ++ .../domain/form/service/FormService.java | 2 + .../form/service/GeneralFormFieldService.java | 12 +++ .../form/service/GeneralFormService.java | 7 ++ .../dto/command/UpdateFormCommand.java | 53 +++++++++++ .../FacadeCentralFormServiceImplTest.java | 47 ++++++++++ 15 files changed, 295 insertions(+), 7 deletions(-) create mode 100644 src/main/java/ddingdong/ddingdongBE/domain/form/controller/dto/request/UpdateFormRequest.java create mode 100644 src/main/java/ddingdong/ddingdongBE/domain/form/service/dto/command/UpdateFormCommand.java diff --git a/src/main/java/ddingdong/ddingdongBE/domain/club/service/GeneralClubService.java b/src/main/java/ddingdong/ddingdongBE/domain/club/service/GeneralClubService.java index 086651e7..ed5d83b2 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/club/service/GeneralClubService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/club/service/GeneralClubService.java @@ -39,7 +39,8 @@ public Club getByUserId(Long userId) { @Override public Club getByUserIdWithFetch(Long userId) { return clubRepository.findEntityGraphByUserId(userId) - .orElseThrow(() -> new ResourceNotFound("Club(userId=" + userId + ")를 찾을 수 없습니다.")); } + .orElseThrow(() -> new ResourceNotFound("Club(userId=" + userId + ")를 찾을 수 없습니다.")); + } @Override public List findAll() { diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/api/CentralFormApi.java b/src/main/java/ddingdong/ddingdongBE/domain/form/api/CentralFormApi.java index 0c2dbf26..7f4bed0c 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/api/CentralFormApi.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/api/CentralFormApi.java @@ -2,13 +2,16 @@ import ddingdong.ddingdongBE.auth.PrincipalDetails; import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest; +import ddingdong.ddingdongBE.domain.form.controller.dto.request.UpdateFormRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.HttpStatus; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; @@ -26,4 +29,15 @@ void createForm( @RequestBody CreateFormRequest createFormRequest, @AuthenticationPrincipal PrincipalDetails principalDetails ); + + @Operation(summary = "동아리 지원 폼지 수정 API") + @ApiResponse(responseCode = "204", description = "동아리 지원 폼지 수정 성공") + @ResponseStatus(HttpStatus.NO_CONTENT) + @SecurityRequirement(name = "AccessToken") + @PutMapping("/my/forms/{formId}") + void updateForm( + @RequestBody UpdateFormRequest updateFormRequest, + @PathVariable("formId") Long formId, + @AuthenticationPrincipal PrincipalDetails principalDetails + ); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/controller/CentralFormController.java b/src/main/java/ddingdong/ddingdongBE/domain/form/controller/CentralFormController.java index 19a20e79..5e467fad 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/controller/CentralFormController.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/controller/CentralFormController.java @@ -3,6 +3,7 @@ import ddingdong.ddingdongBE.auth.PrincipalDetails; import ddingdong.ddingdongBE.domain.form.api.CentralFormApi; import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest; +import ddingdong.ddingdongBE.domain.form.controller.dto.request.UpdateFormRequest; import ddingdong.ddingdongBE.domain.form.service.FacadeCentralFormService; import ddingdong.ddingdongBE.domain.user.entity.User; import lombok.RequiredArgsConstructor; @@ -22,4 +23,13 @@ public void createForm( User user = principalDetails.getUser(); facadeCentralFormService.createForm(createFormRequest.toCommand(user)); } + + @Override + public void updateForm( + UpdateFormRequest updateFormRequest, + Long formId, + PrincipalDetails principalDetails + ) { + facadeCentralFormService.updateForm(updateFormRequest.toCommand(formId)); + } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/controller/dto/request/UpdateFormRequest.java b/src/main/java/ddingdong/ddingdongBE/domain/form/controller/dto/request/UpdateFormRequest.java new file mode 100644 index 00000000..eebf3b91 --- /dev/null +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/controller/dto/request/UpdateFormRequest.java @@ -0,0 +1,88 @@ +package ddingdong.ddingdongBE.domain.form.controller.dto.request; + +import ddingdong.ddingdongBE.domain.form.entity.FieldType; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand.UpdateFormFieldCommand; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDate; +import java.util.List; + +public record UpdateFormRequest( + @Schema(description = "폼지 제목", example = "폼지제목입니다") + @NotNull(message = "폼지 제목은 null이 될 수 없습니다.") + String title, + + @Schema(description = "폼지 설명", example = "우리 동아리는 띵동입니다.") + String description, + + @Schema(description = "폼지 시작일자", example = "2001-01-01") + @NotNull(message = "폼지 시작일자는 null이 될 수 없습니다.") + LocalDate startDate, + + @Schema(description = "폼지 종료일자", example = "2001-01-02") + @NotNull(message = "폼지 종료일자는 null이 될 수 없습니다.") + LocalDate endDate, + + @Schema(description = "면접여부", example = "true") + @NotNull(message = "면접여부는 null이 될 수 없습니다.") + boolean hasInterview, + + @ArraySchema(schema = @Schema(implementation = UpdateFormFieldRequest.class)) + List formFields +) { + + record UpdateFormFieldRequest( + @Schema(description = "폼지 질문", example = "우리 동아리 들어올겁니까?") + @NotNull(message = "질문는 null이 될 수 없습니다.") + String question, + + @Schema(description = "질문 종류", example = "CHECK_BOX") + @NotNull(message = "질문 종류는 null이 될 수 없습니다.") + FieldType type, + + @Schema(description = "질문의 선택리스트", example = "[지문1이다., 지문2이다., 지문3이다.]") + List options, + + @Schema(description = "필수여부", example = "true") + @NotNull(message = "필수여부는 null이 될 수 없습니다.") + boolean required, + + @Schema(description = "질문 순서", example = "1") + @NotNull(message = "질문 순서는 null이 될 수 없습니다.") + int order, + + @Schema(description = "질문 섹션 종류", example = "공통") + @NotNull(message = "질문 섹션종류는 null이 될 수 없습니다.") + String section + ) { + + public UpdateFormFieldCommand toCommand() { + return UpdateFormFieldCommand.builder() + .question(question) + .type(type) + .options(options) + .required(required) + .order(order) + .section(section) + .build(); + } + } + + public UpdateFormCommand toCommand(Long formId) { + List updateFormFieldCommands = formFields.stream() + .map(UpdateFormFieldRequest::toCommand) + .toList(); + return UpdateFormCommand.builder() + .formId(formId) + .title(title) + .description(description) + .startDate(startDate) + .endDate(endDate) + .hasInterview(hasInterview) + .formFieldCommands(updateFormFieldCommands) + .build(); + } + +} diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/entity/Form.java b/src/main/java/ddingdong/ddingdongBE/domain/form/entity/Form.java index aea56abc..05ef3635 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/entity/Form.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/entity/Form.java @@ -42,8 +42,14 @@ public class Form extends BaseEntity { private Club club; @Builder - private Form(String title, String description, LocalDate startDate, LocalDate endDate, boolean hasInterview, - Club club) { + private Form( + String title, + String description, + LocalDate startDate, + LocalDate endDate, + boolean hasInterview, + Club club + ) { this.title = title; this.description = description; this.startDate = startDate; @@ -51,4 +57,12 @@ private Form(String title, String description, LocalDate startDate, LocalDate en this.hasInterview = hasInterview; this.club = club; } + + public void update(Form updateForm) { + this.title = updateForm.getTitle(); + this.description = updateForm.getDescription(); + this.startDate = updateForm.getStartDate(); + this.endDate = updateForm.getEndDate(); + this.hasInterview = updateForm.isHasInterview(); + } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/entity/FormField.java b/src/main/java/ddingdong/ddingdongBE/domain/form/entity/FormField.java index e810fbcb..1cc5d56a 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/entity/FormField.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/entity/FormField.java @@ -50,8 +50,15 @@ public class FormField extends BaseEntity { private Form form; @Builder - private FormField(String question, FieldType fieldType, boolean required, int fieldOrder, String section, - List options, Form form) { + private FormField( + String question, + FieldType fieldType, + boolean required, + int fieldOrder, + String section, + List options, + Form form + ) { this.question = question; this.fieldType = fieldType; this.required = required; diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/repository/FormFieldRepository.java b/src/main/java/ddingdong/ddingdongBE/domain/form/repository/FormFieldRepository.java index 0480309b..9a8db1e1 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/repository/FormFieldRepository.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/repository/FormFieldRepository.java @@ -1,8 +1,11 @@ package ddingdong.ddingdongBE.domain.form.repository; +import ddingdong.ddingdongBE.domain.form.entity.Form; import ddingdong.ddingdongBE.domain.form.entity.FormField; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface FormFieldRepository extends JpaRepository { + List findAllByForm(Form form); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormService.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormService.java index 3ed8153e..6522f17b 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormService.java @@ -1,8 +1,11 @@ package ddingdong.ddingdongBE.domain.form.service; import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand; public interface FacadeCentralFormService { void createForm(CreateFormCommand command); + + void updateForm(UpdateFormCommand command); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java index 36c623f7..81c9d080 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java @@ -6,6 +6,8 @@ import ddingdong.ddingdongBE.domain.form.entity.FormField; import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand; import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand.CreateFormFieldCommand; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand.UpdateFormFieldCommand; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -27,11 +29,31 @@ public void createForm(CreateFormCommand createFormCommand) { Form form = createFormCommand.toEntity(club); Form savedForm = formService.create(form); - List formFields = toFormFields(savedForm, createFormCommand.formFieldCommands()); + List formFields = toCreateFormFields(savedForm, createFormCommand.formFieldCommands()); formFieldService.createAll(formFields); } - private List toFormFields(Form savedForm, List createFormFieldCommands) { + @Transactional + @Override + public void updateForm(UpdateFormCommand updateFormCommand) { + Form originform = formService.getById(updateFormCommand.formId()); + Form updateForm = updateFormCommand.toEntity(); + originform.update(updateForm); + + List originFormFields = formFieldService.findAllByForm(originform); + formFieldService.deleteAll(originFormFields); + + List updateFormFields = toUpdateFormFields(originform, updateFormCommand.formFieldCommands()); + formFieldService.createAll(updateFormFields); + } + + private List toUpdateFormFields(Form originform, List updateFormFieldCommands) { + return updateFormFieldCommands.stream() + .map(formFieldCommand -> formFieldCommand.toEntity(originform)) + .toList(); + } + + private List toCreateFormFields(Form savedForm, List createFormFieldCommands) { return createFormFieldCommands.stream() .map(formFieldCommand -> formFieldCommand.toEntity(savedForm)) .toList(); diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormFieldService.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormFieldService.java index 72c4346e..d173c0db 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormFieldService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormFieldService.java @@ -1,9 +1,14 @@ package ddingdong.ddingdongBE.domain.form.service; +import ddingdong.ddingdongBE.domain.form.entity.Form; import ddingdong.ddingdongBE.domain.form.entity.FormField; import java.util.List; public interface FormFieldService { void createAll(List formFields); + + List findAllByForm(Form form); + + void deleteAll(List originFormFields); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormService.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormService.java index 059f43d7..a065dca5 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/FormService.java @@ -5,4 +5,6 @@ public interface FormService { Form create(Form form); + + Form getById(Long formId); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormFieldService.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormFieldService.java index 2c0c1237..20696576 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormFieldService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormFieldService.java @@ -1,5 +1,6 @@ package ddingdong.ddingdongBE.domain.form.service; +import ddingdong.ddingdongBE.domain.form.entity.Form; import ddingdong.ddingdongBE.domain.form.entity.FormField; import ddingdong.ddingdongBE.domain.form.repository.FormFieldRepository; import java.util.List; @@ -19,4 +20,15 @@ public class GeneralFormFieldService implements FormFieldService { public void createAll(List formFields) { formFieldRepository.saveAll(formFields); } + + @Override + public List findAllByForm(Form form) { + return formFieldRepository.findAllByForm(form); + } + + @Transactional + @Override + public void deleteAll(List originFormFields) { + formFieldRepository.deleteAll(originFormFields); + } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormService.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormService.java index 922608ef..1e9d490a 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/GeneralFormService.java @@ -1,5 +1,6 @@ package ddingdong.ddingdongBE.domain.form.service; +import ddingdong.ddingdongBE.common.exception.PersistenceException.ResourceNotFound; import ddingdong.ddingdongBE.domain.form.entity.Form; import ddingdong.ddingdongBE.domain.form.repository.FormRepository; import lombok.RequiredArgsConstructor; @@ -18,4 +19,10 @@ public class GeneralFormService implements FormService{ public Form create(Form form) { return formRepository.save(form); } + + @Override + public Form getById(Long formId) { + return formRepository.findById(formId) + .orElseThrow(() -> new ResourceNotFound("Form(formId=" + formId + ")를 찾을 수 없습니다.")); + } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/form/service/dto/command/UpdateFormCommand.java b/src/main/java/ddingdong/ddingdongBE/domain/form/service/dto/command/UpdateFormCommand.java new file mode 100644 index 00000000..f81a0c9b --- /dev/null +++ b/src/main/java/ddingdong/ddingdongBE/domain/form/service/dto/command/UpdateFormCommand.java @@ -0,0 +1,53 @@ +package ddingdong.ddingdongBE.domain.form.service.dto.command; + +import ddingdong.ddingdongBE.domain.form.entity.FieldType; +import ddingdong.ddingdongBE.domain.form.entity.Form; +import ddingdong.ddingdongBE.domain.form.entity.FormField; +import java.time.LocalDate; +import java.util.List; +import lombok.Builder; + +@Builder +public record UpdateFormCommand( + Long formId, + String title, + String description, + LocalDate startDate, + LocalDate endDate, + boolean hasInterview, + List formFieldCommands +) { + + @Builder + public record UpdateFormFieldCommand( + String question, + FieldType type, + List options, + boolean required, + int order, + String section + ) { + + public FormField toEntity(Form form) { + return FormField.builder() + .form(form) + .question(question) + .fieldType(type) + .options(options) + .required(required) + .fieldOrder(order) + .section(section) + .build(); + } + } + + public Form toEntity() { + return Form.builder() + .title(title) + .description(description) + .startDate(startDate) + .endDate(endDate) + .hasInterview(hasInterview) + .build(); + } +} diff --git a/src/test/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImplTest.java b/src/test/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImplTest.java index fc50d37e..ceb8c07d 100644 --- a/src/test/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImplTest.java +++ b/src/test/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImplTest.java @@ -12,6 +12,8 @@ import ddingdong.ddingdongBE.domain.form.repository.FormFieldRepository; import ddingdong.ddingdongBE.domain.form.repository.FormRepository; import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand; +import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand.UpdateFormFieldCommand; import ddingdong.ddingdongBE.domain.user.entity.Role; import ddingdong.ddingdongBE.domain.user.entity.User; import ddingdong.ddingdongBE.domain.user.repository.UserRepository; @@ -74,4 +76,49 @@ void createForm() { assertThat(form).isNotEmpty(); assertThat(formFields).isNotEmpty(); } + + @DisplayName("폼지와 폼지 질문을 수정할 수 있다.") + @Test + void updateForm() { + // given + User user = fixtureMonkey.giveMeBuilder(User.class) + .set("id", 1L) + .set("Role", Role.CLUB) + .set("deletedAt", null) + .sample(); + User savedUser = userRepository.save(user); + Club club = fixtureMonkey.giveMeBuilder(Club.class) + .set("id", 1L) + .set("user", savedUser) + .set("score", null) + .set("clubMembers", null) + .set("deletedAt", null) + .sample(); + clubRepository.save(club); + Form form = fixtureMonkey.giveMeBuilder(Form.class) + .set("club", club) + .sample(); + Form savedForm = formService.create(form); + UpdateFormCommand updateFormCommand = fixtureMonkey.giveMeBuilder(UpdateFormCommand.class) + .set("title", "수정된 제목") + .set("description", "수정된 설명") + .set("formId", savedForm.getId()) + .set("formFieldCommands", List.of( + fixtureMonkey.giveMeBuilder(UpdateFormFieldCommand.class) + .set("question", "수정된 질문") + .sample()) + ) + .sample(); + // when + facadeCentralFormService.updateForm(updateFormCommand); + // then + Form found = formRepository.findById(savedForm.getId()).orElse(null); + List formFields = formFieldRepository.findAllByForm(found); + assertThat(found).isNotNull(); + assertThat(found.getTitle()).isEqualTo("수정된 제목"); + assertThat(found.getDescription()).isEqualTo("수정된 설명"); + assertThat(formFields).isNotEmpty(); + assertThat(formFields.get(0).getQuestion()).isEqualTo("수정된 질문"); + + } }