Skip to content

Commit

Permalink
Merge pull request #24 from dnd-side-project/feature/#18-conduct-review
Browse files Browse the repository at this point in the history
[Feature] 리뷰 진행하기
  • Loading branch information
heejjinkim authored Oct 28, 2024
2 parents 13cc398 + f068e17 commit 3c06dc0
Show file tree
Hide file tree
Showing 36 changed files with 969 additions and 148 deletions.
79 changes: 60 additions & 19 deletions src/main/java/com/_119/wepro/global/config/DataInitializer.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com._119.wepro.global.config;

import com._119.wepro.global.enums.CategoryType;
import com._119.wepro.review.domain.ChoiceQuestion;
import com._119.wepro.review.domain.Option;
import com._119.wepro.review.domain.Question;
import com._119.wepro.review.domain.repository.QuestionCustomRepository;
import com._119.wepro.review.domain.repository.QuestionJdbcRepository;
import com._119.wepro.review.domain.SubQuestion;
import com._119.wepro.review.domain.repository.ChoiceQuestionCustomRepository;
import com._119.wepro.review.domain.repository.ChoiceQuestionJdbcRepository;
import com._119.wepro.review.domain.repository.SubQuestionCustomRepository;
import com._119.wepro.review.domain.repository.SubQuestionJdbcRepository;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
Expand All @@ -24,29 +27,33 @@
@RequiredArgsConstructor
public class DataInitializer implements ApplicationRunner {

private final QuestionJdbcRepository questionJdbcRepository;
private final QuestionCustomRepository questionCustomRepository;
private final ChoiceQuestionJdbcRepository choiceQuestionJdbcRepository;
private final ChoiceQuestionCustomRepository choiceQuestionCustomRepository;
private final SubQuestionJdbcRepository subQuestionJdbcRepository;
private final SubQuestionCustomRepository subQuestionCustomRepository;

private final ObjectMapper objectMapper;
private final AtomicLong optionIdCounter = new AtomicLong(1);

@Override
public void run(ApplicationArguments args) throws Exception {
setDefaultQuestionsAndOptions();
setDefaultChoiceQuestionsAndOptions();
setDefaultSubQuestions();
}

private void setDefaultQuestionsAndOptions() {
private void setDefaultChoiceQuestionsAndOptions() {
// DB에 데이터가 없는 경우만 새로 생성
if (!questionCustomRepository.exists()) {
if (!choiceQuestionCustomRepository.exists()) {

List<Question> allQuestions = new ArrayList<>();
List<ChoiceQuestion> allChoiceQuestions = new ArrayList<>();
List<CategoryQuestions> categoryQuestionsList;

// JSON 파일 읽기
try {
ClassPathResource resource = new ClassPathResource("default-questions.json");
ClassPathResource resource = new ClassPathResource("default-choice-questions.json");
categoryQuestionsList = objectMapper.readValue(
resource.getInputStream(), new TypeReference<List<CategoryQuestions>>() {});
resource.getInputStream(), new TypeReference<List<CategoryQuestions>>() {
});
} catch (IOException e) {
e.printStackTrace();
return;
Expand All @@ -57,32 +64,66 @@ private void setDefaultQuestionsAndOptions() {
CategoryType categoryType = categoryQuestions.categoryType();
categoryQuestions.questions().forEach(questionWithOptions -> {

Question question = Question.builder()
ChoiceQuestion choiceQuestion = ChoiceQuestion.builder()
.content(questionWithOptions.question())
.categoryType(categoryType)
.options(createOptionsForQuestion(questionWithOptions.options()))
.build();

allQuestions.add(question);
allChoiceQuestions.add(choiceQuestion);
});
});

questionJdbcRepository.batchInsert(allQuestions);
choiceQuestionJdbcRepository.batchInsert(allChoiceQuestions);
}
}

private void setDefaultSubQuestions() {
// 주관식 문항 추가
if (!subQuestionCustomRepository.exists()) {
List<SubQuestion> subQuestions = new ArrayList<>();

try {
ClassPathResource resource = new ClassPathResource("default-sub-questions.json");
List<String> subQuestionContents = objectMapper.readValue(
resource.getInputStream(), new TypeReference<List<String>>() {
});

subQuestionContents.forEach(content -> {
SubQuestion subQuestion = SubQuestion.builder()
.content(content)
.build();
subQuestions.add(subQuestion);
});

} catch (IOException e) {
e.printStackTrace();
return;
}

subQuestionJdbcRepository.batchInsert(subQuestions);
}
}

private List<Option> createOptionsForQuestion(List<String> optionTexts) {
List<Option> options = new ArrayList<>();
for (int i = 0; i < optionTexts.size(); i++) {
Integer score = optionTexts.size();

for (String optionText : optionTexts) {
options.add(Option.builder()
.id(optionIdCounter.getAndIncrement())
.content(optionTexts.get(i))
.score(score--)
.content(optionText)
.build());
}
return options;
return options;
}

private record CategoryQuestions(CategoryType categoryType, List<QuestionWithOptions> questions) {}
private record CategoryQuestions(CategoryType categoryType, List<QuestionWithOptions> questions) {

private record QuestionWithOptions(String question, List<String> options) {}
}

private record QuestionWithOptions(String question, List<String> options) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ public enum ReviewErrorCode implements ErrorCode {
QUESTION_NOT_FOUND(HttpStatus.NOT_FOUND, "Question not found"),
CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "Category not found"),
QUESTIONS_NOT_FOUND_FOR_CATEGORY(HttpStatus.NOT_FOUND, "No questions found for the given category"),
REVIEW_FORM_NOT_FOUND(HttpStatus.NOT_FOUND, "Review Form not found")
REVIEW_FORM_NOT_FOUND(HttpStatus.NOT_FOUND, "Review Form not found"),
REVIEW_FORM_EXPIRED(HttpStatus.GONE, "Review Form expired"),
ALREADY_SUBMITTED(HttpStatus.CONFLICT, "Already Submitted"),
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package com._119.wepro.member.domain.repository;

import com._119.wepro.global.exception.RestApiException;
import com._119.wepro.global.exception.errorcode.UserErrorCode;
import com._119.wepro.member.domain.Member;
import com._119.wepro.member.domain.OauthInfo;
import io.lettuce.core.dynamic.annotation.Param;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {

Optional<Member> findByOauthInfo(OauthInfo oauthInfo);

@Query("SELECT m FROM Member m WHERE m.oauthInfo.providerId = :providerId")
Optional<Member> findByProviderId(@Param("providerId") String providerId);
default Member findByIdOrThrow(Long memberId) {
return findById(memberId).orElseThrow(() -> new RestApiException(UserErrorCode.USER_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com._119.wepro.project.domain.repository;

import com._119.wepro.global.exception.RestApiException;
import com._119.wepro.global.exception.errorcode.ProjectErrorCode;
import com._119.wepro.project.domain.Project;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProjectRepository extends JpaRepository<Project, Long> {

default Project findByIdOrThrow(Long projectId) {
return findById(projectId).orElseThrow(() -> new RestApiException(ProjectErrorCode.PROJECT_NOT_FOUND));
}
}
46 changes: 46 additions & 0 deletions src/main/java/com/_119/wepro/review/domain/ChoiceAnswer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com._119.wepro.review.domain;

import com._119.wepro.review.dto.ChoiceAnswerDto;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
@Builder
public class ChoiceAnswer {

private Long optionId;

private Long questionId;


public static ChoiceAnswer of(ChoiceAnswerDto answerDto) {
return ChoiceAnswer.builder()
.questionId(answerDto.getQuestionId())
.optionId(answerDto.getOptionId())
.build();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ChoiceAnswer that = (ChoiceAnswer) o;
return Objects.equals(questionId, that.questionId) &&
Objects.equals(optionId, that.optionId);
}

@Override
public int hashCode() {
return Objects.hash(questionId, optionId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
@Entity
@Getter
@Builder
public class Question extends BaseEntity {
public class ChoiceQuestion extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/com/_119/wepro/review/domain/Option.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,22 @@ public class Option {

private String content;

private Integer score;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

Option option = (Option) o;

if (id != null ? !id.equals(option.id) : option.id != null) return false;
if (id != null ? !id.equals(option.id) : option.id != null) {
return false;
}
return content != null ? content.equals(option.content) : option.content == null;
}

Expand Down
101 changes: 101 additions & 0 deletions src/main/java/com/_119/wepro/review/domain/ReviewRecord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com._119.wepro.review.domain;

import com._119.wepro.global.BaseEntity;
import com._119.wepro.member.domain.Member;
import com._119.wepro.review.domain.converter.ChoiceAnswerConverter;
import com._119.wepro.review.domain.converter.SubAnswerConverter;
import com._119.wepro.review.dto.request.ReviewRequest.ReviewSaveRequest;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Entity
@Getter
@Builder
public class ReviewRecord extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Builder.Default
@Column(nullable = false)
private Boolean isDraft = true;

@Builder.Default
@Column(nullable = false)
private Boolean isPublic = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "receiver_id")
private Member receiver;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "writer_id")
private Member writer;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "review_form_id")
private ReviewForm reviewForm;

@Column(columnDefinition = "json")
@JdbcTypeCode(SqlTypes.JSON)
@Convert(converter = ChoiceAnswerConverter.class)
private List<ChoiceAnswer> choiceAnswers;

@Column(columnDefinition = "json")
@JdbcTypeCode(SqlTypes.JSON)
@Convert(converter = SubAnswerConverter.class)
private List<SubAnswer> subAnswers;

public static ReviewRecord of(Member writer, ReviewForm reviewForm, ReviewSaveRequest request) {
List<ChoiceAnswer> choiceAnswers = request.getChoiceAnswerList().stream()
.map(ChoiceAnswer::of)
.toList();

List<SubAnswer> subAnswers = request.getSubAnswerList().stream()
.map(SubAnswer::of)
.toList();

return ReviewRecord.builder()
.writer(writer)
.receiver(reviewForm.getMember())
.reviewForm(reviewForm)
.choiceAnswers(choiceAnswers)
.subAnswers(subAnswers)
.build();
}

public void update(ReviewSaveRequest request) {
List<ChoiceAnswer> choiceAnswers = request.getChoiceAnswerList().stream()
.map(ChoiceAnswer::of)
.toList();

List<SubAnswer> subAnswers = request.getSubAnswerList().stream()
.map(SubAnswer::of)
.toList();

this.choiceAnswers = choiceAnswers;
this.subAnswers = subAnswers;
}

public void submit(){
this.isDraft = false;
}
}
Loading

0 comments on commit 3c06dc0

Please sign in to comment.