diff --git a/backend/src/main/java/ddangkong/domain/room/balance/roomvote/RoomBalanceVoteRepository.java b/backend/src/main/java/ddangkong/domain/room/balance/roomvote/RoomBalanceVoteRepository.java index 1beacaa90..10746dce2 100644 --- a/backend/src/main/java/ddangkong/domain/room/balance/roomvote/RoomBalanceVoteRepository.java +++ b/backend/src/main/java/ddangkong/domain/room/balance/roomvote/RoomBalanceVoteRepository.java @@ -11,7 +11,7 @@ public interface RoomBalanceVoteRepository extends JpaRepository findByMemberInAndBalanceOption(List members, BalanceOption balanceOption); - long countByMemberInAndBalanceOptionIn(List members, List balanceOptions); + int countByMemberInAndBalanceOptionIn(List members, List balanceOptions); List findByMemberRoom(Room room); diff --git a/backend/src/main/java/ddangkong/domain/room/balance/roomvote/VotingStatus.java b/backend/src/main/java/ddangkong/domain/room/balance/roomvote/VotingStatus.java new file mode 100644 index 000000000..b00b17436 --- /dev/null +++ b/backend/src/main/java/ddangkong/domain/room/balance/roomvote/VotingStatus.java @@ -0,0 +1,53 @@ +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 int voteCount; + private final boolean isVoteFinished; + + public VotingStatus(RoomMembers roomMembers, + BalanceOptions balanceOptions, + int voteCount, + boolean isVoteFinished) { + checkVoteSize(roomMembers, voteCount); + + this.roomMembers = roomMembers; + this.balanceOptions = balanceOptions; + this.voteCount = voteCount; + this.isVoteFinished = isVoteFinished; + } + + private void checkVoteSize(RoomMembers roomMembers, int voteCount) { + if (voteCount > roomMembers.size()) { + log.error("[Concurrency Error] 투표한 인원 수가 방 인원 수보다 많습니다. 투표한 인원 수: {}, 방 인원 수: {}", + voteCount, roomMembers.size()); + } + } + + public Member getMember(Long memberId) { + return roomMembers.getMember(memberId); + } + + public List getMembers() { + return roomMembers.getMembers(); + } + + public int getMemberCount() { + return roomMembers.size(); + } + + public boolean isVoteNotFinished() { + return !isVoteFinished; + } +} diff --git a/backend/src/main/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacade.java b/backend/src/main/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacade.java index 9a2e9a92b..f41fba57b 100644 --- a/backend/src/main/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacade.java +++ b/backend/src/main/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacade.java @@ -5,13 +5,13 @@ import ddangkong.domain.balance.option.BalanceOptions; import ddangkong.domain.room.Room; import ddangkong.domain.room.balance.roomvote.RoomBalanceVote; +import ddangkong.domain.room.balance.roomvote.VotingStatus; import ddangkong.domain.room.member.Member; import ddangkong.domain.room.member.RoomMembers; import ddangkong.exception.room.balance.roomvote.CanNotCheckMatchingPercentException; 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.facade.room.balance.roomvote.dto.ContentRoomBalanceVoteResponse; import ddangkong.facade.room.balance.roomvote.dto.RoomBalanceVoteRequest; import ddangkong.facade.room.balance.roomvote.dto.RoomBalanceVoteResponse; @@ -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); } @@ -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 new VoteFinishedResponse(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); + int voteCount = roomBalanceVoteService.countVotesInRound(roomMembers, balanceOptions); + boolean isOverVoteDeadline = roomContentService.isOverVoteDeadline(room, balanceContent); - boolean isAllMemberVoted = roomBalanceVoteService.isAllMemberVoted(roomMembers, balanceOptions); + boolean isAllMemberVoted = voteCount >= roomMembers.size(); - return new VoteContext(roomMembers, balanceOptions, isOverVoteDeadline || isAllMemberVoted); + return new VotingStatus(roomMembers, balanceOptions, voteCount, isOverVoteDeadline || isAllMemberVoted); } @Transactional(readOnly = true) @@ -145,10 +147,9 @@ private Map getRoomMembersVoteMatchingCountWithoutSelf(Room room, List roomBalanceVotes = roomBalanceVoteService.findRoomVotesByBalanceOptionsWithoutMember( memberRoomVoteOptions, room, member); - Map membersVoteMatchingCount = roomBalanceVotes.stream() + return roomBalanceVotes.stream() .map(RoomBalanceVote::getMember) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); - return membersVoteMatchingCount; } private RoomMembersVoteMatchingResponse getRoomMembersVoteMatchingPercent(Map membersAndMatchingCount, diff --git a/backend/src/main/java/ddangkong/facade/room/balance/roomvote/context/VoteContext.java b/backend/src/main/java/ddangkong/facade/room/balance/roomvote/context/VoteContext.java deleted file mode 100644 index 646cb399b..000000000 --- a/backend/src/main/java/ddangkong/facade/room/balance/roomvote/context/VoteContext.java +++ /dev/null @@ -1,30 +0,0 @@ -package ddangkong.facade.room.balance.roomvote.context; - -import ddangkong.domain.balance.option.BalanceOptions; -import ddangkong.domain.room.member.Member; -import ddangkong.domain.room.member.RoomMembers; -import lombok.Getter; - -@Getter -public class VoteContext { - - private final RoomMembers roomMembers; - - private final BalanceOptions balanceOptions; - - private final boolean voteFinished; - - public VoteContext(RoomMembers roomMembers, BalanceOptions balanceOptions, boolean voteFinished) { - this.roomMembers = roomMembers; - this.balanceOptions = balanceOptions; - this.voteFinished = voteFinished; - } - - public Member getMember(Long memberId) { - return roomMembers.getMember(memberId); - } - - public boolean isVoteNotFinished() { - return !voteFinished; - } -} diff --git a/backend/src/main/java/ddangkong/facade/room/balance/roomvote/dto/VoteFinishedResponse.java b/backend/src/main/java/ddangkong/facade/room/balance/roomvote/dto/VoteFinishedResponse.java index cfd5f97af..60981a974 100644 --- a/backend/src/main/java/ddangkong/facade/room/balance/roomvote/dto/VoteFinishedResponse.java +++ b/backend/src/main/java/ddangkong/facade/room/balance/roomvote/dto/VoteFinishedResponse.java @@ -1,6 +1,14 @@ package ddangkong.facade.room.balance.roomvote.dto; +import ddangkong.domain.room.balance.roomvote.VotingStatus; + public record VoteFinishedResponse( - boolean isFinished + boolean isFinished, + int memberCount, + int voteCount ) { + + public VoteFinishedResponse(VotingStatus status) { + this(status.isVoteFinished(), status.getMemberCount(), status.getVoteCount()); + } } diff --git a/backend/src/main/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteService.java b/backend/src/main/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteService.java index 39c1ca8dd..3c3d9a79a 100644 --- a/backend/src/main/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteService.java +++ b/backend/src/main/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteService.java @@ -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; @@ -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 getVotesInRoom(RoomMembers roomMembers, BalanceOption balanceOption) { + return roomVoteRepository.findByMemberInAndBalanceOption(roomMembers.getMembers(), balanceOption); } @Transactional(readOnly = true) - public List getVotesInRoom(RoomMembers roomMembers, BalanceOption balanceOption) { - return roomVoteRepository.findByMemberInAndBalanceOption(roomMembers.getMembers(), balanceOption); + public int countVotesInRound(RoomMembers roomMembers, BalanceOptions balanceOptions) { + return roomVoteRepository.countByMemberInAndBalanceOptionIn( + roomMembers.getMembers(), balanceOptions.getOptions()); } + @Transactional(readOnly = true) public List findRoomVotesByBalanceOptionsWithoutMember(List memberRoomVoteOptions, Room room, Member member) { - return roomVoteRepository.findRoomBalanceVotesByBalanceOptionsAndRoomWithoutMember(memberRoomVoteOptions, room, - member); - } - - @Transactional - public void deleteRoomVotes(List roomBalanceVotes) { - roomVoteRepository.deleteAllInBatch(roomBalanceVotes); + return roomVoteRepository.findRoomBalanceVotesByBalanceOptionsAndRoomWithoutMember( + memberRoomVoteOptions, room, member); } } diff --git a/backend/src/test/java/ddangkong/controller/room/balance/roomvote/RoomBalanceVoteControllerTest.java b/backend/src/test/java/ddangkong/controller/room/balance/roomvote/RoomBalanceVoteControllerTest.java index 550ef5bcc..0b1b52268 100644 --- a/backend/src/test/java/ddangkong/controller/room/balance/roomvote/RoomBalanceVoteControllerTest.java +++ b/backend/src/test/java/ddangkong/controller/room/balance/roomvote/RoomBalanceVoteControllerTest.java @@ -107,7 +107,11 @@ void init() { .extract().as(VoteFinishedResponse.class); // then - assertThat(actual.isFinished()).isEqualTo(true); + assertAll( + () -> assertThat(actual.isFinished()).isTrue(), + () -> assertThat(actual.memberCount()).isEqualTo(2), + () -> assertThat(actual.voteCount()).isEqualTo(2) + ); } @Test @@ -126,7 +130,11 @@ void init() { .extract().as(VoteFinishedResponse.class); // then - assertThat(actual.isFinished()).isEqualTo(true); + assertAll( + () -> assertThat(actual.isFinished()).isTrue(), + () -> assertThat(actual.memberCount()).isEqualTo(2), + () -> assertThat(actual.voteCount()).isEqualTo(0) + ); } @Test @@ -135,6 +143,8 @@ void init() { 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()) @@ -145,7 +155,11 @@ 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) + ); } } diff --git a/backend/src/test/java/ddangkong/documentation/room/balance/roomvote/RoomBalanceVoteDocumentationTest.java b/backend/src/test/java/ddangkong/documentation/room/balance/roomvote/RoomBalanceVoteDocumentationTest.java index 50bc15904..b9010d1a4 100644 --- a/backend/src/test/java/ddangkong/documentation/room/balance/roomvote/RoomBalanceVoteDocumentationTest.java +++ b/backend/src/test/java/ddangkong/documentation/room/balance/roomvote/RoomBalanceVoteDocumentationTest.java @@ -166,7 +166,7 @@ class 투표_종료_여부_조회 { @Test void 투표가_종료되었는지_조회한다() throws Exception { // given - VoteFinishedResponse response = new VoteFinishedResponse(true); + VoteFinishedResponse response = new VoteFinishedResponse(true, 2, 1); when(roomBalanceVoteFacade.getVoteFinished(anyLong(), anyLong())).thenReturn(response); // when & then @@ -178,7 +178,9 @@ 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("투표한 인원") ) ) ); @@ -187,6 +189,7 @@ class 투표_종료_여부_조회 { @Nested class 투표_매칭도_조회 { + private static final String ENDPOINT = "/api/balances/rooms/{roomId}/members/{memberId}/matching"; @Test diff --git a/backend/src/test/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacadeTest.java b/backend/src/test/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacadeTest.java index 3bd2812e2..55cb04065 100644 --- a/backend/src/test/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacadeTest.java +++ b/backend/src/test/java/ddangkong/facade/room/balance/roomvote/RoomBalanceVoteFacadeTest.java @@ -209,7 +209,6 @@ void init() { balanceContent = balanceContentFixture.create(room.getCategory()); option1 = balanceOptionFixture.create(balanceContent); option2 = balanceOptionFixture.create(balanceContent); - } @Test @@ -260,6 +259,25 @@ void init() { assertThat(actual.isFinished()).isFalse(); } + @Test + void 현재_투표가_진행_중인_상황들을_조회할_수_있다() { + // given + int round = 1; + LocalDateTime notFinishedTime = LocalDateTime.parse("2024-08-03T11:00:09"); + roomContentFixture.initRoomContent(room, balanceContent, round, notFinishedTime); + roomBalanceVoteFixture.create(master, option1); + + // when + VoteFinishedResponse actual = roomBalanceVoteFacade.getVoteFinished(room.getId(), balanceContent.getId()); + + // then + assertAll( + () -> assertThat(actual.isFinished()).isFalse(), + () -> assertThat(actual.memberCount()).isEqualTo(2), + () -> assertThat(actual.voteCount()).isEqualTo(1) + ); + } + @Test void 방의_현재_라운드와_다른_방_컨텐츠의_투표_종료_여부를_조회하면_예외가_발생한다() { // given diff --git a/backend/src/test/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteServiceTest.java b/backend/src/test/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteServiceTest.java index 72123fd4f..cd9cec3ea 100644 --- a/backend/src/test/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteServiceTest.java +++ b/backend/src/test/java/ddangkong/service/room/balance/roomvote/RoomBalanceVoteServiceTest.java @@ -10,7 +10,6 @@ import ddangkong.domain.room.Room; import ddangkong.domain.room.balance.roomvote.RoomBalanceVote; import ddangkong.domain.room.member.Member; -import ddangkong.domain.room.member.RoomMembers; import ddangkong.exception.room.balance.roomvote.AlreadyVotedException; import ddangkong.facade.BaseServiceTest; import java.util.List; @@ -78,60 +77,4 @@ void setUp() { "이미 투표했습니다. nickname: %s, option name: %s".formatted(member.getNickname(), option1.getName())); } } - - @Nested - class 모든_멤버_투표_완료_여부 { - - private BalanceOptions balanceOptions; - - private Room room; - private RoomMembers members; - private Member member1; - private Member member2; - private Member member3; - private BalanceContent balanceContent; - private BalanceOption option1; - private BalanceOption option2; - - @BeforeEach - void setUp() { - room = roomFixture.createNotStartedRoom(); - member1 = memberFixture.createMaster(room); - member2 = memberFixture.createCommon(1, room); - member3 = memberFixture.createCommon(2, room); - members = new RoomMembers(List.of(member1, member2, member3)); - - balanceContent = balanceContentFixture.create(room.getCategory()); - option1 = balanceOptionFixture.create(balanceContent); - option2 = balanceOptionFixture.create(balanceContent); - balanceOptions = new BalanceOptions(List.of(option1, option2)); - } - - @Test - void 모든_인원이_투표했으면_true를_반환한다() { - // given - roomBalanceVoteFixture.create(member1, option1); - roomBalanceVoteFixture.create(member2, option1); - roomBalanceVoteFixture.create(member3, option2); - - // when - boolean isAllMemberVoted = roomBalanceVoteService.isAllMemberVoted(members, balanceOptions); - - // then - assertThat(isAllMemberVoted).isTrue(); - } - - @Test - void 모든_인원이_투표하지_않았으면_false를_반환한다() { - // given - roomBalanceVoteFixture.create(member1, option1); - roomBalanceVoteFixture.create(member2, option1); - - // when - boolean isAllMemberVoted = roomBalanceVoteService.isAllMemberVoted(members, balanceOptions); - - // then - assertThat(isAllMemberVoted).isFalse(); - } - } }