Skip to content

Commit

Permalink
[SAMBAD-257] 질문 및 답변 패키지 내 코드 정리 (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
nahyeon99 authored and kkjsw17 committed Aug 16, 2024
1 parent c66a6e5 commit 537f5eb
Show file tree
Hide file tree
Showing 14 changed files with 110 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

public interface AnswerRepository {

Optional<Answer> findByQuestionIdAndAnswerId(Long questionId, Long answerId);

void save(Answer answer);

Optional<Answer> findByQuestionIdAndAnswerId(Long questionId, Long answerId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@
public class AnswerService {

private final AnswerRepository answerRepository;
private final QuestionService questionService;

public Answer getById(Long questionId, Long answerId) {
return answerRepository.findByQuestionIdAndAnswerId(questionId, answerId)
.orElseThrow(NotFoundAnswerException::new);
}
private final QuestionService questionService;

@Transactional
public void saveAnswer(AnswerRequest answerRequest) {
Expand All @@ -32,4 +28,9 @@ public void saveAnswer(AnswerRequest answerRequest) {
.build();
answerRepository.save(answer);
}

public Answer getById(Long questionId, Long answerId) {
return answerRepository.findByQuestionIdAndAnswerId(questionId, answerId)
.orElseThrow(NotFoundAnswerException::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
@Transactional(readOnly = true)
public class MeetingAnswerResultService {

private final MeetingMemberService meetingMemberService;
private final MeetingQuestionRepository meetingQuestionRepository;
private final MeetingAnswerRepository meetingAnswerRepository;

private final MeetingMemberService meetingMemberService;

private final MeetingMemberValidator meetingMemberValidator;

public SelectedAnswerResponse getMostSelectedAnswer(Long userId, Long meetingId, Long meetingQuestionId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ public interface MeetingQuestionRepository {

boolean existsByQuestion(Long meetingId, Long questionId);

Optional<MeetingQuestion> findActiveOneByMeeting(Long meetingId);
// 현재 진행 중인 모임 질문을 조회한다.
Optional<MeetingQuestion> findCurrentOne(Long meetingId);

MostInactiveMeetingQuestionListResponse findMostInactiveList(Long meetingId);
// 질문이 등록된 현재 진행 중인 모임 질문을 조회한다.
Optional<MeetingQuestion> findCurrentActiveOne(Long meetingId);

MostInactiveMeetingQuestionListResponse findTopInactiveList(Long meetingId);

FullInactiveMeetingQuestionListResponse findFullInactiveList(Long meetingId, Pageable pageable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestion;
import org.depromeet.sambad.moring.meeting.question.presentation.exception.NotFoundMeetingQuestion;
import org.depromeet.sambad.moring.meeting.question.presentation.request.MeetingQuestionRequest;
import org.depromeet.sambad.moring.meeting.question.presentation.response.ActiveMeetingQuestionResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.CurrentMeetingQuestionResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.FullInactiveMeetingQuestionListResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.MeetingQuestionAndAnswerListResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.MeetingQuestionStatisticsDetail;
Expand All @@ -43,12 +43,13 @@ public class MeetingQuestionService {
private final MeetingMemberService meetingMemberService;
private final QuestionService questionService;
private final EventService eventService;

private final MeetingMemberValidator meetingMemberValidator;

private final Clock clock;

@Transactional
public ActiveMeetingQuestionResponse save(Long userId, Long meetingId, MeetingQuestionRequest request) {
public CurrentMeetingQuestionResponse save(Long userId, Long meetingId, MeetingQuestionRequest request) {
MeetingMember loginMember = meetingMemberService.getByUserIdAndMeetingId(userId, meetingId);
MeetingMember nextTargetMember = meetingMemberService.getById(request.meetingMemberId());
loginMember.validateNextTarget(nextTargetMember);
Expand All @@ -59,24 +60,24 @@ public ActiveMeetingQuestionResponse save(Long userId, Long meetingId, MeetingQu
validateNonDuplicateQuestion(meetingId, activeQuestion.getId());

Meeting meeting = loginMember.getMeeting();
MeetingQuestion nowMeetingQuestion;
MeetingQuestion currentMeetingQuestion;

if (registeredMeetingQuestion.isPresent()) {
nowMeetingQuestion = registeredMeetingQuestion.get();
nowMeetingQuestion.registerQuestion(loginMember, activeQuestion);
currentMeetingQuestion = registeredMeetingQuestion.get();
currentMeetingQuestion.registerQuestion(loginMember, activeQuestion);
} else {
nowMeetingQuestion = createActiveQuestion(meeting, loginMember, activeQuestion);
currentMeetingQuestion = createActiveQuestion(meeting, loginMember, activeQuestion);
}

eventService.inactivateLastEventByType(userId, meetingId, TARGET_MEMBER);
meeting.getMeetingMembers().forEach(member ->
eventService.publish(member.getUser().getId(), meetingId, QUESTION_REGISTERED));

MeetingQuestion nextMeetingQuestion = MeetingQuestion.createNextMeetingQuestion(
meeting, nextTargetMember, nowMeetingQuestion.getNextStartTime());
meeting, nextTargetMember, currentMeetingQuestion.getNextStartTime());
meetingQuestionRepository.save(nextMeetingQuestion);

return ActiveMeetingQuestionResponse.questionRegisteredOf(nowMeetingQuestion, false);
return CurrentMeetingQuestionResponse.questionRegisteredOf(currentMeetingQuestion, false);
}

@Transactional
Expand All @@ -87,39 +88,34 @@ public MeetingQuestion createActiveQuestion(Meeting meeting, MeetingMember targe
}

public MeetingQuestionAndAnswerListResponse getActiveMeetingQuestionAndAnswerList(Long userId, Long meetingId) {
MeetingMember loginMember = meetingMemberService.getByUserIdAndMeetingId(userId, meetingId);
Optional<MeetingQuestion> activeMeetingQuestion = findActiveMeetingQuestion(loginMember.getMeeting().getId());
if (activeMeetingQuestion.isEmpty()) {
throw new NotFoundMeetingQuestion();
}
if (activeMeetingQuestion.get().getQuestion() == null) {
throw new NotFoundMeetingQuestion();
}
return MeetingQuestionAndAnswerListResponse.of(activeMeetingQuestion.get());
meetingMemberValidator.validateUserIsMemberOfMeeting(userId, meetingId);

MeetingQuestion activeMeetingQuestion = meetingQuestionRepository.findCurrentActiveOne(meetingId)
.orElseThrow(NotFoundMeetingQuestion::new);
return MeetingQuestionAndAnswerListResponse.of(activeMeetingQuestion);
}

public Optional<ActiveMeetingQuestionResponse> findActiveOne(Long userId, Long meetingId) {
public Optional<CurrentMeetingQuestionResponse> findCurrentOne(Long userId, Long meetingId) {
MeetingMember meetingMember = meetingMemberService.getByUserIdAndMeetingId(userId, meetingId);
Meeting meeting = meetingMember.getMeeting();
Optional<MeetingQuestion> activeMeetingQuestionOpt = meetingQuestionRepository.findActiveOneByMeeting(
Optional<MeetingQuestion> activeMeetingQuestionOpt = meetingQuestionRepository.findCurrentOne(
meeting.getId());

if (activeMeetingQuestionOpt.isPresent()) {
MeetingQuestion activeMeetingQuestion = activeMeetingQuestionOpt.get();
boolean isAnswered = meetingQuestionRepository.isAnswered(
activeMeetingQuestion.getId(), meetingMember.getId());

return activeMeetingQuestion.getQuestion() == null
? Optional.of(ActiveMeetingQuestionResponse.questionNotRegisteredOf(activeMeetingQuestion))
: Optional.of(ActiveMeetingQuestionResponse.questionRegisteredOf(activeMeetingQuestion, isAnswered));
? Optional.of(CurrentMeetingQuestionResponse.questionNotRegisteredOf(activeMeetingQuestion))
: Optional.of(CurrentMeetingQuestionResponse.questionRegisteredOf(activeMeetingQuestion,
meetingQuestionRepository.isAnswered(activeMeetingQuestion.getId(), meetingMember.getId())));
}

return Optional.empty();
}

public MostInactiveMeetingQuestionListResponse findMostInactiveList(Long userId, Long meetingId) {
public MostInactiveMeetingQuestionListResponse findTopInactiveList(Long userId, Long meetingId) {
meetingMemberValidator.validateUserIsMemberOfMeeting(userId, meetingId);
return meetingQuestionRepository.findMostInactiveList(meetingId);
return meetingQuestionRepository.findTopInactiveList(meetingId);
}

public FullInactiveMeetingQuestionListResponse findFullInactiveList(Long userId, Long meetingId,
Expand Down Expand Up @@ -162,10 +158,6 @@ public MeetingMemberListResponse getMeetingMembersByMeetingQuestionId(
return MeetingMemberListResponse.from(members);
}

private Optional<MeetingQuestion> findActiveMeetingQuestion(Long meetingId) {
return meetingQuestionRepository.findActiveOneByMeeting(meetingId);
}

private void validateNonDuplicateQuestion(Long meetingId, Long questionId) {
boolean isDuplicateQuestion = meetingQuestionRepository.existsByQuestion(meetingId, questionId);
if (isDuplicateQuestion) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.List;

import org.depromeet.sambad.moring.common.domain.BaseTimeEntity;
import org.depromeet.sambad.moring.common.logging.LoggingUtils;
import org.depromeet.sambad.moring.meeting.answer.domain.MeetingAnswer;
import org.depromeet.sambad.moring.meeting.meeting.domain.Meeting;
import org.depromeet.sambad.moring.meeting.member.domain.MeetingMember;
Expand Down Expand Up @@ -114,7 +115,6 @@ public void registerQuestion(MeetingMember targetMember, Question question) {
throw new DuplicateMeetingQuestionException();
}
this.question = question;
this.status = ACTIVE;
this.question.addMeetingQuestion(this);
}

Expand All @@ -124,9 +124,9 @@ public void updateStatusToInactive() {

public void updateStatusToActive(LocalDateTime startTime) {
if (this.status != NOT_STARTED) {
throw new IllegalStateException("이미 시작되거나 종료된 질문입니다.");
LoggingUtils.error("다음 MeetingQuestion 의 활성화를 시도하였으나, 이미 시작되거나 종료된 질문입니다. meetingQuestionId : "
+ id + " status : " + status.name());
}

this.startTime = startTime;
this.expiredAt = startTime.plusSeconds(RESPONSE_TIME_LIMIT_SECONDS);
this.status = ACTIVE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public interface MeetingQuestionJpaRepository extends JpaRepository<MeetingQuest

List<MeetingQuestion> findAllByStatusAndExpiredAtBefore(MeetingQuestionStatus status, LocalDateTime now);

Optional<MeetingQuestion> findFirstByMeetingIdAndStatusOrderByStartTime(
Long meetingId, MeetingQuestionStatus status);
Optional<MeetingQuestion> findFirstByMeetingIdAndStatusOrderByStartTime(Long meetingId,
MeetingQuestionStatus status);

Optional<MeetingQuestion> findFirstByMeetingIdAndStatusAndQuestionIsNotNullOrderByStartTime(Long meetingId,
MeetingQuestionStatus status);
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,6 @@ public FullInactiveMeetingQuestionListResponse findFullInactiveList(Long meeting
return FullInactiveMeetingQuestionListResponse.of(inactiveMeetingQuestions, pageable);
}

private OrderSpecifier<Integer> orderDescByMeetingAnswerCount() {
return new OrderSpecifier<>(Order.DESC, meetingQuestion.memberAnswers.size());
}

private Optional<Answer> getBestAnswer(MeetingQuestion meetingQuestion) {
return Optional.ofNullable(queryFactory
.select(meetingAnswer.answer)
.from(meetingAnswer)
.where(meetingAnswer.meetingQuestion.eq(meetingQuestion))
.groupBy(meetingAnswer.answer)
.orderBy(meetingAnswer.count().desc())
.limit(1)
.fetchOne());
}

public Boolean isAnswered(Long meetingQuestionId, Long meetingMemberId) {
Integer fetchOne = queryFactory
.selectOne()
Expand All @@ -121,11 +106,6 @@ public Boolean isAnswered(Long meetingQuestionId, Long meetingMemberId) {
return fetchOne != null;
}

private BooleanExpression inactiveCond() {
return meetingQuestion.expiredAt.lt(LocalDateTime.now())
.or(meetingQuestion.status.eq(INACTIVE));
}

public List<MeetingQuestionStatisticsDetail> findStatistics(Long meetingQuestionId) {
// Get total count for the percentage calculation
Optional<Long> optionalTotalCount = Optional.ofNullable(queryFactory
Expand Down Expand Up @@ -173,4 +153,24 @@ public List<MeetingMember> findMeetingMembersByMeetingQuestionId(Long meetingQue
.where(meetingQuestion.id.eq(meetingQuestionId))
.fetch();
}

private OrderSpecifier<Integer> orderDescByMeetingAnswerCount() {
return new OrderSpecifier<>(Order.DESC, meetingQuestion.memberAnswers.size());
}

private Optional<Answer> getBestAnswer(MeetingQuestion meetingQuestion) {
return Optional.ofNullable(queryFactory
.select(meetingAnswer.answer)
.from(meetingAnswer)
.where(meetingAnswer.meetingQuestion.eq(meetingQuestion))
.groupBy(meetingAnswer.answer)
.orderBy(meetingAnswer.count().desc())
.limit(1)
.fetchOne());
}

private BooleanExpression inactiveCond() {
return meetingQuestion.expiredAt.lt(LocalDateTime.now())
.or(meetingQuestion.status.eq(INACTIVE));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,18 @@ public boolean existsByQuestion(Long meetingId, Long questionId) {
}

@Override
public Optional<MeetingQuestion> findActiveOneByMeeting(Long meetingId) {
public Optional<MeetingQuestion> findCurrentOne(Long meetingId) {
return meetingQuestionJpaRepository.findFirstByMeetingIdAndStatusOrderByStartTime(meetingId, ACTIVE);
}

@Override
public MostInactiveMeetingQuestionListResponse findMostInactiveList(Long meetingId) {
public Optional<MeetingQuestion> findCurrentActiveOne(Long meetingId) {
return meetingQuestionJpaRepository.findFirstByMeetingIdAndStatusAndQuestionIsNotNullOrderByStartTime(meetingId,
ACTIVE);
}

@Override
public MostInactiveMeetingQuestionListResponse findTopInactiveList(Long meetingId) {
return meetingQuestionQueryRepository.findMostInactiveList(meetingId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.depromeet.sambad.moring.meeting.member.presentation.response.MeetingMemberListResponse;
import org.depromeet.sambad.moring.meeting.question.application.MeetingQuestionService;
import org.depromeet.sambad.moring.meeting.question.presentation.request.MeetingQuestionRequest;
import org.depromeet.sambad.moring.meeting.question.presentation.response.ActiveMeetingQuestionResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.CurrentMeetingQuestionResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.FullInactiveMeetingQuestionListResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.MeetingQuestionAndAnswerListResponse;
import org.depromeet.sambad.moring.meeting.question.presentation.response.MeetingQuestionStatisticsResponse;
Expand Down Expand Up @@ -49,12 +49,12 @@ public class MeetingQuestionController {
+ "INVALID_MEETING_MEMBER_TARGET")
})
@PostMapping
public ResponseEntity<ActiveMeetingQuestionResponse> save(
public ResponseEntity<CurrentMeetingQuestionResponse> save(
@UserId Long userId,
@Parameter(description = "모임 ID", example = "1", required = true) @PathVariable("meetingId") Long meetingId,
@Valid @RequestBody MeetingQuestionRequest request
) {
ActiveMeetingQuestionResponse response = meetingQuestionService.save(userId, meetingId, request);
CurrentMeetingQuestionResponse response = meetingQuestionService.save(userId, meetingId, request);
return ResponseEntity.status(CREATED).body(response);
}

Expand Down Expand Up @@ -104,11 +104,11 @@ public ResponseEntity<MeetingQuestionStatisticsResponse> getStatisticsByQuestion
)
})
@GetMapping("/active")
public ResponseEntity<ActiveMeetingQuestionResponse> findActiveOne(
public ResponseEntity<CurrentMeetingQuestionResponse> findActiveOne(
@UserId Long userId,
@Parameter(description = "모임 ID", example = "1", required = true) @PathVariable("meetingId") Long meetingId
) {
return meetingQuestionService.findActiveOne(userId, meetingId)
return meetingQuestionService.findCurrentOne(userId, meetingId)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.noContent().build());
}
Expand Down Expand Up @@ -159,7 +159,7 @@ public ResponseEntity<MostInactiveMeetingQuestionListResponse> findMostInactiveL
@UserId Long userId,
@Parameter(description = "모임 ID", example = "1", required = true) @PathVariable("meetingId") Long meetingId
) {
MostInactiveMeetingQuestionListResponse inactiveList = meetingQuestionService.findMostInactiveList(userId,
MostInactiveMeetingQuestionListResponse inactiveList = meetingQuestionService.findTopInactiveList(userId,
meetingId);
return ResponseEntity.ok(inactiveList);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.depromeet.sambad.moring.meeting.question.presentation.response;

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

import org.depromeet.sambad.moring.file.presentation.annotation.FullFileUrl;
import org.depromeet.sambad.moring.meeting.meeting.domain.Meeting;
Expand All @@ -11,7 +11,7 @@
import lombok.Builder;

@Builder
public record ActiveMeetingQuestionResponse(
public record CurrentMeetingQuestionResponse(
@Schema(example = "1", description = "모임 질문 식별자", requiredMode = REQUIRED)
Long meetingQuestionId,

Expand Down Expand Up @@ -48,10 +48,10 @@ public record ActiveMeetingQuestionResponse(
MeetingMemberListResponseDetail targetMember
) {

public static ActiveMeetingQuestionResponse questionNotRegisteredOf(MeetingQuestion meetingQuestion) {
public static CurrentMeetingQuestionResponse questionNotRegisteredOf(MeetingQuestion meetingQuestion) {
Meeting meeting = meetingQuestion.getMeeting();

return ActiveMeetingQuestionResponse.builder()
return CurrentMeetingQuestionResponse.builder()
.meetingQuestionId(meetingQuestion.getId())
.questionNumber(meeting.getQuestionNumber(meetingQuestion))
.totalMeetingMemberCount(meeting.getTotalMemberCount())
Expand All @@ -64,11 +64,11 @@ public static ActiveMeetingQuestionResponse questionNotRegisteredOf(MeetingQuest
.build();
}

public static ActiveMeetingQuestionResponse questionRegisteredOf(MeetingQuestion meetingQuestion,
public static CurrentMeetingQuestionResponse questionRegisteredOf(MeetingQuestion meetingQuestion,
Boolean isAnswered) {
Meeting meeting = meetingQuestion.getMeeting();

return ActiveMeetingQuestionResponse.builder()
return CurrentMeetingQuestionResponse.builder()
.meetingQuestionId(meetingQuestion.getId())
.questionImageFileUrl(meetingQuestion.getQuestion().getQuestionImageUrl())
.title(meetingQuestion.getQuestion().getTitle())
Expand Down
Loading

0 comments on commit 537f5eb

Please sign in to comment.