Skip to content

Commit

Permalink
refactor: 모임원 답변 등록 시 리스트로 받도록 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
nahyeon99 committed Aug 6, 2024
1 parent d53e5c2 commit 4c73d74
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

import java.time.Clock;
import java.time.LocalDateTime;
import java.util.List;

import org.depromeet.sambad.moring.answer.application.AnswerService;
import org.depromeet.sambad.moring.answer.domain.Answer;
import org.depromeet.sambad.moring.event.application.EventService;
import org.depromeet.sambad.moring.meeting.answer.domain.MeetingAnswer;
import org.depromeet.sambad.moring.meeting.answer.presentation.exception.DuplicateMeetingAnswerException;
Expand Down Expand Up @@ -41,17 +41,18 @@ public class MeetingAnswerService {
public void save(Long userId, Long meetingId, Long meetingQuestionId, MeetingAnswerRequest request) {
MeetingMember loginMember = meetingMemberService.getByUserIdAndMeetingId(userId, meetingId);
MeetingQuestion meetingQuestion = meetingQuestionService.getById(meetingId, meetingQuestionId);
Long questionId = meetingQuestion.getQuestion().getId();

meetingQuestion.validateNotFinished(LocalDateTime.now(clock));
validateNonDuplicateMeetingAnswer(meetingQuestion.getId(), loginMember.getId());
meetingQuestion.validateMeetingAnswerCount(request.answerIds().size());

Answer selectedAnswer = answerService.getById(meetingQuestion.getQuestion().getId(), request.answerId());
MeetingAnswer meetingAnswer = MeetingAnswer
.builder()
.meetingMember(loginMember)
.meetingQuestion(meetingQuestion)
.answer(selectedAnswer)
.build();
meetingAnswerRepository.save(meetingAnswer);
List<Long> answerIds = request.answerIds();
List<MeetingAnswer> meetingAnswers = answerIds.stream()
.map(answerId -> answerService.getById(questionId, answerId))
.map(answer -> new MeetingAnswer(meetingQuestion, answer, loginMember))
.toList();
meetingAnswers.forEach(meetingAnswerRepository::save);

eventService.inactivateLastEventByType(userId, meetingId, QUESTION_REGISTERED);
advanceToNextQuestionIfAllAnswered(meetingId, meetingQuestion);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
package org.depromeet.sambad.moring.meeting.answer.infrastructure;

import static com.querydsl.core.types.dsl.Expressions.*;
import static com.querydsl.jpa.JPAExpressions.*;
import static org.depromeet.sambad.moring.meeting.answer.domain.QMeetingAnswer.*;
import static org.depromeet.sambad.moring.meeting.comment.domain.comment.QMeetingQuestionComment.*;
import static org.depromeet.sambad.moring.meeting.member.domain.QMeetingMember.*;
import static org.depromeet.sambad.moring.meeting.question.domain.QMeetingQuestion.*;

import java.util.List;
import java.util.Objects;

import org.depromeet.sambad.moring.answer.domain.Answer;
import org.depromeet.sambad.moring.meeting.answer.domain.MeetingAnswer;
import org.depromeet.sambad.moring.meeting.answer.infrastructure.dto.MyMeetingAnswerResponseCustom;
import org.depromeet.sambad.moring.meeting.answer.presentation.response.MyMeetingAnswerListResponse;
import org.depromeet.sambad.moring.meeting.comment.domain.comment.MeetingQuestionComment;
import org.depromeet.sambad.moring.meeting.member.domain.MeetingMember;
import org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestion;
import org.springframework.stereotype.Repository;

import com.querydsl.core.Tuple;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -86,23 +85,36 @@ public List<MeetingMember> findMeetingMembersSelectWith(Long meetingQuestionId,
}

public MyMeetingAnswerListResponse findAllByMeetingMemberId(Long meetingMemberId) {
List<MyMeetingAnswerResponseCustom> responseCustoms = queryFactory.select(Projections.constructor(
MyMeetingAnswerResponseCustom.class,
meetingAnswer.meetingQuestion.as("meetingQuestion"),
meetingAnswer.as("meetingAnswer"),
as(getMyComment(meetingMemberId), "comment")
))
.from(meetingAnswer)
.where(meetingAnswer.meetingMember.id.eq(meetingMemberId))
List<MeetingQuestion> meetingQuestions = queryFactory.select(meetingQuestion)
.from(meetingQuestion)
.join(meetingAnswer).on(meetingQuestion.eq(meetingAnswer.meetingQuestion)).fetchJoin()
.join(meetingMember).on(meetingMember.eq(meetingAnswer.meetingMember)).fetchJoin()
.where(meetingMember.id.eq(meetingMemberId))
.orderBy(meetingQuestion.createdAt.asc())
.fetch();

List<MyMeetingAnswerResponseCustom> responseCustoms = meetingQuestions.stream()
.map(question -> new MyMeetingAnswerResponseCustom(question.getTitle(),
getMyAnswers(meetingMemberId, question),
getMyComment(meetingMemberId, question)))
.toList();

return MyMeetingAnswerListResponse.from(responseCustoms);
}

private JPQLQuery<MeetingQuestionComment> getMyComment(Long memberId) {
return select(meetingQuestionComment)
private List<Answer> getMyAnswers(Long memberId, MeetingQuestion meetingQuestion) {
return queryFactory.select(meetingAnswer.answer)
.from(meetingAnswer)
.where(meetingAnswer.meetingQuestion.id.eq(meetingQuestion.getId()),
meetingAnswer.meetingMember.id.eq(memberId))
.fetch();
}

private String getMyComment(Long memberId, MeetingQuestion meetingQuestion) {
return queryFactory.select(meetingQuestionComment.content)
.from(meetingQuestionComment)
.where(meetingQuestionComment.meetingMember.id.eq(memberId),
meetingQuestionComment.meetingQuestion.eq(meetingAnswer.meetingQuestion));
meetingQuestionComment.meetingQuestion.eq(meetingQuestion))
.fetchFirst();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package org.depromeet.sambad.moring.meeting.answer.infrastructure.dto;

import org.depromeet.sambad.moring.meeting.answer.domain.MeetingAnswer;
import org.depromeet.sambad.moring.meeting.comment.domain.comment.MeetingQuestionComment;
import org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestion;
import java.util.List;

import org.depromeet.sambad.moring.answer.domain.Answer;

import com.querydsl.core.annotations.QueryProjection;

public record MyMeetingAnswerResponseCustom(
MeetingQuestion meetingQuestion,
MeetingAnswer meetingAnswer,
MeetingQuestionComment comment
String meetingQuestionTitle,
List<Answer> meetingAnswers,
String comment
) {

@QueryProjection
public MyMeetingAnswerResponseCustom {
}

public List<String> getMeetingAnswers() {
return meetingAnswers.stream()
.map(Answer::getContent)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public class MeetingAnswerController {

@Operation(summary = "모임원 답변 등록")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "meetingQuestion(모임원 답변) 등록 성공"),
@ApiResponse(responseCode = "201", description = "모임원 답변 등록 성공"),
@ApiResponse(responseCode = "400", description = "ANSWER_COUNT_OUT_OF_RANGE"),
@ApiResponse(responseCode = "404", description = "MEETING_MEMBER_NOT_FOUND / NOT_FOUND_MEETING_QUESTION / "
+ "NOT_FOUND_ANSWER"),
@ApiResponse(responseCode = "409", description = "DUPLICATE_MEETING_ANSWER / FINISHED_MEETING_QUESTION")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package org.depromeet.sambad.moring.meeting.answer.presentation.request;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.*;

import java.util.List;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public record MeetingAnswerRequest(
@Schema(example = "1", description = "선택한 답변 식별자")
@Schema(description = "선택한 Answer ID 리스트", example = "[1, 2, 3]", requiredMode = REQUIRED)
@Size(max = 9)
@NotNull
Long answerId
List<Long> answerIds
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.depromeet.sambad.moring.meeting.answer.presentation.response;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.*;

import java.util.List;

Expand All @@ -9,11 +9,7 @@
import io.swagger.v3.oas.annotations.media.Schema;

public record MyMeetingAnswerListResponse(
@Schema(
description = "내가 작성한 답변 목록",
example = "[{\"idx\":1,\"title\":\"갖고 싶은 초능력은?\",\"content\":\"분신술\",\"commentContent\":\"요새 할 일이 너무 많아요ㅠ 분신술로 시간 단축!!\"}]",
requiredMode = REQUIRED
)
@Schema(description = "내가 작성한 답변 목록", requiredMode = REQUIRED)
List<MyMeetingAnswerListResponseDetail> contents
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public record MyMeetingAnswerListResponseDetail(
@Schema(title = "릴레이 질문 제목", example = "갖고 싶은 초능력은?", requiredMode = REQUIRED)
String title,

@Schema(title = "유저가 선택한 답변", example = "분신술", requiredMode = REQUIRED)
String content,
@Schema(description = "유저가 선택한 답변 리스트", example = "[\"토마토\"]", requiredMode = REQUIRED)
List<String> content,

@Schema(title = "유저가 단 댓글", example = "요새 할 일이 너무 많아요ㅠ 분신술로 시간 단축!!",
description = "댓글이 없으면 null 응답합니다.", requiredMode = NOT_REQUIRED)
Expand All @@ -30,9 +30,9 @@ public static List<MyMeetingAnswerListResponseDetail> from(List<MyMeetingAnswerR
MyMeetingAnswerResponseCustom response = responseCustoms.get(i);
return new MyMeetingAnswerListResponseDetail(
i + 1,
response.meetingQuestion().getTitle(),
response.meetingAnswer().getAnswer().getContent(),
response.comment() != null ? response.comment().getContent() : null
response.meetingQuestionTitle(),
response.getMeetingAnswers(),
response.comment()
);
})
.toList();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.depromeet.sambad.moring.meeting.question.domain;

import static org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestionStatus.NOT_STARTED;
import static org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestionStatus.*;

import java.time.LocalDateTime;
import java.time.ZoneId;
Expand All @@ -15,6 +15,7 @@
import org.depromeet.sambad.moring.meeting.question.presentation.exception.FinishedMeetingQuestionException;
import org.depromeet.sambad.moring.meeting.question.presentation.exception.InvalidMeetingMemberTargetException;
import org.depromeet.sambad.moring.question.domain.Question;
import org.depromeet.sambad.moring.question.domain.QuestionType;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand Down Expand Up @@ -138,6 +139,10 @@ public void validateNotFinished(LocalDateTime now) {
}
}

public void validateMeetingAnswerCount(int answerSize) {
QuestionType.validateAnswerCount(question.getQuestionType(), answerSize);
}

public Long getEpochMilliStartTime() {
return startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
Expand All @@ -147,5 +152,4 @@ private void validateTarget(MeetingMember targetMember) {
throw new InvalidMeetingMemberTargetException();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.depromeet.sambad.moring.common.domain.BaseTimeEntity;
import org.depromeet.sambad.moring.file.domain.FileEntity;
import org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestion;
import org.depromeet.sambad.moring.question.presentation.exception.AnswerCountOutOfRangeException;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
Expand Down Expand Up @@ -58,7 +57,7 @@ public class Question extends BaseTimeEntity {
@Builder
public Question(String title, FileEntity questionImageFile, QuestionType questionType,
List<String> answerContents) {
validateAnswerCount(answerContents);
QuestionType.validateAnswerCount(questionType, answerContents.size());
this.questionType = questionType;
this.title = title;
this.questionImageFile = questionImageFile;
Expand Down Expand Up @@ -86,10 +85,4 @@ public String getQuestionImageUrl() {
public QuestionType getQuestionType() {
return questionType;
}

private void validateAnswerCount(List<String> answerContents) {
if (answerContents.size() < MIN_ANSWER_COUNT || answerContents.size() > MAX_ANSWER_COUNT) {
throw new AnswerCountOutOfRangeException();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
package org.depromeet.sambad.moring.question.domain;

import org.depromeet.sambad.moring.question.presentation.exception.AnswerCountOutOfRangeException;

public enum QuestionType {
SINGLE_CHOICE, MULTIPLE_SHORT_CHOICE, MULTIPLE_DESCRIPTIVE_CHOICE;

private static final int MIN_ANSWER_COUNT = 1;
private static final int MULTI_CHOICE_MAX_ANSWER_COUNT = 9;

public static void validateAnswerCount(QuestionType questionType, int answerCount) {
if (SINGLE_CHOICE.equals(questionType)) {
if (answerCount != MIN_ANSWER_COUNT) {
throw new AnswerCountOutOfRangeException();
}
return;
}
if (answerCount < MIN_ANSWER_COUNT || answerCount > MULTI_CHOICE_MAX_ANSWER_COUNT) {
throw new AnswerCountOutOfRangeException();
}
}
}

0 comments on commit 4c73d74

Please sign in to comment.