Skip to content

Commit

Permalink
Merge branch 'dev' into 370-feature-토너먼트-알림-추가하기
Browse files Browse the repository at this point in the history
  • Loading branch information
Newsujin authored Dec 21, 2023
2 parents 7686e71 + 1f587c0 commit cbe6850
Show file tree
Hide file tree
Showing 23 changed files with 263 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.gg.server.domain.game.data.Game;
import com.gg.server.domain.game.dto.GameTeamUser;
import com.gg.server.domain.game.type.Mode;
import com.gg.server.domain.game.type.StatusType;
import com.gg.server.domain.season.data.Season;
import java.util.Optional;
Expand All @@ -17,6 +18,10 @@ public interface GameAdminRepository extends JpaRepository<Game, Long> {

Page<Game> findBySeason(Pageable pageable, Season season);

Page<Game> findBySeasonAndModeIn(Pageable pageable, Season season, List<Mode> modes);

Page<Game> findAllByModeIn(Pageable pageable, List<Mode> modes);

@Query(value = "select t1.gameId, t1.startTime, t1.endTime, t1.status, t1.mode, " +
"t1.teamId t1TeamId, t1.intraId t1IntraId, t1.win t1IsWin, t1.score t1Score, t1.image t1Image, t1.total_exp t1Exp, t1.wins t1Wins, t1.losses t1Losses, " +
"t2.teamId t2TeamId, t2.win t2IsWin, t2.score t2Score, t2.intraId t2IntraId, t2.wins t2Wins, t2.losses t2Losses, t2.image t2Image, t2.total_exp t2Exp " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.gg.server.domain.game.data.Game;
import com.gg.server.domain.game.dto.GameTeamUser;
import com.gg.server.domain.game.exception.GameNotExistException;
import com.gg.server.domain.game.type.Mode;
import com.gg.server.domain.game.type.StatusType;
import com.gg.server.domain.match.data.RedisMatchUserRepository;
import com.gg.server.domain.pchange.data.PChange;
Expand Down Expand Up @@ -47,16 +48,26 @@ public class GameAdminService {
private final TeamUserAdminRepository teamUserAdminRepository;
private final RedisMatchUserRepository redisMatchUserRepository;

/**
* <p>토너먼트 게임을 제외한 일반, 랭크 게임들을 찾아서 반환해준다.</p>
* @param pageable
* @return
*/
@Transactional(readOnly = true)
public GameLogListAdminResponseDto findAllGamesByAdmin(Pageable pageable) {
Page<Game> gamePage = gameAdminRepository.findAll(pageable); //모든 게임 정보 가져오기
Page<Game> gamePage = gameAdminRepository.findAllByModeIn(pageable, List.of(Mode.NORMAL, Mode.RANK));
return new GameLogListAdminResponseDto(getGameLogList(gamePage.getContent().stream().map(Game::getId).collect(Collectors.toList())), gamePage.getTotalPages());
}

/**
* <p>토너먼트 게임을 제외한 해당 시즌의 일반, 랭크 게임들을 찾아서 반환해준다.</p>
* @param pageable
* @return
*/
@Transactional(readOnly = true)
public GameLogListAdminResponseDto findGamesBySeasonId(Long seasonId, Pageable pageable){
Season season = seasonAdminRepository.findById(seasonId).orElseThrow(()-> new SeasonNotFoundException());
Page<Game> games = gameAdminRepository.findBySeason(pageable, season); //시즌 id로 게임들 찾아오기
Season season = seasonAdminRepository.findById(seasonId).orElseThrow(SeasonNotFoundException::new);
Page<Game> games = gameAdminRepository.findBySeasonAndModeIn(pageable, season, List.of(Mode.NORMAL, Mode.RANK));
return new GameLogListAdminResponseDto(getGameLogList(games.getContent().stream().map(Game::getId).collect(Collectors.toList())), games.getTotalPages());
}

Expand All @@ -67,7 +78,7 @@ public List<GameLogAdminDto> getGameLogList(List<Long> gameIdList){
}

/**
* 특정 유저의 게임 목록 조회
* 특정 유저의 게임 목록 조회 (토너먼트 게임 제외)
* @param intraId 조회할 유저의 intraId
* @param pageable page size
* @return GameLogListAdminResponseDto
Expand All @@ -76,7 +87,7 @@ public List<GameLogAdminDto> getGameLogList(List<Long> gameIdList){
@Transactional(readOnly = true)
public GameLogListAdminResponseDto findGamesByIntraId(String intraId, Pageable pageable){
User user = userAdminRepository.findByIntraId(intraId).orElseThrow(UserNotFoundException::new);
List<PChange> pChangeList = pChangeRepository.findAllByUserId(user.getId());
List<PChange> pChangeList = pChangeRepository.findAllByUserIdGameModeIn(user.getId(), List.of(Mode.NORMAL, Mode.RANK));
List<Game> gameList = new ArrayList<>();

for(PChange pChange : pChangeList)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.gg.server.domain.game.data.Game;
import com.gg.server.domain.game.data.GameRepository;
import com.gg.server.domain.game.exception.ScoreNotInvalidException;
import com.gg.server.domain.game.service.GameService;
import com.gg.server.domain.game.type.StatusType;
import com.gg.server.domain.match.exception.SlotNotFoundException;
import com.gg.server.domain.slotmanagement.SlotManagement;
Expand All @@ -14,7 +15,6 @@
import com.gg.server.domain.match.type.TournamentMatchStatus;
import com.gg.server.domain.team.data.Team;
import com.gg.server.domain.team.data.TeamUser;
import com.gg.server.domain.team.data.TeamUserRepository;
import com.gg.server.domain.tournament.data.*;
import com.gg.server.domain.tournament.dto.TournamentUserListResponseDto;
import com.gg.server.domain.tournament.exception.TournamentConflictException;
Expand All @@ -26,13 +26,15 @@
import com.gg.server.domain.user.data.User;
import com.gg.server.domain.user.data.UserRepository;
import com.gg.server.domain.user.exception.UserNotFoundException;
import com.gg.server.global.config.ConstantConfig;
import com.gg.server.global.exception.ErrorCode;
import com.gg.server.global.exception.custom.InvalidParameterException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.gg.server.domain.match.type.TournamentMatchStatus.*;
Expand All @@ -47,8 +49,8 @@ public class TournamentAdminService {
private final TournamentGameRepository tournamentGameRepository;
private final SlotManagementRepository slotManagementRepository;
private final MatchTournamentService matchTournamentService;
private final NotiAdminService notiAdminService;
private final TeamUserRepository teamUserRepository;
private final ConstantConfig constantConfig;
private final GameService gameService;

/***
* 토너먼트 생성 Method
Expand All @@ -59,8 +61,7 @@ public class TournamentAdminService {
* @return 새로 생성된 tournament
*/
@Transactional
public Tournament createTournament(TournamentAdminCreateRequestDto tournamentAdminCreateRequestDto) {
checkTournamentTitle(tournamentAdminCreateRequestDto.getTitle());
public void createTournament(TournamentAdminCreateRequestDto tournamentAdminCreateRequestDto) {
checkValidTournamentTime(tournamentAdminCreateRequestDto.getStartTime(), tournamentAdminCreateRequestDto.getEndTime());
checkConflictedTournament(-1L, tournamentAdminCreateRequestDto.getStartTime(), tournamentAdminCreateRequestDto.getEndTime());
checkGameExistence(tournamentAdminCreateRequestDto.getStartTime(), tournamentAdminCreateRequestDto.getEndTime());
Expand All @@ -73,7 +74,7 @@ public Tournament createTournament(TournamentAdminCreateRequestDto tournamentAdm
.type(tournamentAdminCreateRequestDto.getType())
.status(TournamentStatus.BEFORE).build();
createTournamentGameList(tournament, 7);
return tournamentRepository.save(tournament);
tournamentRepository.save(tournament);
}

/**
Expand Down Expand Up @@ -214,7 +215,7 @@ private void checkValidTournamentTime(LocalDateTime startTime, LocalDateTime end
int interval = slotManagement.getGameInterval();

if (startTime.isAfter(endTime) || startTime.isEqual(endTime) ||
startTime.getDayOfMonth() - LocalDateTime.now().getDayOfMonth() < Tournament.ALLOWED_MINIMAL_START_DAYS ||
startTime.getDayOfMonth() - LocalDateTime.now().getDayOfMonth() < constantConfig.getAllowedMinimalStartDays()||
startTime.plusHours(Tournament.MINIMUM_TOURNAMENT_DURATION).isAfter(endTime) ||
startTime.getMinute() % interval != 0 || endTime.getMinute() % interval != 0) {
throw new TournamentUpdateException(ErrorCode.TOURNAMENT_INVALID_TIME);
Expand All @@ -239,16 +240,6 @@ private void checkConflictedTournament(Long targetTournamentId, LocalDateTime st
}
}

/***
* 토너먼트 제목 중복 체크
* @param tournamentTitle 요청 데이터에서 받아온 토너먼트 제목
* @throws TournamentConflictException 토너먼트의 제목이 겹칠 때
*/
private void checkTournamentTitle(String tournamentTitle) {
tournamentRepository.findByTitle(tournamentTitle)
.ifPresent(a -> {throw new TournamentConflictException(ErrorCode.TOURNAMENT_TITLE_CONFLICT);});
}

/**
* <p>타겟 시간 내에 게임이 존재하는지 체크</p>
* @param startTime 시작 시간
Expand Down Expand Up @@ -307,6 +298,11 @@ public void updateTournamentGame(Long tournamentId, TournamentGameUpdateRequestD
updateTeamScore(game, reqDto);
TournamentMatchStatus matchStatus = matchTournamentService.checkTournamentGame(game);
TournamentRound nextRound = tournamentGame.getTournamentRound().getNextRound();
List<TeamUser> teamUsers = new ArrayList<>();
for(Team team : game.getTeams()){
teamUsers.add(team.getTeamUsers().get(0));
}
gameService.savePChange(game, teamUsers, teamUsers.get(0).getUser().getId());
if (POSSIBLE.equals(matchStatus)) {
matchTournamentService.matchGames(tournament, nextRound);
String gameMatchingMessage = "토너먼트 게임이 매칭되었습니다! 경기 상대를 확인해주세요.";
Expand Down Expand Up @@ -346,9 +342,11 @@ private void updateTeamScore(Game game, TournamentGameUpdateRequestDto reqDto){
* @return 수정 가능 여부
*/
private boolean canUpdateScore(TournamentGame tournamentGame, TournamentGameUpdateRequestDto reqDto) {
if (reqDto.getNextTournamentGameId() == null &&
tournamentGame.getTournamentRound() == TournamentRound.THE_FINAL) {
return true;
if (tournamentGame.getGame().getStatus() == StatusType.BEFORE) {
return false;
}
if (reqDto.getNextTournamentGameId() == null){
return tournamentGame.getTournamentRound() == TournamentRound.THE_FINAL;
}
TournamentGame nextTournamentGame = tournamentGameRepository.findById(reqDto.getNextTournamentGameId())
.orElseThrow(TournamentGameNotFoundException::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ synchronized ResponseEntity<Void> createTournamentGameResult(@Valid @RequestBody
throw new InvalidParameterException("점수를 잘못 입력했습니다.", ErrorCode.VALID_FAILED);
}
gameService.createTournamentGameResult(reqDto, user.getId());
return new ResponseEntity<Void>(HttpStatus.CREATED);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping("/{gameId}/result/normal")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private void updatePchangeIsChecked(Game game, Long loginUserId) {
});
}

private void savePChange(Game game, List<TeamUser> teamUsers, Long loginUserId) {
public void savePChange(Game game, List<TeamUser> teamUsers, Long loginUserId) {
Long team1UserId = teamUsers.get(0).getUser().getId();
Long team2UserId = teamUsers.get(1).getUser().getId();
pChangeService.addPChange(game, teamUsers.get(0).getUser(),
Expand Down Expand Up @@ -293,6 +293,7 @@ private void updateTournamentGameScore(Game game, TournamentResultReqDto scoreDt
setTeamScore(myTeam, scoreDto.getMyTeamScore(), scoreDto.getMyTeamScore() > scoreDto.getEnemyTeamScore());
setTeamScore(enemyTeam, scoreDto.getEnemyTeamScore(), scoreDto.getMyTeamScore() < scoreDto.getEnemyTeamScore());
expUpdates(game, teams);
savePChange(game, teams, userId);
} else {
// score 가 이미 입력됨
throw new ScoreAlreadyEnteredException(ErrorCode.SCORE_ALREADY_ENTERED.getMessage(), ErrorCode.SCORE_ALREADY_ENTERED);
Expand Down
46 changes: 27 additions & 19 deletions src/main/java/com/gg/server/domain/match/service/MatchService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.gg.server.domain.game.data.Game;
import com.gg.server.domain.game.data.GameRepository;
import com.gg.server.domain.game.exception.GameAlreadyExistException;
import com.gg.server.domain.game.type.Mode;
import com.gg.server.domain.game.type.StatusType;
import com.gg.server.domain.match.data.RedisMatchTime;
import com.gg.server.domain.match.data.RedisMatchTimeRepository;
Expand All @@ -21,6 +22,7 @@
import com.gg.server.domain.rank.redis.RedisKeyManager;
import com.gg.server.domain.season.data.Season;
import com.gg.server.domain.season.service.SeasonFindService;
import com.gg.server.domain.slotmanagement.data.SlotManagementRepository;
import com.gg.server.domain.tournament.data.Tournament;
import com.gg.server.domain.tournament.data.TournamentRepository;
import com.gg.server.domain.tournament.exception.TournamentConflictException;
Expand All @@ -29,6 +31,8 @@
import com.gg.server.domain.user.data.UserRepository;
import com.gg.server.domain.user.dto.UserDto;
import com.gg.server.domain.user.exception.UserNotFoundException;
import com.gg.server.global.exception.ErrorCode;
import com.gg.server.global.exception.custom.BusinessException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
Expand All @@ -50,6 +54,7 @@ public class MatchService {
private final GameUpdateService gameUpdateService;
private final UserRepository userRepository;
private final TournamentRepository tournamentRepository;
private final SlotManagementRepository slotManagementRepository;

/**
* 1) 매칭 가능한 유저 있을 경우 : 게임 생성
Expand Down Expand Up @@ -79,8 +84,6 @@ public synchronized void makeMatch(UserDto userDto, Option option, LocalDateTime
* 1) 매칭되어 게임 생성된 후 : 게임 삭제하고 알림 전송, 취소한 유저 패널티 부과
* 복귀 유저는 매칭 가능한 상대 존재하면 다시 매칭해주고 아니면 취소 알림 보내고 큐에 등록 시킴
* 2) 매칭 전 : 큐에서 유저 삭제
* */
/**
* game 매칭된 user 이외에 다른 user가 취소할 경우, 에러 발생
*/
@Transactional
Expand All @@ -91,14 +94,17 @@ public synchronized void cancelMatch(UserDto userDto, LocalDateTime startTime) {
if (enemyTeam.size() > 1) {
throw new SlotNotFoundException();
}
if (game.get().getMode().equals(Mode.TOURNAMENT)) {
throw new BusinessException(ErrorCode.TOURNAMENT_GAME_CAN_NOT_CANCELED);
}
cancelGame(userDto, startTime, game.get(), enemyTeam);
}else {
} else {
deleteUserFromQueue(userDto, startTime);
};
}
}

private void cancelGame(UserDto userDto, LocalDateTime startTime, Game game, List<User> enemyTeam) {
/**취소한 유저 큐에서 삭제 후 패널티 부과*/
/*취소한 유저 큐에서 삭제 후 패널티 부과*/
Long recoveredUserId = enemyTeam.get(0).getId();
List<RedisMatchUser> allMatchUsers = redisMatchTimeRepository.getAllMatchUsers(startTime);
RedisMatchUser penaltyUser = allMatchUsers.stream()
Expand All @@ -111,7 +117,7 @@ private void cancelGame(UserDto userDto, LocalDateTime startTime, Game game, Lis
.orElseThrow(UserNotFoundException::new);
redisMatchTimeRepository.deleteMatchUser(startTime, penaltyUser);
penaltyService.givePenalty(userDto, 30);
/**취소 당한 유저 매칭 상대 찾고 있으면 다시 게임 생성 아니면 취소 알림*/
/*취소 당한 유저 매칭 상대 찾고 있으면 다시 게임 생성 아니면 취소 알림*/
Season season = seasonFindService.findCurrentSeason(startTime);
MatchCalculator matchCalculator = new MatchCalculator(season.getPppGap(), recoveredUser);
List<RedisMatchUser> targetPlayers = allMatchUsers.stream()
Expand Down Expand Up @@ -176,7 +182,7 @@ private void cancelEnrolledSlots(List<RedisMatchUser> players, LocalDateTime tar
.stream()
.filter(ele -> !ele.getStartTime().equals(targetTIme))
.collect(Collectors.toSet());
matchTimes.stream().forEach(ele -> redisMatchTimeRepository.deleteMatchUser(ele.getStartTime(), player));
matchTimes.forEach(ele -> redisMatchTimeRepository.deleteMatchUser(ele.getStartTime(), player));
redisMatchUserRepository.deleteMatchUser(player.getUserId());
}
}
Expand All @@ -197,24 +203,26 @@ private void deleteUserFromQueue(UserDto userDto, LocalDateTime startTime) {

/**
* LIVE, BEFORE 상태인 토너먼트와 진행 시간이 겹치지 않으면 true, 겹치면 false
* @param time 현재 시간
* @param startTime 현재 시간
* @return 종료되지 않은 토너먼트 있으면 true, 없으면 false
* @throws SlotNotFoundException 현재 시간에 해당하는 슬롯이 없을 경우
*/
private boolean isExistTournamentNotEnded(LocalDateTime time) {
private boolean isExistTournamentNotEnded(LocalDateTime startTime) {
List<Tournament> tournamentList = tournamentRepository.findAllByStatusIsNot(TournamentStatus.END);
if (tournamentList.isEmpty()) {
return false;
}
int gameInterval = slotManagementRepository.findCurrent(startTime)
.orElseThrow(SlotNotFoundException::new)
.getGameInterval();
LocalDateTime endTime = startTime.plusMinutes(gameInterval);
for (Tournament tournament : tournamentList) {
if (time.isAfter(tournament.getStartTime()) &&
time.isBefore(tournament.getEndTime())) {
return false;
if (startTime.isAfter(tournament.getStartTime()) && startTime.isBefore(tournament.getEndTime()) ||
endTime.isAfter(tournament.getStartTime()) && endTime.isBefore(tournament.getEndTime())) {
return true;
}
if (time.isEqual(tournament.getStartTime()) ||
time.isEqual(tournament.getEndTime())) {
return false;
if (startTime.isEqual(tournament.getStartTime()) || endTime.isEqual(tournament.getEndTime()) ||
endTime.isEqual(tournament.getStartTime()) || startTime.isEqual(tournament.getEndTime())) {
return true;
}
}
return true;
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ private void closeTournament(Tournament tournament, Game finalGame) {
User winner = getWinningTeam(finalGame)
.getTeamUsers().get(0).getUser();
tournament.updateStatus(TournamentStatus.END);
tournament.updateEndTime(finalGame.getEndTime());
tournament.updateWinner(winner);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ public void addTournamentSlots(List<Tournament> tournaments) {
LocalDateTime startTime = tournament.getStartTime();
int startTimeMinute = startTime.getMinute();
startTimeMinute = startTimeMinute - (startTimeMinute % interval);
startTime = startTime.withMinute(startTimeMinute);
LocalDateTime endTime = tournament.getEndTime();
int endTimeMinute = endTime.getMinute();
endTimeMinute = endTimeMinute + (interval - (endTimeMinute % interval));
endTime = endTime.withMinute(endTimeMinute);
for (LocalDateTime time = startTime; time.isBefore(endTime); time = time.plusMinutes(interval)) {
slots.put(time, new SlotStatusDto(time, SlotStatus.CLOSE, interval));
}
Expand Down
Loading

0 comments on commit cbe6850

Please sign in to comment.