Skip to content
Merged
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
4 changes: 4 additions & 0 deletions src/main/java/com/codzilla/backend/MatchRoom/Match.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public enum Status {

boolean ratingApplied = false;

Integer firstUserRating;

Integer secondUserRating;

@JdbcTypeCode(SqlTypes.JSON)
@Column(name = "options", columnDefinition = "jsonb")
Map<Category, String> options;
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/codzilla/backend/MatchRoom/MatchController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.codzilla.backend.MatchRoom;

import com.codzilla.backend.MatchRoom.dto.MatchHistoryEntryDTO;
import com.codzilla.backend.User.User;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/match")
@RequiredArgsConstructor
public class MatchController {

private final MatchService matchService;

@GetMapping("/history")
public ResponseEntity<List<MatchHistoryEntryDTO>> getMatchHistory(@AuthenticationPrincipal User user) {
return ResponseEntity.ok(matchService.getMatchHistory(user.getId()));
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/codzilla/backend/MatchRoom/MatchRepository.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package com.codzilla.backend.MatchRoom;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.UUID;

public interface MatchRepository extends JpaRepository<Match, UUID> {

@Query("""
SELECT m FROM Match m
WHERE m.status = com.codzilla.backend.MatchRoom.Match.Status.FINISHED
AND (m.firstUserId = :userId OR m.secondUserId = :userId)
ORDER BY m.finishedAt DESC
""")
List<Match> findFinishedByUser(@Param("userId") UUID userId);
}
28 changes: 28 additions & 0 deletions src/main/java/com/codzilla/backend/MatchRoom/MatchService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.codzilla.backend.MatchRoom;

import com.codzilla.backend.MatchRoom.dto.MatchHistoryEntryDTO;
import com.codzilla.backend.Rating.MatchFinishedEvent;
import com.codzilla.backend.PreMatch.DraftSession.DraftSession;
import com.codzilla.backend.PreMatch.DraftSession.DraftSessionService;
Expand All @@ -10,6 +11,8 @@
import com.codzilla.backend.judge.problem.Problem;
import com.codzilla.backend.judge.problem.ProblemRepository;
import com.codzilla.backend.judge.problem.ProblemService;
import com.codzilla.backend.User.User;
import com.codzilla.backend.User.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;
Expand All @@ -18,6 +21,7 @@
import org.springframework.context.ApplicationEventPublisher;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID;

Expand All @@ -33,6 +37,7 @@ public class MatchService {
private final ProblemRepository problemRepository;
private final SqlServiceClient sqlServiceClient;
private final ProblemService problemService;
private final UserRepository userRepository;
private final ApplicationEventPublisher eventPublisher;

public UUID startMatch(UUID firstUserId, UUID secondUserId) {
Expand Down Expand Up @@ -113,4 +118,27 @@ public Problem pickProblemOfOptions(Map<Category, String> options) {
public Match getMatchById(UUID matchId) {
return matchRepository.getReferenceById(matchId);
}

@Transactional(readOnly = true)
public List<MatchHistoryEntryDTO> getMatchHistory(UUID userId) {
return matchRepository.findFinishedByUser(userId).stream()
.map(match -> {
UUID opponentId = match.opponentOf(userId);
String opponentNickname = userRepository.findById(opponentId)
.map(User::getNickname)
.orElse("Неизвестный соперник");
boolean won = userId.equals(match.getWinnerId());
Integer rating = userId.equals(match.getFirstUserId())
? match.getFirstUserRating()
: match.getSecondUserRating();
return new MatchHistoryEntryDTO(
match.getId(),
opponentNickname,
won,
rating,
match.getFinishedAt()
);
})
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.codzilla.backend.MatchRoom.dto;

import java.time.Instant;
import java.util.UUID;

public record MatchHistoryEntryDTO(
UUID matchId,
String opponentNickname,
boolean won,
Integer rating,
Instant finishedAt
) {}
21 changes: 21 additions & 0 deletions src/main/java/com/codzilla/backend/Rating/RatingService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.codzilla.backend.Rating;

import com.codzilla.backend.MatchRoom.Match;
import com.codzilla.backend.MatchRoom.MatchRepository;
import com.codzilla.backend.PreMatch.events.MatchResultNotifyEvent;
import com.codzilla.backend.User.User;
import com.codzilla.backend.User.UserRepository;
Expand All @@ -20,6 +22,7 @@
public class RatingService {

private final UserRepository userRepository;
private final MatchRepository matchRepository;
private final ApplicationEventPublisher eventPublisher;
private final Glicko2 glicko2 = new Glicko2();

Expand Down Expand Up @@ -59,6 +62,8 @@ public void recalculate(UUID matchId, UUID winnerId, UUID loserId) {
userRepository.save(winner);
userRepository.save(loser);

saveRatingSnapshot(matchId, winnerId, winner.getRating(), loser.getRating());

log.info("Rating updated: winner {} -> {}, loser {} -> {}",
winnerId, winner.getRating(), loserId, loser.getRating());

Expand All @@ -75,6 +80,22 @@ public void recalculate(UUID matchId, UUID winnerId, UUID loserId) {
));
}

private void saveRatingSnapshot(UUID matchId, UUID winnerId, int winnerRating, int loserRating) {
Match match = matchRepository.findById(matchId).orElse(null);
if (match == null) {
log.warn("saveRatingSnapshot: match {} not found", matchId);
return;
}
if (winnerId.equals(match.getFirstUserId())) {
match.setFirstUserRating(winnerRating);
match.setSecondUserRating(loserRating);
} else {
match.setFirstUserRating(loserRating);
match.setSecondUserRating(winnerRating);
}
matchRepository.save(match);
}

private void applyResult(User user, Glicko2.Result r, Instant now) {
user.setRating((int) Math.round(r.rating()));
user.setRatingDeviation(r.rd());
Expand Down
10 changes: 7 additions & 3 deletions src/test/java/com/codzilla/backend/Rating/RatingServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.codzilla.backend.Rating;

import com.codzilla.backend.MatchRoom.MatchRepository;
import com.codzilla.backend.PreMatch.events.MatchResultNotifyEvent;
import com.codzilla.backend.User.User;
import com.codzilla.backend.User.UserRepository;
Expand All @@ -22,6 +23,9 @@ class RatingServiceTest {
@Mock
private UserRepository userRepository;

@Mock
private MatchRepository matchRepository;

@Mock
private ApplicationEventPublisher eventPublisher;

Expand All @@ -38,7 +42,7 @@ private User newUser(UUID id, int rating) {

@Test
void matchFinishedEvent_winnerGains_loserLoses() {
RatingService service = new RatingService(userRepository, eventPublisher);
RatingService service = new RatingService(userRepository, matchRepository, eventPublisher);

UUID winnerId = UUID.randomUUID();
UUID loserId = UUID.randomUUID();
Expand Down Expand Up @@ -67,7 +71,7 @@ void matchFinishedEvent_winnerGains_loserLoses() {

@Test
void matchFinishedEvent_publishesNotifyEventWithEmailsAndDeltas() {
RatingService service = new RatingService(userRepository, eventPublisher);
RatingService service = new RatingService(userRepository, matchRepository, eventPublisher);

UUID winnerId = UUID.randomUUID();
UUID loserId = UUID.randomUUID();
Expand Down Expand Up @@ -96,7 +100,7 @@ void matchFinishedEvent_publishesNotifyEventWithEmailsAndDeltas() {

@Test
void unknownUser_skipsWithoutSaving() {
RatingService service = new RatingService(userRepository, eventPublisher);
RatingService service = new RatingService(userRepository, matchRepository, eventPublisher);
UUID winnerId = UUID.randomUUID();
UUID loserId = UUID.randomUUID();

Expand Down
Loading