Skip to content

Commit

Permalink
feat-be: 지원폼 답변 제출 기능 (#213)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Do Yeop Kim <113661364+Dobby-Kim@users.noreply.github.com>
Co-authored-by: Kwoun Ki Ho <fingercut3822@gmail.com>
  • Loading branch information
3 people authored Aug 1, 2024
1 parent c55d4de commit f21fb03
Show file tree
Hide file tree
Showing 27 changed files with 746 additions and 56 deletions.
19 changes: 16 additions & 3 deletions backend/src/main/java/com/cruru/DataLoader.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.cruru;

import static com.cruru.question.domain.QuestionType.DROPDOWN;
import static com.cruru.question.domain.QuestionType.SHORT_ANSWER;

import com.cruru.answer.domain.Answer;
import com.cruru.answer.domain.repository.AnswerRepository;
import com.cruru.applicant.domain.Applicant;
import com.cruru.applicant.domain.repository.ApplicantRepository;
import com.cruru.applyform.domain.ApplyForm;
import com.cruru.applyform.domain.repository.ApplyFormRepository;
import com.cruru.choice.domain.Choice;
import com.cruru.choice.domain.repository.ChoiceRepository;
import com.cruru.club.domain.Club;
Expand All @@ -18,6 +23,7 @@
import com.cruru.process.domain.repository.ProcessRepository;
import com.cruru.question.domain.Question;
import com.cruru.question.domain.repository.QuestionRepository;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -42,6 +48,7 @@ public class DataLoader implements ApplicationRunner {
private final ChoiceRepository choiceRepository;
private final AnswerRepository answerRepository;
private final EvaluationRepository evaluationRepository;
private final ApplyFormRepository applyFormRepository;

@Value("${dataloader.enable}")
private boolean enableDataLoader;
Expand All @@ -58,8 +65,13 @@ private void runDataLoader() {
memberRepository.save(member);
Club club = new Club(1L, "크루루", member);
clubRepository.save(club);
Dashboard dashboard = new Dashboard(1L, "크루루 모집 공고", club);
Dashboard dashboard = new Dashboard(1L, club);
LocalDateTime startDate = LocalDateTime.MIN;
LocalDateTime dueDate = LocalDateTime.MAX;
dashboardRepository.save(dashboard);
ApplyForm applyForm = new ApplyForm(1L, "크루루 모집 공고", "# 모집 설명이다.", "www.cruru.kr/form/1", startDate, dueDate,
dashboard);
applyFormRepository.save(applyForm);

Process firstProcess = new Process(1L, 0, "서류 전형", "지원 서류를 확인한다.", dashboard);
Process lastProcess = new Process(2L, 1, "최종 합격", "최종 합격자", dashboard);
Expand All @@ -77,8 +89,9 @@ private void runDataLoader() {
List<Applicant> applicants = List.of(lurgi, dobby, arrr, chocochip, myungoh, rush, nyangin, redpanda);
applicantRepository.saveAll(applicants);

Question choiceQuestion = questionRepository.save(new Question(1L, "성별", 0, dashboard));
Question essayQuestion = questionRepository.save(new Question(2L, "좋아하는 숫자가 무엇인가요?", 1, dashboard));
Question choiceQuestion = questionRepository.save(new Question(1L, DROPDOWN, "성별", 0, applyForm));
Question essayQuestion = questionRepository.save(
new Question(SHORT_ANSWER, "좋아하는 숫자가 무엇인가요?", 1, applyForm));

Choice maleChoice = choiceRepository.save(new Choice(1L, "남", choiceQuestion));
Choice femaleChoice = choiceRepository.save(new Choice(2L, "여", choiceQuestion));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

public class InternalServerException extends RuntimeException {

public InternalServerException(String message) {
super(message);
private static final String TEXT = "서버 내부에 오류가 발생했습니다.";

public InternalServerException() {
super(TEXT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.cruru.applicant.controller.dto;

import jakarta.validation.constraints.NotBlank;

public record ApplicantCreateRequest(
@NotBlank(message = "이름은 필수 값입니다.")
String name,

@NotBlank(message = "이메일은 필수 값입니다.")
String email,

@NotBlank(message = "전화번호는 필수 값입니다.")
String phone
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.cruru.applyform.controller;

import com.cruru.applyform.controller.dto.ApplyFormSubmitRequest;
import com.cruru.applyform.service.ApplyFormService;
import jakarta.validation.Valid;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
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;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1/applyform")
@RequiredArgsConstructor
public class ApplyFormController {

private final ApplyFormService applyFormService;

@PostMapping("/{applyform_id}/submit")
public ResponseEntity<Void> submit(
@RequestBody @Valid ApplyFormSubmitRequest request,
@PathVariable(name = "applyform_id") long applyFormId
) {
applyFormService.submit(request, applyFormId);
return ResponseEntity.created(URI.create("/v1/applyform/" + applyFormId)).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.cruru.applyform.controller.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import java.util.List;

public record AnswerCreateRequest(
@NotNull(message = "질문 식별자는 필수 값입니다.")
@PositiveOrZero(message = "질문 식별자는 0 이상의 정수입니다.")
@JsonProperty("question_id")
Long questionId,

@NotNull(message = "응답은 필수 값입니다.")
List<String> replies
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.cruru.applyform.controller.dto;

import com.cruru.applicant.controller.dto.ApplicantCreateRequest;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import java.util.List;

public record ApplyFormSubmitRequest(
@JsonProperty("applicant")
ApplicantCreateRequest applicantCreateRequest,

@JsonProperty("answers")
List<AnswerCreateRequest> answerCreateRequest,

@NotNull(message = "개인정보 활용 동의는 필수 값입니다.")
@JsonProperty("personal_data_collection")
Boolean personalDataCollection
) {

}
89 changes: 89 additions & 0 deletions backend/src/main/java/com/cruru/applyform/domain/ApplyForm.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.cruru.applyform.domain;

import com.cruru.BaseEntity;
import com.cruru.dashboard.domain.Dashboard;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import java.time.LocalDateTime;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class ApplyForm extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "apply_form_id")
private Long id;

private String title;

private String description;

private String url;

@Column(name = "start_date")
private LocalDateTime startDate;

@Column(name = "due_date")
private LocalDateTime dueDate;

@OneToOne
@JoinColumn(name = "dashboard_id")
private Dashboard dashboard;

public ApplyForm(
String title,
String description,
String url,
LocalDateTime startDate,
LocalDateTime dueDate,
Dashboard dashboard
) {
this.title = title;
this.description = description;
this.url = url;
this.startDate = startDate;
this.dueDate = dueDate;
this.dashboard = dashboard;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ApplyForm applyForm)) {
return false;
}
return Objects.equals(id, applyForm.id);
}

@Override
public int hashCode() {
return Objects.hashCode(id);
}

@Override
public String toString() {
return "ApplyForm{" +
"id=" + id +
", title='" + title + '\'' +
", url='" + url + '\'' +
", dashboard=" + dashboard +
", startDate=" + startDate +
", dueDate=" + dueDate +
", description='" + description + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.cruru.applyform.domain.repository;

import com.cruru.applyform.domain.ApplyForm;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ApplyFormRepository extends JpaRepository<ApplyForm, Long> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.cruru.applyform.exception;

import com.cruru.advice.NotFoundException;

public class ApplyFormNotFoundException extends NotFoundException {

private static final String TEXT = "지원서 폼";

public ApplyFormNotFoundException() {
super(TEXT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.cruru.applyform.exception;

import com.cruru.advice.badrequest.BadRequestException;

public class PersonalDataProcessingException extends BadRequestException {

private static final String TEXT = "개인 정보 수집에 동의하지 않았습니다.";

public PersonalDataProcessingException() {
super(TEXT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.cruru.applyform.service;


import com.cruru.advice.InternalServerException;
import com.cruru.answer.domain.Answer;
import com.cruru.answer.domain.repository.AnswerRepository;
import com.cruru.applicant.domain.Applicant;
import com.cruru.applicant.domain.repository.ApplicantRepository;
import com.cruru.applyform.controller.dto.AnswerCreateRequest;
import com.cruru.applyform.controller.dto.ApplyFormSubmitRequest;
import com.cruru.applyform.domain.ApplyForm;
import com.cruru.applyform.domain.repository.ApplyFormRepository;
import com.cruru.applyform.exception.ApplyFormNotFoundException;
import com.cruru.applyform.exception.PersonalDataProcessingException;
import com.cruru.process.domain.Process;
import com.cruru.process.domain.repository.ProcessRepository;
import com.cruru.question.domain.Question;
import com.cruru.question.domain.repository.QuestionRepository;
import com.cruru.question.exception.QuestionNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ApplyFormService {

private final ApplicantRepository applicantRepository;
private final AnswerRepository answerRepository;
private final QuestionRepository questionRepository;
private final ApplyFormRepository applyFormRepository;
private final ProcessRepository processRepository;

@Transactional
public void submit(ApplyFormSubmitRequest request, long applyFormId) {
validatePersonalDataCollection(request);

ApplyForm applyForm = applyFormRepository.findById(applyFormId)
.orElseThrow(ApplyFormNotFoundException::new);

Process firstProcess = processRepository.findFirstByDashboardIdOrderBySequenceAsc(
applyForm.getDashboard().getId()
)
.orElseThrow(InternalServerException::new);

Applicant applicant = applicantRepository.save(
new Applicant(
request.applicantCreateRequest().name(),
request.applicantCreateRequest().email(),
request.applicantCreateRequest().phone(),
firstProcess,
false
)
);

for (AnswerCreateRequest answerCreateRequest : request.answerCreateRequest()) {
saveAnswerReplies(answerCreateRequest, applicant);
}
}

private void validatePersonalDataCollection(ApplyFormSubmitRequest request) {
if (!request.personalDataCollection()) {
throw new PersonalDataProcessingException();
}
}

private void saveAnswerReplies(AnswerCreateRequest answerCreateRequest, Applicant applicant) {
for (String reply : answerCreateRequest.replies()) {
Question question = getQuestionById(answerCreateRequest.questionId());
Answer answer = new Answer(reply, question, applicant);
answerRepository.save(answer);
}
}

private Question getQuestionById(long questionId) {
return questionRepository.findById(questionId)
.orElseThrow(QuestionNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,11 @@ public class Dashboard {
@Column(name = "dashboard_id")
private Long id;

private String name;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "club_id")
private Club club;

public Dashboard(String name, Club club) {
this.name = name;
public Dashboard(Club club) {
this.club = club;
}

Expand All @@ -57,7 +54,6 @@ public int hashCode() {
public String toString() {
return "Dashboard{" +
"id=" + id +
", name='" + name + '\'' +
", club=" + club +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class DashboardService {
public long create(long clubId, DashboardCreateRequest request) {
Club club = clubRepository.findById(clubId)
.orElseThrow(ClubNotFoundException::new);
Dashboard savedDashboard = dashboardRepository.save(new Dashboard(request.name(), club));
Dashboard savedDashboard = dashboardRepository.save(new Dashboard(club));

Process firstProcess = new Process(
DEFAULT_FIRST_PROCESS.getSequence(),
Expand Down
Loading

0 comments on commit f21fb03

Please sign in to comment.