Skip to content

Commit 7a8c985

Browse files
authored
[FEAT] 투표자 API 구현 (#205)
1 parent ca1c4c1 commit 7a8c985

34 files changed

Lines changed: 967 additions & 19 deletions
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.debatetimer.config;
2+
3+
import com.debatetimer.exception.decoder.H2ErrorDecoder;
4+
import com.debatetimer.exception.decoder.MySqlErrorDecoder;
5+
import com.debatetimer.exception.decoder.RepositoryErrorDecoder;
6+
import lombok.NoArgsConstructor;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
import org.springframework.context.annotation.Profile;
10+
11+
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
12+
public class ErrorDecoderConfig {
13+
14+
@Profile({"dev", "prod"})
15+
@Configuration
16+
public static class MySqlErrorDecoderConfig {
17+
18+
@Bean
19+
public RepositoryErrorDecoder mySqlErrorDecoder() {
20+
return new MySqlErrorDecoder();
21+
}
22+
}
23+
24+
@Profile({"test", "local"})
25+
@Configuration
26+
public static class H2ErrorDecoderConfig {
27+
28+
@Bean
29+
public RepositoryErrorDecoder h2ErrorDecoder() {
30+
return new H2ErrorDecoder();
31+
}
32+
}
33+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.debatetimer.controller.poll;
2+
3+
import com.debatetimer.dto.poll.request.VoteRequest;
4+
import com.debatetimer.dto.poll.response.VoteCreateResponse;
5+
import com.debatetimer.dto.poll.response.VoterPollInfoResponse;
6+
import com.debatetimer.service.poll.VoteService;
7+
import jakarta.validation.Valid;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.http.HttpStatus;
10+
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.PathVariable;
12+
import org.springframework.web.bind.annotation.PostMapping;
13+
import org.springframework.web.bind.annotation.RequestBody;
14+
import org.springframework.web.bind.annotation.ResponseStatus;
15+
import org.springframework.web.bind.annotation.RestController;
16+
17+
@RestController
18+
@RequiredArgsConstructor
19+
public class VoteController {
20+
21+
private final VoteService voteService;
22+
23+
@GetMapping("/api/polls/{pollId}/votes")
24+
@ResponseStatus(HttpStatus.OK)
25+
public VoterPollInfoResponse getVotersPollInfo(@PathVariable long pollId) {
26+
return voteService.getVoterPollInfo(pollId);
27+
}
28+
29+
@PostMapping("/api/polls/{pollId}/votes")
30+
@ResponseStatus(HttpStatus.CREATED)
31+
public VoteCreateResponse votePoll(
32+
@PathVariable long pollId,
33+
@RequestBody @Valid VoteRequest voteRequest
34+
) {
35+
return voteService.vote(pollId, voteRequest);
36+
}
37+
}

src/main/java/com/debatetimer/domain/member/Member.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.debatetimer.domain.member;
22

3-
import com.debatetimer.entity.customize.BaseTimeEntity;
3+
import com.debatetimer.entity.BaseTimeEntity;
44
import jakarta.persistence.Column;
55
import jakarta.persistence.Entity;
66
import jakarta.persistence.GeneratedValue;

src/main/java/com/debatetimer/domain/poll/Poll.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,8 @@ public Poll(Long id, long tableId, long memberId, PollStatus status,
2626
String prosTeamName, String consTeamName, String agenda) {
2727
this(id, tableId, memberId, status, new TeamName(prosTeamName), new TeamName(consTeamName), new Agenda(agenda));
2828
}
29+
30+
public boolean isProgress() {
31+
return status.isProgress();
32+
}
2933
}

src/main/java/com/debatetimer/domain/poll/PollStatus.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ public enum PollStatus {
55
PROGRESS,
66
DONE,
77
;
8+
9+
public boolean isProgress() {
10+
return this == PROGRESS;
11+
}
812
}

src/main/java/com/debatetimer/domain/poll/Vote.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public class Vote {
1313
private final ParticipantName name;
1414
private final ParticipateCode code;
1515

16+
public Vote(long pollId, VoteTeam team, String name, String code) {
17+
this(null, pollId, team, name, code);
18+
}
19+
1620
public Vote(Long id, long pollId, VoteTeam team, String name, String code) {
1721
this(id, pollId, team, new ParticipantName(name), new ParticipateCode(code));
1822
}

src/main/java/com/debatetimer/domainrepository/poll/PollDomainRepository.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import com.debatetimer.domain.poll.Poll;
44
import com.debatetimer.entity.poll.PollEntity;
5-
import com.debatetimer.exception.custom.DTClientErrorException;
6-
import com.debatetimer.exception.errorcode.ClientErrorCode;
75
import com.debatetimer.repository.poll.PollRepository;
86
import lombok.RequiredArgsConstructor;
97
import org.springframework.stereotype.Repository;
@@ -24,19 +22,20 @@ public Poll create(Poll poll) {
2422

2523
@Transactional(readOnly = true)
2624
public Poll getByIdAndMemberId(long id, long memberId) {
27-
return findPoll(id, memberId)
25+
return pollRepository.getByIdAndMemberId(id, memberId)
26+
.toDomain();
27+
}
28+
29+
@Transactional(readOnly = true)
30+
public Poll getById(long id) {
31+
return pollRepository.getById(id)
2832
.toDomain();
2933
}
3034

3135
@Transactional
3236
public Poll finishPoll(long pollId, long memberId) {
33-
PollEntity pollEntity = findPoll(pollId, memberId);
37+
PollEntity pollEntity = pollRepository.getByIdAndMemberId(pollId, memberId);
3438
pollEntity.updateToDone();
3539
return pollEntity.toDomain();
3640
}
37-
38-
private PollEntity findPoll(long pollId, long memberId) {
39-
return pollRepository.findByIdAndMemberId(pollId, memberId)
40-
.orElseThrow(() -> new DTClientErrorException(ClientErrorCode.POLL_NOT_FOUND));
41-
}
4241
}

src/main/java/com/debatetimer/domainrepository/poll/VoteDomainRepository.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
package com.debatetimer.domainrepository.poll;
22

3+
import com.debatetimer.domain.poll.ParticipateCode;
4+
import com.debatetimer.domain.poll.Vote;
35
import com.debatetimer.domain.poll.VoteInfo;
46
import com.debatetimer.domain.poll.VoteTeam;
7+
import com.debatetimer.entity.poll.PollEntity;
58
import com.debatetimer.entity.poll.VoteEntity;
9+
import com.debatetimer.exception.custom.DTClientErrorException;
10+
import com.debatetimer.exception.decoder.RepositoryErrorDecoder;
11+
import com.debatetimer.exception.errorcode.ClientErrorCode;
12+
import com.debatetimer.repository.poll.PollRepository;
613
import com.debatetimer.repository.poll.VoteRepository;
714
import java.util.List;
815
import java.util.Map;
916
import java.util.stream.Collectors;
1017
import lombok.RequiredArgsConstructor;
18+
import org.springframework.dao.DataIntegrityViolationException;
1119
import org.springframework.stereotype.Repository;
1220

1321
@Repository
1422
@RequiredArgsConstructor
1523
public class VoteDomainRepository {
1624

25+
private final PollRepository pollRepository;
1726
private final VoteRepository voteRepository;
27+
private final RepositoryErrorDecoder errorDecoder;
1828

1929
public VoteInfo findVoteInfoByPollId(long pollId) {
2030
List<VoteEntity> pollVotes = voteRepository.findAllByPollId(pollId);
@@ -28,4 +38,22 @@ private VoteInfo countVotes(long pollId, List<VoteEntity> voteEntities) {
2838
long consCount = teamCount.getOrDefault(VoteTeam.CONS, 0L);
2939
return new VoteInfo(pollId, prosCount, consCount);
3040
}
41+
42+
public boolean isExists(long pollId, ParticipateCode code) {
43+
return voteRepository.existsByPollIdAndParticipateCode(pollId, code.getValue());
44+
}
45+
46+
public Vote save(Vote vote) {
47+
try {
48+
PollEntity pollEntity = pollRepository.getById(vote.getPollId());
49+
VoteEntity voteEntity = new VoteEntity(vote, pollEntity);
50+
return voteRepository.save(voteEntity)
51+
.toDomain();
52+
} catch (DataIntegrityViolationException exception) {
53+
if (errorDecoder.isUniqueConstraintViolation(exception)) {
54+
throw new DTClientErrorException(ClientErrorCode.ALREADY_VOTED_PARTICIPANT);
55+
}
56+
throw exception;
57+
}
58+
}
3159
}

src/main/java/com/debatetimer/domainrepository/poll/CustomizeTableDomainRepository.java renamed to src/main/java/com/debatetimer/domainrepository/table/CustomizeTableDomainRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.debatetimer.domainrepository.poll;
1+
package com.debatetimer.domainrepository.table;
22

33
import com.debatetimer.domain.customize.CustomizeTable;
44
import com.debatetimer.domain.member.Member;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.debatetimer.dto.poll.request;
2+
3+
import com.debatetimer.domain.poll.VoteTeam;
4+
import jakarta.validation.constraints.NotBlank;
5+
import jakarta.validation.constraints.NotNull;
6+
7+
public record VoteRequest(
8+
@NotBlank String name,
9+
@NotBlank String participateCode,
10+
@NotNull VoteTeam team
11+
) {
12+
13+
}

0 commit comments

Comments
 (0)