Skip to content

Commit 38896cf

Browse files
authored
[DDING-85] 동아리 지원폼지 생성 API 구현 (#230)
1 parent 48ce276 commit 38896cf

File tree

11 files changed

+384
-0
lines changed

11 files changed

+384
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package ddingdong.ddingdongBE.domain.form.api;
2+
3+
import ddingdong.ddingdongBE.auth.PrincipalDetails;
4+
import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest;
5+
import io.swagger.v3.oas.annotations.Operation;
6+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
7+
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
8+
import io.swagger.v3.oas.annotations.tags.Tag;
9+
import org.springframework.http.HttpStatus;
10+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.RequestBody;
13+
import org.springframework.web.bind.annotation.RequestMapping;
14+
import org.springframework.web.bind.annotation.ResponseStatus;
15+
16+
@Tag(name = "Form - Club", description = "Form API")
17+
@RequestMapping("/server/central")
18+
public interface CentralFormApi {
19+
20+
@Operation(summary = "동아리 지원 폼지 생성 API")
21+
@ApiResponse(responseCode = "201", description = "동아리 지원 폼지 생성 성공")
22+
@ResponseStatus(HttpStatus.CREATED)
23+
@SecurityRequirement(name = "AccessToken")
24+
@PostMapping("/my/forms")
25+
void createForm(
26+
@RequestBody CreateFormRequest createFormRequest,
27+
@AuthenticationPrincipal PrincipalDetails principalDetails
28+
);
29+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package ddingdong.ddingdongBE.domain.form.controller;
2+
3+
import ddingdong.ddingdongBE.auth.PrincipalDetails;
4+
import ddingdong.ddingdongBE.domain.form.api.CentralFormApi;
5+
import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest;
6+
import ddingdong.ddingdongBE.domain.form.service.FacadeCentralFormService;
7+
import ddingdong.ddingdongBE.domain.user.entity.User;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
@RestController
12+
@RequiredArgsConstructor
13+
public class CentralFormController implements CentralFormApi {
14+
15+
private final FacadeCentralFormService facadeCentralFormService;
16+
17+
@Override
18+
public void createForm(
19+
CreateFormRequest createFormRequest,
20+
PrincipalDetails principalDetails
21+
) {
22+
User user = principalDetails.getUser();
23+
facadeCentralFormService.createForm(createFormRequest.toCommand(user));
24+
}
25+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package ddingdong.ddingdongBE.domain.form.controller.dto.request;
2+
3+
import ddingdong.ddingdongBE.domain.form.entity.FieldType;
4+
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand;
5+
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand.CreateFormFieldCommand;
6+
import ddingdong.ddingdongBE.domain.user.entity.User;
7+
import io.swagger.v3.oas.annotations.media.ArraySchema;
8+
import io.swagger.v3.oas.annotations.media.Schema;
9+
import jakarta.validation.constraints.NotNull;
10+
import java.time.LocalDate;
11+
import java.util.List;
12+
13+
14+
public record CreateFormRequest(
15+
@Schema(description = "폼지 제목", example = "폼지제목입니다")
16+
@NotNull(message = "폼지 제목은 null이 될 수 없습니다.")
17+
String title,
18+
19+
@Schema(description = "폼지 설명", example = "우리 동아리는 띵동입니다.")
20+
String description,
21+
22+
@Schema(description = "폼지 시작일자", example = "2001-01-01")
23+
@NotNull(message = "폼지 시작일자는 null이 될 수 없습니다.")
24+
LocalDate startDate,
25+
26+
@Schema(description = "폼지 종료일자", example = "2001-01-02")
27+
@NotNull(message = "폼지 종료일자는 null이 될 수 없습니다.")
28+
LocalDate endDate,
29+
30+
@Schema(description = "면접여부", example = "true")
31+
@NotNull(message = "면접여부는 null이 될 수 없습니다.")
32+
boolean hasInterview,
33+
34+
@ArraySchema(schema = @Schema(implementation = CreateFormFieldRequest.class))
35+
List<CreateFormFieldRequest> formFields
36+
) {
37+
38+
record CreateFormFieldRequest(
39+
@Schema(description = "폼지 질문", example = "우리 동아리 들어올겁니까?")
40+
@NotNull(message = "질문는 null이 될 수 없습니다.")
41+
String question,
42+
43+
@Schema(description = "질문 종류", example = "CHECK_BOX")
44+
@NotNull(message = "질문 종류는 null이 될 수 없습니다.")
45+
FieldType type,
46+
47+
@Schema(description = "질문의 선택리스트", example = "[지문1이다., 지문2이다., 지문3이다.]")
48+
List<String> options,
49+
50+
@Schema(description = "필수여부", example = "true")
51+
@NotNull(message = "필수여부는 null이 될 수 없습니다.")
52+
boolean required,
53+
54+
@Schema(description = "질문 순서", example = "1")
55+
@NotNull(message = "질문 순서는 null이 될 수 없습니다.")
56+
int order,
57+
58+
@Schema(description = "질문 섹션 종류", example = "공통")
59+
@NotNull(message = "질문 섹션종류는 null이 될 수 없습니다.")
60+
String section
61+
) {
62+
63+
public CreateFormFieldCommand toCommand() {
64+
return CreateFormFieldCommand.builder()
65+
.question(question)
66+
.type(type)
67+
.options(options)
68+
.required(required)
69+
.order(order)
70+
.section(section)
71+
.build();
72+
}
73+
}
74+
75+
public CreateFormCommand toCommand(User user) {
76+
List<CreateFormFieldCommand> createFormFieldCommands = formFields.stream()
77+
.map(CreateFormFieldRequest::toCommand)
78+
.toList();
79+
return CreateFormCommand.builder()
80+
.user(user)
81+
.title(title)
82+
.description(description)
83+
.startDate(startDate)
84+
.endDate(endDate)
85+
.hasInterview(hasInterview)
86+
.formFieldCommands(createFormFieldCommands)
87+
.build();
88+
}
89+
90+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand;
4+
5+
public interface FacadeCentralFormService {
6+
7+
void createForm(CreateFormCommand command);
8+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import ddingdong.ddingdongBE.domain.club.entity.Club;
4+
import ddingdong.ddingdongBE.domain.club.service.ClubService;
5+
import ddingdong.ddingdongBE.domain.form.entity.Form;
6+
import ddingdong.ddingdongBE.domain.form.entity.FormField;
7+
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand;
8+
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand.CreateFormFieldCommand;
9+
import java.util.List;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.stereotype.Service;
12+
import org.springframework.transaction.annotation.Transactional;
13+
14+
@Service
15+
@RequiredArgsConstructor
16+
@Transactional(readOnly = true)
17+
public class FacadeCentralFormServiceImpl implements FacadeCentralFormService{
18+
19+
private final FormService formService;
20+
private final FormFieldService formFieldService;
21+
private final ClubService clubService;
22+
23+
@Transactional
24+
@Override
25+
public void createForm(CreateFormCommand createFormCommand) {
26+
Club club = clubService.getByUserId(createFormCommand.user().getId());
27+
Form form = createFormCommand.toEntity(club);
28+
Form savedForm = formService.create(form);
29+
30+
List<FormField> formFields = toFormFields(savedForm, createFormCommand.formFieldCommands());
31+
formFieldService.createAll(formFields);
32+
}
33+
34+
private List<FormField> toFormFields(Form savedForm, List<CreateFormFieldCommand> createFormFieldCommands) {
35+
return createFormFieldCommands.stream()
36+
.map(formFieldCommand -> formFieldCommand.toEntity(savedForm))
37+
.toList();
38+
}
39+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import ddingdong.ddingdongBE.domain.form.entity.FormField;
4+
import java.util.List;
5+
6+
public interface FormFieldService {
7+
8+
void createAll(List<FormField> formFields);
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import ddingdong.ddingdongBE.domain.form.entity.Form;
4+
5+
public interface FormService {
6+
7+
Form create(Form form);
8+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import ddingdong.ddingdongBE.domain.form.entity.FormField;
4+
import ddingdong.ddingdongBE.domain.form.repository.FormFieldRepository;
5+
import java.util.List;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.stereotype.Service;
8+
import org.springframework.transaction.annotation.Transactional;
9+
10+
@Service
11+
@RequiredArgsConstructor
12+
@Transactional(readOnly = true)
13+
public class GeneralFormFieldService implements FormFieldService {
14+
15+
private final FormFieldRepository formFieldRepository;
16+
17+
@Transactional
18+
@Override
19+
public void createAll(List<FormField> formFields) {
20+
formFieldRepository.saveAll(formFields);
21+
}
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import ddingdong.ddingdongBE.domain.form.entity.Form;
4+
import ddingdong.ddingdongBE.domain.form.repository.FormRepository;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Service;
7+
import org.springframework.transaction.annotation.Transactional;
8+
9+
@Service
10+
@RequiredArgsConstructor
11+
@Transactional(readOnly = true)
12+
public class GeneralFormService implements FormService{
13+
14+
private final FormRepository formRepository;
15+
16+
@Transactional
17+
@Override
18+
public Form create(Form form) {
19+
return formRepository.save(form);
20+
}
21+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package ddingdong.ddingdongBE.domain.form.service.dto.command;
2+
3+
import ddingdong.ddingdongBE.domain.club.entity.Club;
4+
import ddingdong.ddingdongBE.domain.form.entity.FieldType;
5+
import ddingdong.ddingdongBE.domain.form.entity.Form;
6+
import ddingdong.ddingdongBE.domain.form.entity.FormField;
7+
import ddingdong.ddingdongBE.domain.user.entity.User;
8+
import java.time.LocalDate;
9+
import java.util.List;
10+
import lombok.Builder;
11+
12+
@Builder
13+
public record CreateFormCommand(
14+
User user,
15+
String title,
16+
String description,
17+
LocalDate startDate,
18+
LocalDate endDate,
19+
boolean hasInterview,
20+
List<CreateFormFieldCommand> formFieldCommands
21+
) {
22+
23+
@Builder
24+
public record CreateFormFieldCommand(
25+
String question,
26+
FieldType type,
27+
List<String> options,
28+
boolean required,
29+
int order,
30+
String section
31+
) {
32+
33+
public FormField toEntity(Form savedForm) {
34+
return FormField.builder()
35+
.question(question)
36+
.fieldType(type)
37+
.options(options)
38+
.required(required)
39+
.fieldOrder(order)
40+
.section(section)
41+
.form(savedForm)
42+
.build();
43+
}
44+
}
45+
46+
public Form toEntity(Club club) {
47+
return Form.builder()
48+
.title(title)
49+
.description(description)
50+
.startDate(startDate)
51+
.endDate(endDate)
52+
.hasInterview(hasInterview)
53+
.club(club)
54+
.build();
55+
}
56+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package ddingdong.ddingdongBE.domain.form.service;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import com.navercorp.fixturemonkey.FixtureMonkey;
6+
import ddingdong.ddingdongBE.common.support.FixtureMonkeyFactory;
7+
import ddingdong.ddingdongBE.common.support.TestContainerSupport;
8+
import ddingdong.ddingdongBE.domain.club.entity.Club;
9+
import ddingdong.ddingdongBE.domain.club.repository.ClubRepository;
10+
import ddingdong.ddingdongBE.domain.form.entity.Form;
11+
import ddingdong.ddingdongBE.domain.form.entity.FormField;
12+
import ddingdong.ddingdongBE.domain.form.repository.FormFieldRepository;
13+
import ddingdong.ddingdongBE.domain.form.repository.FormRepository;
14+
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand;
15+
import ddingdong.ddingdongBE.domain.user.entity.Role;
16+
import ddingdong.ddingdongBE.domain.user.entity.User;
17+
import ddingdong.ddingdongBE.domain.user.repository.UserRepository;
18+
import java.util.List;
19+
import org.junit.jupiter.api.DisplayName;
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.test.context.SpringBootTest;
23+
24+
@SpringBootTest
25+
class FacadeCentralFormServiceImplTest extends TestContainerSupport {
26+
27+
@Autowired
28+
private FormService formService;
29+
30+
@Autowired
31+
private FormRepository formRepository;
32+
33+
@Autowired
34+
private FacadeCentralFormService facadeCentralFormService;
35+
36+
@Autowired
37+
private ClubRepository clubRepository;
38+
39+
@Autowired
40+
private UserRepository userRepository;
41+
42+
@Autowired
43+
private FormFieldRepository formFieldRepository;
44+
45+
private static final FixtureMonkey fixtureMonkey = FixtureMonkeyFactory.getNotNullBuilderIntrospectorMonkey();
46+
47+
@DisplayName("폼지와 폼지 질문을 생성할 수 있다.")
48+
@Test
49+
void createForm() {
50+
// given
51+
User user = fixtureMonkey.giveMeBuilder(User.class)
52+
.set("id", 1L)
53+
.set("Role", Role.CLUB)
54+
.set("deletedAt", null)
55+
.sample();
56+
User savedUser = userRepository.save(user);
57+
Club club = fixtureMonkey.giveMeBuilder(Club.class)
58+
.set("id", 1L)
59+
.set("user", savedUser)
60+
.set("score", null)
61+
.set("clubMembers", null)
62+
.set("deletedAt", null)
63+
.sample();
64+
clubRepository.save(club);
65+
CreateFormCommand createFormCommand = fixtureMonkey.giveMeBuilder(CreateFormCommand.class)
66+
.set("user", savedUser)
67+
.sample();
68+
// when
69+
facadeCentralFormService.createForm(createFormCommand);
70+
// then
71+
List<Form> form = formRepository.findAll();
72+
List<FormField> formFields = formFieldRepository.findAll();
73+
74+
assertThat(form).isNotEmpty();
75+
assertThat(formFields).isNotEmpty();
76+
}
77+
}

0 commit comments

Comments
 (0)