Skip to content

Commit

Permalink
[DDING-85] 동아리 지원폼지 생성 API 구현 (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
KoSeonJe authored Jan 31, 2025
1 parent 48ce276 commit 38896cf
Show file tree
Hide file tree
Showing 11 changed files with 384 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ddingdong.ddingdongBE.domain.form.api;

import ddingdong.ddingdongBE.auth.PrincipalDetails;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;

@Tag(name = "Form - Club", description = "Form API")
@RequestMapping("/server/central")
public interface CentralFormApi {

@Operation(summary = "동아리 지원 폼지 생성 API")
@ApiResponse(responseCode = "201", description = "동아리 지원 폼지 생성 성공")
@ResponseStatus(HttpStatus.CREATED)
@SecurityRequirement(name = "AccessToken")
@PostMapping("/my/forms")
void createForm(
@RequestBody CreateFormRequest createFormRequest,
@AuthenticationPrincipal PrincipalDetails principalDetails
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ddingdong.ddingdongBE.domain.form.controller;

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.service.FacadeCentralFormService;
import ddingdong.ddingdongBE.domain.user.entity.User;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class CentralFormController implements CentralFormApi {

private final FacadeCentralFormService facadeCentralFormService;

@Override
public void createForm(
CreateFormRequest createFormRequest,
PrincipalDetails principalDetails
) {
User user = principalDetails.getUser();
facadeCentralFormService.createForm(createFormRequest.toCommand(user));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package ddingdong.ddingdongBE.domain.form.controller.dto.request;

import ddingdong.ddingdongBE.domain.form.entity.FieldType;
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand;
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand.CreateFormFieldCommand;
import ddingdong.ddingdongBE.domain.user.entity.User;
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 CreateFormRequest(
@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 = CreateFormFieldRequest.class))
List<CreateFormFieldRequest> formFields
) {

record CreateFormFieldRequest(
@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<String> 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 CreateFormFieldCommand toCommand() {
return CreateFormFieldCommand.builder()
.question(question)
.type(type)
.options(options)
.required(required)
.order(order)
.section(section)
.build();
}
}

public CreateFormCommand toCommand(User user) {
List<CreateFormFieldCommand> createFormFieldCommands = formFields.stream()
.map(CreateFormFieldRequest::toCommand)
.toList();
return CreateFormCommand.builder()
.user(user)
.title(title)
.description(description)
.startDate(startDate)
.endDate(endDate)
.hasInterview(hasInterview)
.formFieldCommands(createFormFieldCommands)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ddingdong.ddingdongBE.domain.form.service;

import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand;

public interface FacadeCentralFormService {

void createForm(CreateFormCommand command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ddingdong.ddingdongBE.domain.form.service;

import ddingdong.ddingdongBE.domain.club.entity.Club;
import ddingdong.ddingdongBE.domain.club.service.ClubService;
import ddingdong.ddingdongBE.domain.form.entity.Form;
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 java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class FacadeCentralFormServiceImpl implements FacadeCentralFormService{

private final FormService formService;
private final FormFieldService formFieldService;
private final ClubService clubService;

@Transactional
@Override
public void createForm(CreateFormCommand createFormCommand) {
Club club = clubService.getByUserId(createFormCommand.user().getId());
Form form = createFormCommand.toEntity(club);
Form savedForm = formService.create(form);

List<FormField> formFields = toFormFields(savedForm, createFormCommand.formFieldCommands());
formFieldService.createAll(formFields);
}

private List<FormField> toFormFields(Form savedForm, List<CreateFormFieldCommand> createFormFieldCommands) {
return createFormFieldCommands.stream()
.map(formFieldCommand -> formFieldCommand.toEntity(savedForm))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ddingdong.ddingdongBE.domain.form.service;

import ddingdong.ddingdongBE.domain.form.entity.FormField;
import java.util.List;

public interface FormFieldService {

void createAll(List<FormField> formFields);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ddingdong.ddingdongBE.domain.form.service;

import ddingdong.ddingdongBE.domain.form.entity.Form;

public interface FormService {

Form create(Form form);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ddingdong.ddingdongBE.domain.form.service;

import ddingdong.ddingdongBE.domain.form.entity.FormField;
import ddingdong.ddingdongBE.domain.form.repository.FormFieldRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class GeneralFormFieldService implements FormFieldService {

private final FormFieldRepository formFieldRepository;

@Transactional
@Override
public void createAll(List<FormField> formFields) {
formFieldRepository.saveAll(formFields);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ddingdong.ddingdongBE.domain.form.service;

import ddingdong.ddingdongBE.domain.form.entity.Form;
import ddingdong.ddingdongBE.domain.form.repository.FormRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class GeneralFormService implements FormService{

private final FormRepository formRepository;

@Transactional
@Override
public Form create(Form form) {
return formRepository.save(form);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package ddingdong.ddingdongBE.domain.form.service.dto.command;

import ddingdong.ddingdongBE.domain.club.entity.Club;
import ddingdong.ddingdongBE.domain.form.entity.FieldType;
import ddingdong.ddingdongBE.domain.form.entity.Form;
import ddingdong.ddingdongBE.domain.form.entity.FormField;
import ddingdong.ddingdongBE.domain.user.entity.User;
import java.time.LocalDate;
import java.util.List;
import lombok.Builder;

@Builder
public record CreateFormCommand(
User user,
String title,
String description,
LocalDate startDate,
LocalDate endDate,
boolean hasInterview,
List<CreateFormFieldCommand> formFieldCommands
) {

@Builder
public record CreateFormFieldCommand(
String question,
FieldType type,
List<String> options,
boolean required,
int order,
String section
) {

public FormField toEntity(Form savedForm) {
return FormField.builder()
.question(question)
.fieldType(type)
.options(options)
.required(required)
.fieldOrder(order)
.section(section)
.form(savedForm)
.build();
}
}

public Form toEntity(Club club) {
return Form.builder()
.title(title)
.description(description)
.startDate(startDate)
.endDate(endDate)
.hasInterview(hasInterview)
.club(club)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package ddingdong.ddingdongBE.domain.form.service;

import static org.assertj.core.api.Assertions.assertThat;

import com.navercorp.fixturemonkey.FixtureMonkey;
import ddingdong.ddingdongBE.common.support.FixtureMonkeyFactory;
import ddingdong.ddingdongBE.common.support.TestContainerSupport;
import ddingdong.ddingdongBE.domain.club.entity.Club;
import ddingdong.ddingdongBE.domain.club.repository.ClubRepository;
import ddingdong.ddingdongBE.domain.form.entity.Form;
import ddingdong.ddingdongBE.domain.form.entity.FormField;
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.user.entity.Role;
import ddingdong.ddingdongBE.domain.user.entity.User;
import ddingdong.ddingdongBE.domain.user.repository.UserRepository;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class FacadeCentralFormServiceImplTest extends TestContainerSupport {

@Autowired
private FormService formService;

@Autowired
private FormRepository formRepository;

@Autowired
private FacadeCentralFormService facadeCentralFormService;

@Autowired
private ClubRepository clubRepository;

@Autowired
private UserRepository userRepository;

@Autowired
private FormFieldRepository formFieldRepository;

private static final FixtureMonkey fixtureMonkey = FixtureMonkeyFactory.getNotNullBuilderIntrospectorMonkey();

@DisplayName("폼지와 폼지 질문을 생성할 수 있다.")
@Test
void createForm() {
// 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);
CreateFormCommand createFormCommand = fixtureMonkey.giveMeBuilder(CreateFormCommand.class)
.set("user", savedUser)
.sample();
// when
facadeCentralFormService.createForm(createFormCommand);
// then
List<Form> form = formRepository.findAll();
List<FormField> formFields = formFieldRepository.findAll();

assertThat(form).isNotEmpty();
assertThat(formFields).isNotEmpty();
}
}

0 comments on commit 38896cf

Please sign in to comment.