Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SAMBAD-255] 종료된 모임 질문의 경우 참여율 계산 로직 수정 (#109) #112

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,11 @@ public MeetingMember getOwner() {
});
}

public int getTotalMemberCount() {
public Integer getTotalMemberCount() {
return meetingMembers.size();
}

public int getQuestionNumber(MeetingQuestion meetingQuestion) {
return meetingQuestions.indexOf(meetingQuestion) + 1;
}

public double calculateEngagementRate(MeetingQuestion meetingQuestion) {
if (getTotalMemberCount() == 0)
return 0;
double engagementRate = ((double)meetingQuestion.getResponseCount() / getTotalMemberCount()) * 100;
return Math.round(engagementRate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ public class MeetingMemberService {
private final MeetingMemberHobbyRepository meetingMemberHobbyRepository;
private final EventService eventService;

@Transactional
public MeetingMemberPersistResponse registerMeetingMember(
Long userId, String code, MeetingMemberPersistRequest request
) {
Meeting meeting = meetingRepository.findByCode(MeetingCode.from(code))
.orElseThrow(MeetingNotFoundException::new);

User user = userRepository.findById(userId)
.orElseThrow(NotFoundUserException::new);

MeetingMember meetingMember = validateAndCreateMember(userId, request, meeting, user);
addHobbies(meetingMember, request);

createMeetingQuestionIfFirstMeetingMember(meeting, meetingMember);

return MeetingMemberPersistResponse.from(meetingMember);
}

public MeetingMemberListResponse getMeetingMembers(Long userId, Long meetingId) {
meetingMemberValidator.validateUserIsMemberOfMeeting(userId, meetingId);

Expand All @@ -56,10 +74,6 @@ public MeetingMember getByUserIdAndMeetingId(Long userId, Long meetingId) {
.orElseThrow(MeetingMemberNotFoundException::new);
}

public boolean isNotEnterAnyMeeting(Long userId) {
return meetingMemberRepository.findByUserId(userId).isEmpty();
}

public MeetingMember getById(Long meetingMemberId) {
return meetingMemberRepository.findById(meetingMemberId)
.orElseThrow(MeetingMemberNotFoundException::new);
Expand All @@ -77,51 +91,37 @@ public MeetingMemberResponse getMyMeetingMember(Long userId, Long meetingId) {
return MeetingMemberResponse.from(getByUserIdAndMeetingId(userId, meetingId));
}

@Transactional
public MeetingMemberPersistResponse registerMeetingMember(
Long userId, String code, MeetingMemberPersistRequest request
) {
Meeting meeting = meetingRepository.findByCode(MeetingCode.from(code))
.orElseThrow(MeetingNotFoundException::new);
public MeetingMemberListResponseDetail getRandomMeetingMember(Long userId, Long meetingId,
List<Long> excludeMemberIds) {
meetingMemberValidator.validateUserIsMemberOfMeeting(userId, meetingId);

User user = userRepository.findById(userId)
.orElseThrow(NotFoundUserException::new);
List<MeetingMember> nextTargetMembers = meetingMemberRepository.findNextTargetsByMeeting(meetingId, userId,
excludeMemberIds);

MeetingMember meetingMember = validateAndCreateMember(userId, request, meeting, user);
addHobbies(meetingMember, request);
if (nextTargetMembers.isEmpty()) {
throw new NoMeetingMemberInConditionException();
}

createMeetingQuestionIfFirstMeetingMember(meeting, meetingMember);
MeetingMember randomMember = meetingMemberRandomGenerator.generate(nextTargetMembers);
return MeetingMemberListResponseDetail.from(randomMember);
}

return MeetingMemberPersistResponse.from(meetingMember);
public boolean isNotEnterAnyMeeting(Long userId) {
return meetingMemberRepository.findByUserId(userId).isEmpty();
}

private void createMeetingQuestionIfFirstMeetingMember(Meeting meeting, MeetingMember meetingMember) {
Long meetingId = meeting.getId();

if (meetingMemberRepository.isCountOfMembersIsOne(meetingId)) {
MeetingQuestion activeMeetingQuestion = MeetingQuestion.createActiveMeetingQuestion(
meeting, meetingMember, null, LocalDateTime.now());
meeting, meetingMember, null, LocalDateTime.now(), meeting.getTotalMemberCount());

meetingQuestionRepository.save(activeMeetingQuestion);
eventService.publish(meetingMember.getUser().getId(), meetingId, TARGET_MEMBER);
}
}

public MeetingMemberListResponseDetail getRandomMeetingMember(Long userId, Long meetingId,
List<Long> excludeMemberIds) {
meetingMemberValidator.validateUserIsMemberOfMeeting(userId, meetingId);

List<MeetingMember> nextTargetMembers = meetingMemberRepository.findNextTargetsByMeeting(meetingId, userId,
excludeMemberIds);

if (nextTargetMembers.isEmpty()) {
throw new NoMeetingMemberInConditionException();
}

MeetingMember randomMember = meetingMemberRandomGenerator.generate(nextTargetMembers);
return MeetingMemberListResponseDetail.from(randomMember);
}

private MeetingMember validateAndCreateMember(
Long userId, MeetingMemberPersistRequest request, Meeting meeting, User user
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public CurrentMeetingQuestionResponse save(Long userId, Long meetingId, MeetingQ
eventService.publish(member.getUser().getId(), meetingId, QUESTION_REGISTERED));

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

return CurrentMeetingQuestionResponse.questionRegisteredOf(currentMeetingQuestion, false);
Expand All @@ -83,7 +83,7 @@ public CurrentMeetingQuestionResponse save(Long userId, Long meetingId, MeetingQ
@Transactional
public MeetingQuestion createActiveQuestion(Meeting meeting, MeetingMember targetMember, Question activeQuestion) {
MeetingQuestion activeMeetingQuestion = MeetingQuestion.createActiveMeetingQuestion(meeting, targetMember,
activeQuestion, LocalDateTime.now(clock));
activeQuestion, LocalDateTime.now(clock), meeting.getTotalMemberCount());
return meetingQuestionRepository.save(activeMeetingQuestion);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
public class MeetingQuestionStatusCheckScheduler {

private final MeetingQuestionRepository meetingQuestionRepository;

private final EventService eventService;

@Scheduled(fixedDelay = 10 * 1000)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public class MeetingQuestion extends BaseTimeEntity {

private LocalDateTime expiredAt;

private int totalMemberCount; // 모임 질문 종료 시점의 모임원 수

@OneToMany(mappedBy = "meetingQuestion", fetch = FetchType.LAZY)
private List<MeetingAnswer> memberAnswers = new ArrayList<>();

Expand All @@ -76,14 +78,16 @@ private MeetingQuestion(
Question question,
LocalDateTime now,
MeetingQuestionStatus status,
LocalDateTime expiredAt
LocalDateTime expiredAt,
int totalMemberCount
) {
this.meeting = meeting;
this.targetMember = targetMember;
this.question = question;
this.startTime = now;
this.status = status;
this.expiredAt = expiredAt;
this.totalMemberCount = totalMemberCount;

meeting.addMeetingQuestion(this);
targetMember.addMeetingQuestion(this);
Expand All @@ -93,17 +97,18 @@ private MeetingQuestion(
}

public static MeetingQuestion createActiveMeetingQuestion(
Meeting meeting, MeetingMember targetMember, Question activeQuestion, LocalDateTime now
Meeting meeting, MeetingMember targetMember, Question activeQuestion, LocalDateTime now, int totalMemberCount
) {
LocalDateTime expiredAt = now.plusSeconds(RESPONSE_TIME_LIMIT_SECONDS);
return new MeetingQuestion(meeting, targetMember, activeQuestion, now, ACTIVE, expiredAt);
return new MeetingQuestion(meeting, targetMember, activeQuestion, now, ACTIVE, expiredAt, totalMemberCount);
}

public static MeetingQuestion createNextMeetingQuestion(
Meeting meeting, MeetingMember targetMember, LocalDateTime startTime
Meeting meeting, MeetingMember targetMember, LocalDateTime startTime, int totalMemberCount
) {
LocalDateTime expiredAt = startTime.plusSeconds(RESPONSE_TIME_LIMIT_SECONDS);
return new MeetingQuestion(meeting, targetMember, null, startTime, NOT_STARTED, expiredAt);
return new MeetingQuestion(meeting, targetMember, null, startTime, NOT_STARTED, expiredAt,
totalMemberCount);
}

public void addMeetingAnswer(MeetingAnswer meetingAnswer) {
Expand All @@ -120,7 +125,12 @@ public void registerQuestion(MeetingMember targetMember, Question question) {
}

public void updateStatusToInactive() {
if (this.status == INACTIVE) {
LoggingUtils.error("다음 MeetingQuestion 의 비활성화를 시도하였으나, 이미 비활성화된 질문입니다. meetingQuestionId : " + id);
return;
}
this.status = MeetingQuestionStatus.INACTIVE;
this.totalMemberCount = meeting.getTotalMemberCount();
}

public void updateStatusToActive(LocalDateTime startTime) {
Expand Down Expand Up @@ -153,6 +163,14 @@ public LocalDateTime getNextStartTime() {
return startTime.plusSeconds(RESPONSE_TIME_LIMIT_SECONDS);
}

public double calculateEngagementRate() {
Integer totalMemberCount = (status == INACTIVE) ? this.totalMemberCount : this.meeting.getTotalMemberCount();
if (totalMemberCount == 0)
return 0;
double engagementRate = ((double)getResponseCount() / totalMemberCount) * 100;
return Math.round(engagementRate);
}

public void validateNotFinished(LocalDateTime now) {
LocalDateTime endTime = startTime.plusSeconds(RESPONSE_TIME_LIMIT_SECONDS);
if (now.isAfter(endTime)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static CurrentMeetingQuestionResponse questionRegisteredOf(MeetingQuestio
.questionNumber(meeting.getQuestionNumber(meetingQuestion))
.totalMeetingMemberCount(meeting.getTotalMemberCount())
.responseCount(meetingQuestion.getResponseCount())
.engagementRate(meeting.calculateEngagementRate(meetingQuestion))
.engagementRate(meetingQuestion.calculateEngagementRate())
.startTime(meetingQuestion.getEpochMilliStartTime())
.isAnswered(isAnswered)
.isQuestionRegistered(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.Optional;

import org.depromeet.sambad.moring.answer.domain.Answer;
import org.depromeet.sambad.moring.meeting.meeting.domain.Meeting;
import org.depromeet.sambad.moring.meeting.question.domain.MeetingQuestion;

import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -31,13 +30,11 @@ public record MostInactiveMeetingQuestionListResponseDetail(

public static MostInactiveMeetingQuestionListResponseDetail of(MeetingQuestion meetingQuestion,
Optional<Answer> bestAnswer) {
Meeting meeting = meetingQuestion.getMeeting();

return MostInactiveMeetingQuestionListResponseDetail.builder()
.meetingQuestionId(meetingQuestion.getId())
.title(meetingQuestion.getQuestion().getTitle())
.content(bestAnswer.isPresent() ? bestAnswer.get().getContent() : null)
.engagementRate(meeting.calculateEngagementRate(meetingQuestion))
.engagementRate(meetingQuestion.calculateEngagementRate())
.startTime(meetingQuestion.getEpochMilliStartTime())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Question extends BaseTimeEntity {

private static final int MIN_ANSWER_COUNT = 2;
private static final int MAX_ANSWER_COUNT = 9;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "question_id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
public enum QuestionType {
SINGLE_CHOICE, MULTIPLE_SHORT_CHOICE, MULTIPLE_DESCRIPTIVE_CHOICE;

private static final int MIN_ANSWER_COUNT = 2;
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
@RequiredArgsConstructor
public enum QuestionExceptionCode implements ExceptionCode {

ANSWER_COUNT_OUT_OF_RANGE(BAD_REQUEST, "답변 개수가 범위를 벗어났습니다. 2개 이상 16개 이하로 입력해주세요."),
ANSWER_COUNT_OUT_OF_RANGE(BAD_REQUEST, "답변 개수가 범위를 벗어났습니다. 1개 이상 16개 이하로 입력해주세요."),

NOT_FOUND_QUESTION(NOT_FOUND, "릴레이 질문이 존재하지 않습니다."),
NOT_FOUND_AVAILABLE_QUESTION(NOT_FOUND, "사용 가능한 질문이 존재하지 않습니다."),
Expand Down
Loading