-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/#29 대회 정렬 기능 개발 #71
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
base: develop
Are you sure you want to change the base?
The head ref may contain hidden characters: "Feature/#29-\uB300\uD68C_\uC815\uB82C_\uAE30\uB2A5_\uAC1C\uBC1C"
Changes from all commits
076b023
ee18415
70b94c0
fbcb766
31d4c10
fceca52
6577719
53c15ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,32 +1,48 @@ | ||
| package com.opus.opus.modules.contest.application; | ||
|
|
||
|
|
||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.*; | ||
| import static com.opus.opus.modules.contest.domain.SortType.CUSTOM; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.ALREADY_CURRENT_CONTEST; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.ALREADY_NOT_CURRENT_CONTEST; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.CANNOT_CHANGE_VOTES_DURING_VOTING_PERIOD; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.CURRENT_CONTEST_LIMIT_EXCEEDED; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.DUPLICATE_ITEM_ORDER_IN_SORT_REQUEST; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.DUPLICATE_TEAM_ID_IN_SORT_REQUEST; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.INVALID_CONTEST_SORT_CUSTOM_REQUEST; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.NOT_EXIST_TEAM_IN_CONTEST; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.ONLY_CUSTOM_MODE_CAN_CHANGE; | ||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.VOTE_END_PRECEDE_VOTE_START; | ||
| import static com.opus.opus.modules.file.domain.FileImageType.BANNER; | ||
| import static com.opus.opus.modules.file.domain.ReferenceDomainType.CONTEST; | ||
| import static com.opus.opus.modules.file.exception.FileExceptionType.NOT_WEBP_CONVERTED; | ||
| import static com.opus.opus.modules.team.exception.TeamExceptionType.INVALID_ITEM_ORDER; | ||
| import static java.util.function.Function.identity; | ||
| import static java.util.stream.Collectors.toMap; | ||
|
|
||
| import com.opus.opus.global.util.FileStorageUtil; | ||
| import com.opus.opus.modules.contest.application.convenience.ContestCategoryConvenience; | ||
| import com.opus.opus.modules.contest.application.convenience.ContestConvenience; | ||
| import com.opus.opus.modules.contest.application.convenience.ContestSortConvenience; | ||
| import com.opus.opus.modules.contest.application.dto.request.ContestRequest; | ||
| import com.opus.opus.modules.contest.application.dto.request.ContestSortCustomRequest; | ||
| import com.opus.opus.modules.contest.application.dto.request.ContestSortRequest; | ||
| import com.opus.opus.modules.contest.application.dto.request.VoteUpdateRequest; | ||
| import com.opus.opus.modules.contest.application.dto.response.ContestCurrentToggleResponse; | ||
| import com.opus.opus.modules.contest.application.dto.response.ContestResponse; | ||
| import com.opus.opus.modules.contest.application.dto.response.VotePeriodResponse; | ||
| import com.opus.opus.modules.contest.domain.Contest; | ||
| import com.opus.opus.modules.contest.domain.ContestCategory; | ||
| import com.opus.opus.modules.contest.domain.ContestSort; | ||
| import com.opus.opus.modules.contest.domain.dao.ContestRepository; | ||
| import com.opus.opus.modules.contest.domain.dao.ContestSortRepository; | ||
| import com.opus.opus.modules.contest.exception.ContestException; | ||
| import com.opus.opus.modules.contest.exception.ContestExceptionType; | ||
| import com.opus.opus.modules.file.domain.File; | ||
| import com.opus.opus.modules.file.domain.dao.FileRepository; | ||
| import com.opus.opus.modules.file.exception.FileException; | ||
| import com.opus.opus.modules.team.application.convenience.TeamConvenience; | ||
| import com.opus.opus.modules.team.domain.Team; | ||
| import com.opus.opus.modules.team.exception.TeamException; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
@@ -40,10 +56,12 @@ public class ContestCommandService { | |
| private static final int MAX_CURRENT_CONTEST_COUNT = 2; | ||
|
|
||
| private final ContestRepository contestRepository; | ||
| private final ContestSortRepository contestSortRepository; | ||
| private final FileRepository fileRepository; | ||
|
|
||
| private final ContestConvenience contestConvenience; | ||
| private final ContestCategoryConvenience contestCategoryConvenience; | ||
| private final ContestSortConvenience contestSortConvenience; | ||
| private final TeamConvenience teamConvenience; | ||
|
|
||
| private final FileStorageUtil fileStorageUtil; | ||
|
|
@@ -76,6 +94,10 @@ public ContestResponse createContest(final ContestRequest request) { | |
| .build(); | ||
| contestRepository.save(contest); | ||
|
|
||
| contestSortRepository.save(ContestSort.builder() | ||
| .contest(contest) | ||
| .build()); | ||
|
|
||
| return ContestResponse.from(contest, contestCategory.getCategoryName()); | ||
| } | ||
|
|
||
|
|
@@ -127,6 +149,28 @@ public void updateMaxVotesLimit(final Long contestId, final Integer maxVotesLimi | |
| contest.updateMaxVotesLimit(maxVotesLimit); | ||
| } | ||
|
|
||
| public void updateContestSort(final Long contestId, final ContestSortRequest request) { | ||
| contestConvenience.validateExistContest(contestId); | ||
| final ContestSort contestSort = contestSortConvenience.getValidateExistContestSort(contestId); | ||
|
|
||
| contestSort.updateMode(request.mode()); | ||
| } | ||
|
|
||
| //todo: 팀 생성 시 itemOrder 추가 | ||
| public void updateContestSortCustom(final Long contestId, final List<ContestSortCustomRequest> requests) { | ||
| final Contest contest = contestConvenience.getValidateExistContestForUpdate(contestId); | ||
| final ContestSort contestSort = contestSortConvenience.getValidateExistContestSort(contest.getId()); | ||
| checkCustomSort(contestSort); | ||
| validateDuplicateTeamIds(requests); | ||
|
|
||
| final List<Team> teams = teamConvenience.getTeamsOfContest(contestId); | ||
| validateRequestSizeMatchesTeams(requests, teams); | ||
| validateItemOrderRange(requests, teams.size()); | ||
| validateDuplicateItemOrders(requests); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분도 DB 조회 전에 검증 가능할 거 같은데 |
||
|
|
||
| applyCustomSortToTeams(requests, teams); | ||
| } | ||
|
|
||
| private void validateNotInVotingPeriod(final Contest contest) { | ||
| if (contest.isVotingPeriod()) { | ||
| throw new ContestException(CANNOT_CHANGE_VOTES_DURING_VOTING_PERIOD); | ||
|
|
@@ -140,7 +184,7 @@ private void checkWebpConverted(File existingFile) { | |
| } | ||
|
|
||
| private void validateSameCurrentRequest(final Boolean currentValue, final Boolean requestValue) { | ||
| if (currentValue == requestValue) { | ||
| if (currentValue.equals(requestValue)) { | ||
| throw new ContestException(currentValue ? ALREADY_CURRENT_CONTEST : ALREADY_NOT_CURRENT_CONTEST); | ||
| } | ||
| } | ||
|
|
@@ -150,4 +194,51 @@ private void validateCurrentContestLimit(final long currentCount) { | |
| throw new ContestException(CURRENT_CONTEST_LIMIT_EXCEEDED); | ||
| } | ||
| } | ||
|
|
||
| private void validateItemOrderRange(final List<ContestSortCustomRequest> requests, final int teamCount) { | ||
| for (ContestSortCustomRequest r : requests) { | ||
| final int order = r.itemOrder(); | ||
| if (order < 1 || order > teamCount) { | ||
| throw new TeamException(INVALID_ITEM_ORDER); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Contest 관련 로직에서 TeamException을 던지는게 조금 어색한 거 같습니다! |
||
| } | ||
| } | ||
| } | ||
|
|
||
| private void checkCustomSort(final ContestSort contestSort) { | ||
| if (contestSort.getMode() != CUSTOM) { | ||
| throw new ContestException(ONLY_CUSTOM_MODE_CAN_CHANGE); | ||
| } | ||
| } | ||
|
|
||
| private void validateRequestSizeMatchesTeams(final List<ContestSortCustomRequest> requests, | ||
| final List<Team> teams) { | ||
| if (requests.size() != teams.size()) { | ||
| throw new ContestException(INVALID_CONTEST_SORT_CUSTOM_REQUEST); | ||
| } | ||
| } | ||
|
|
||
| private void validateDuplicateTeamIds(final List<ContestSortCustomRequest> requests) { | ||
| if (requests.stream().map(ContestSortCustomRequest::teamId).distinct().count() != requests.size()) { | ||
| throw new ContestException(DUPLICATE_TEAM_ID_IN_SORT_REQUEST); | ||
| } | ||
| } | ||
|
|
||
| private void validateDuplicateItemOrders(final List<ContestSortCustomRequest> requests) { | ||
| if (requests.stream().map(ContestSortCustomRequest::itemOrder).distinct().count() != requests.size()) { | ||
| throw new ContestException(DUPLICATE_ITEM_ORDER_IN_SORT_REQUEST); | ||
| } | ||
| } | ||
|
|
||
| private void applyCustomSortToTeams(final List<ContestSortCustomRequest> requests, final List<Team> teams) { | ||
| final Map<Long, Team> teamMap = teams.stream() | ||
| .collect(toMap(Team::getId, identity())); | ||
|
|
||
| for (ContestSortCustomRequest r : requests) { | ||
| final Team team = teamMap.get(r.teamId()); | ||
| if (team == null) { | ||
| throw new ContestException(NOT_EXIST_TEAM_IN_CONTEST); | ||
| } | ||
| team.updateItemOrder(r.itemOrder()); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.opus.opus.modules.contest.application.convenience; | ||
|
|
||
| import static com.opus.opus.modules.contest.exception.ContestExceptionType.NOT_FOUND_CONTEST_SORT; | ||
|
|
||
| import com.opus.opus.modules.contest.domain.ContestSort; | ||
| import com.opus.opus.modules.contest.domain.dao.ContestSortRepository; | ||
| import com.opus.opus.modules.contest.exception.ContestException; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| @Transactional(readOnly = true) | ||
| public class ContestSortConvenience { | ||
|
|
||
| private final ContestSortRepository contestSortRepository; | ||
|
|
||
| public ContestSort getValidateExistContestSort(final Long contestId) { | ||
| return contestSortRepository.findByContestId(contestId) | ||
| .orElseThrow(() -> new ContestException(NOT_FOUND_CONTEST_SORT)); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updateContestSortCustom의 request body는List타입인데 파라미터에@Valid가 없어서(현재는List<@Valid ...>만 사용) Bean Validation이 실행되지 않을 수 있습니다. Spring MVC에서@RequestBody검증을 보장하려면 파라미터 자체에@Valid(또는@Validated)를 추가해 요소의 @NotNull 등이 실제로 검증되도록 해주세요.