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

[FEAT] 게임 화면에서 멤버별 투표 여부 확인하기 #412

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
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 @@ -38,6 +38,10 @@ public RoomBalanceVote(Member member, BalanceOption balanceOption) {
this.balanceOption = balanceOption;
}

public boolean isOwner(Member member) {
return this.member.getId().equals(member.getId());
}

public Long getOptionId() {
return balanceOption.getId();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface RoomBalanceVoteRepository extends JpaRepository<RoomBalanceVote

List<RoomBalanceVote> findByMemberInAndBalanceOption(List<Member> members, BalanceOption balanceOption);

long countByMemberInAndBalanceOptionIn(List<Member> members, List<BalanceOption> balanceOptions);
List<RoomBalanceVote> findByMemberInAndBalanceOptionIn(List<Member> members, List<BalanceOption> balanceOptions);

List<RoomBalanceVote> findByMemberRoom(Room room);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ddangkong.domain.room.balance.roomvote;

import ddangkong.domain.balance.option.BalanceOptions;
import ddangkong.domain.room.member.Member;
import ddangkong.domain.room.member.RoomMembers;
import java.util.List;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Getter
@Slf4j
public class VotingStatus {

private final RoomMembers roomMembers;
private final BalanceOptions balanceOptions;
private final List<RoomBalanceVote> votes;
private final boolean voteFinished;

public VotingStatus(RoomMembers roomMembers,
BalanceOptions balanceOptions,
List<RoomBalanceVote> votes,
boolean voteFinished) {
checkVoteSize(roomMembers, votes);

this.roomMembers = roomMembers;
this.balanceOptions = balanceOptions;
this.votes = votes;
this.voteFinished = voteFinished;
}

private static void checkVoteSize(RoomMembers roomMembers, List<RoomBalanceVote> votes) {
if (votes.size() > roomMembers.size()) {
log.error("[Concurrency Error] 투표한 인원 수가 방 인원 수보다 많습니다. 투표한 인원 수: {}, 방 인원 수: {}",
votes.size(), roomMembers.size());
}
}

public Member getMember(Long memberId) {
return roomMembers.getMember(memberId);
}

public List<Member> getMembers() {
return roomMembers.getMembers();
}

public int getMemberCount() {
return roomMembers.size();
}

public int getVoteCount() {
return votes.size();
}

public boolean didVote(Member member) {
return votes.stream()
.anyMatch(vote -> vote.isOwner(member));
}

public boolean isVoteNotFinished() {
return !voteFinished;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import ddangkong.exception.room.balance.roomvote.VoteFinishedException;
import ddangkong.exception.room.balance.roomvote.VoteNotFinishedException;
import ddangkong.facade.balance.vote.dto.ContentTotalBalanceVoteResponse;
import ddangkong.facade.room.balance.roomvote.context.VoteContext;
import ddangkong.domain.room.balance.roomvote.VotingStatus;
import ddangkong.facade.room.balance.roomvote.dto.ContentRoomBalanceVoteResponse;
import ddangkong.facade.room.balance.roomvote.dto.RoomBalanceVoteRequest;
import ddangkong.facade.room.balance.roomvote.dto.RoomBalanceVoteResponse;
Expand Down Expand Up @@ -56,25 +56,25 @@ public class RoomBalanceVoteFacade {

@Transactional
public RoomBalanceVoteResponse createVote(RoomBalanceVoteRequest request, Long roomId, Long contentId) {
VoteContext voteContext = getVoteContext(roomId, contentId);
if (voteContext.isVoteFinished()) {
VotingStatus votingStatus = getVotingStatus(roomId, contentId);
if (votingStatus.isVoteFinished()) {
throw new VoteFinishedException();
}
Member member = voteContext.getMember(request.memberId());
RoomBalanceVote roomBalanceVote = roomBalanceVoteService.createVote(member, voteContext.getBalanceOptions(),
Member member = votingStatus.getMember(request.memberId());
RoomBalanceVote roomBalanceVote = roomBalanceVoteService.createVote(member, votingStatus.getBalanceOptions(),
request.optionId());
return new RoomBalanceVoteResponse(roomBalanceVote);
}

@Transactional(readOnly = true)
public RoomBalanceVoteResultResponse getAllVoteResult(Long roomId, Long contentId) {
VoteContext voteContext = getVoteContext(roomId, contentId);
if (voteContext.isVoteNotFinished()) {
VotingStatus votingStatus = getVotingStatus(roomId, contentId);
if (votingStatus.isVoteNotFinished()) {
throw new VoteNotFinishedException();
}
ContentRoomBalanceVoteResponse group = getContentRoomBalanceVoteResponse(voteContext.getRoomMembers(),
voteContext.getBalanceOptions());
ContentTotalBalanceVoteResponse total = getContentTotalBalanceVoteResponse(voteContext.getBalanceOptions());
ContentRoomBalanceVoteResponse group = getContentRoomBalanceVoteResponse(votingStatus.getRoomMembers(),
votingStatus.getBalanceOptions());
ContentTotalBalanceVoteResponse total = getContentTotalBalanceVoteResponse(votingStatus.getBalanceOptions());
return new RoomBalanceVoteResultResponse(group, total);
}

Expand Down Expand Up @@ -112,19 +112,21 @@ private ContentTotalBalanceVoteResponse getContentTotalBalanceVoteResponse(Balan

@Transactional(readOnly = true)
public VoteFinishedResponse getVoteFinished(Long roomId, Long contentId) {
VoteContext voteContext = getVoteContext(roomId, contentId);
return new VoteFinishedResponse(voteContext.isVoteFinished());
VotingStatus votingStatus = getVotingStatus(roomId, contentId);
return VoteFinishedResponse.from(votingStatus);
}

private VoteContext getVoteContext(Long roomId, Long contentId) {
private VotingStatus getVotingStatus(Long roomId, Long contentId) {
Room room = roomService.getRoom(roomId);
BalanceContent balanceContent = balanceContentService.getBalanceContent(contentId);
RoomMembers roomMembers = memberService.findRoomMembers(room);
BalanceOptions balanceOptions = balanceOptionService.getBalanceOptions(balanceContent);
List<RoomBalanceVote> votes = roomBalanceVoteService.getVotesInRound(roomMembers, balanceOptions);

boolean isOverVoteDeadline = roomContentService.isOverVoteDeadline(room, balanceContent);
boolean isAllMemberVoted = roomBalanceVoteService.isAllMemberVoted(roomMembers, balanceOptions);
boolean isAllMemberVoted = votes.size() >= roomMembers.size();

return new VoteContext(roomMembers, balanceOptions, isOverVoteDeadline || isAllMemberVoted);
return new VotingStatus(roomMembers, balanceOptions, votes, isOverVoteDeadline || isAllMemberVoted);
}

@Transactional(readOnly = true)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
package ddangkong.facade.room.balance.roomvote.dto;

import ddangkong.domain.room.balance.roomvote.VotingStatus;
import java.util.List;

public record VoteFinishedResponse(
boolean isFinished
boolean isFinished,
int memberCount,
int voteCount,
List<VoteStatusPerMemberResponse> memberStates
) {

public static VoteFinishedResponse from(VotingStatus status) {
List<VoteStatusPerMemberResponse> memberStates = status.getMembers()
.stream()
.map(member -> new VoteStatusPerMemberResponse(member, status.didVote(member)))
.toList();

return new VoteFinishedResponse(
status.isVoteFinished(),
status.getMemberCount(),
status.getVoteCount(),
memberStates);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ddangkong.facade.room.balance.roomvote.dto;

import ddangkong.domain.room.member.Member;
import ddangkong.facade.room.member.dto.MemberResponse;

public record VoteStatusPerMemberResponse(
MemberResponse member,
boolean isVoteFinished
) {

public VoteStatusPerMemberResponse(Member member, boolean isVoteFinished) {
this(new MemberResponse(member), isVoteFinished);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@
import ddangkong.exception.room.balance.roomvote.AlreadyVotedException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class RoomBalanceVoteService {

private final RoomBalanceVoteRepository roomVoteRepository;
Expand Down Expand Up @@ -45,30 +43,21 @@ private void validDuplicatedVote(Member member, BalanceOption balanceOption) {
}

@Transactional(readOnly = true)
public boolean isAllMemberVoted(RoomMembers roomMembers, BalanceOptions balanceOptions) {
long voteCount = roomVoteRepository.countByMemberInAndBalanceOptionIn(roomMembers.getMembers(),
balanceOptions.getOptions());
if (voteCount > roomMembers.size()) {
log.error("[Concurrency Error] 투표한 인원 수가 방 인원 수보다 많습니다. 투표한 인원 수: {}, 방 인원 수: {}",
voteCount, roomMembers.size());
}
return voteCount >= roomMembers.size();
public List<RoomBalanceVote> getVotesInRoom(RoomMembers roomMembers, BalanceOption balanceOption) {
return roomVoteRepository.findByMemberInAndBalanceOption(roomMembers.getMembers(), balanceOption);
}

@Transactional(readOnly = true)
public List<RoomBalanceVote> getVotesInRoom(RoomMembers roomMembers, BalanceOption balanceOption) {
return roomVoteRepository.findByMemberInAndBalanceOption(roomMembers.getMembers(), balanceOption);
public List<RoomBalanceVote> getVotesInRound(RoomMembers roomMembers, BalanceOptions balanceOptions) {
return roomVoteRepository.findByMemberInAndBalanceOptionIn(
roomMembers.getMembers(), balanceOptions.getOptions());
}

@Transactional(readOnly = true)
public List<RoomBalanceVote> findRoomVotesByBalanceOptionsWithoutMember(List<BalanceOption> memberRoomVoteOptions,
Room room,
Member member) {
return roomVoteRepository.findRoomBalanceVotesByBalanceOptionsAndRoomWithoutMember(memberRoomVoteOptions, room,
member);
}

@Transactional
public void deleteRoomVotes(List<RoomBalanceVote> roomBalanceVotes) {
roomVoteRepository.deleteAllInBatch(roomBalanceVotes);
return roomVoteRepository.findRoomBalanceVotesByBalanceOptionsAndRoomWithoutMember(
memberRoomVoteOptions, room, member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,13 @@ void init() {
}

@Test
void 투표_마감_시간이_지나지_않고_방의_모든_멤버가_투표하지_않으면_투표가_종료되지_않는다() {
void 투표_진행_중인_상황을_알_수_있다() {
// given
LocalDateTime voteDeadline = LocalDateTime.parse("2024-08-03T20:00:08");
roomContentFixture.create(room, balanceContent, 1, voteDeadline);

roomBalanceVoteFixture.create(master, optionA);

// when
VoteFinishedResponse actual = RestAssured.given().log().all()
.pathParam("roomId", room.getId())
Expand All @@ -145,7 +147,19 @@ void init() {
.extract().as(VoteFinishedResponse.class);

// then
assertThat(actual.isFinished()).isEqualTo(false);
assertAll(
() -> assertThat(actual.isFinished()).isFalse(),
() -> assertThat(actual.memberCount()).isEqualTo(2),
() -> assertThat(actual.voteCount()).isEqualTo(1),
() -> assertThat(actual.memberStates().get(0).member().memberId()).isEqualTo(master.getId()),
() -> assertThat(actual.memberStates().get(0).member().isMaster()).isEqualTo(master.isMaster()),
() -> assertThat(actual.memberStates().get(0).member().nickname()).isEqualTo(master.getNickname()),
() -> assertThat(actual.memberStates().get(0).isVoteFinished()).isTrue(),
() -> assertThat(actual.memberStates().get(1).member().memberId()).isEqualTo(common.getId()),
() -> assertThat(actual.memberStates().get(1).member().isMaster()).isEqualTo(common.isMaster()),
() -> assertThat(actual.memberStates().get(1).member().nickname()).isEqualTo(common.getNickname()),
() -> assertThat(actual.memberStates().get(1).isVoteFinished()).isFalse()
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import ddangkong.facade.room.balance.roomvote.dto.RoomMemberVoteMatchingResponse;
import ddangkong.facade.room.balance.roomvote.dto.RoomMembersVoteMatchingResponse;
import ddangkong.facade.room.balance.roomvote.dto.VoteFinishedResponse;
import ddangkong.facade.room.balance.roomvote.dto.VoteStatusPerMemberResponse;
import ddangkong.facade.room.member.dto.MemberResponse;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Nested;
Expand Down Expand Up @@ -166,7 +168,11 @@ class 투표_종료_여부_조회 {
@Test
void 투표가_종료되었는지_조회한다() throws Exception {
// given
VoteFinishedResponse response = new VoteFinishedResponse(true);
List<VoteStatusPerMemberResponse> memberStates = List.of(
new VoteStatusPerMemberResponse(new MemberResponse(1L, "커찬", false), false),
new VoteStatusPerMemberResponse(new MemberResponse(2L, "마루", true), true)
);
VoteFinishedResponse response = new VoteFinishedResponse(true, 2, 1, memberStates);
when(roomBalanceVoteFacade.getVoteFinished(anyLong(), anyLong())).thenReturn(response);

// when & then
Expand All @@ -178,7 +184,15 @@ class 투표_종료_여부_조회 {
parameterWithName("contentId").description("콘텐츠 ID")
),
responseFields(
fieldWithPath("isFinished").type(BOOLEAN).description("투표 종료 여부")
fieldWithPath("isFinished").type(BOOLEAN).description("투표 종료 여부"),
fieldWithPath("memberCount").type(NUMBER).description("방에 참여한 인원"),
fieldWithPath("voteCount").type(NUMBER).description("투표한 인원"),
fieldWithPath("memberStates").type(ARRAY).description("방 참여 인원들의 투표 현황"),
fieldWithPath("memberStates[].member").type(OBJECT).description("해당 멤버 정보"),
fieldWithPath("memberStates[].member.memberId").type(NUMBER).description("멤버 ID"),
fieldWithPath("memberStates[].member.nickname").type(STRING).description("멤버 이름"),
fieldWithPath("memberStates[].member.isMaster").type(BOOLEAN).description("마스터 여부"),
fieldWithPath("memberStates[].isVoteFinished").type(BOOLEAN).description("멤버 투표 여부")
)
)
);
Expand All @@ -187,6 +201,7 @@ class 투표_종료_여부_조회 {

@Nested
class 투표_매칭도_조회 {

private static final String ENDPOINT = "/api/balances/rooms/{roomId}/members/{memberId}/matching";

@Test
Expand Down
Loading