api: add score history endpoints (per leaderboard and last 30 day improvements (all maps))
Some checks failed
Deploy API / docker (17, 3.8.5) (push) Failing after 47s
Some checks failed
Deploy API / docker (17, 3.8.5) (push) Failing after 47s
This commit is contained in:
parent
6fda81e81a
commit
199ee50534
@ -37,4 +37,14 @@ public class DateUtils {
|
||||
public static Date alignToCurrentHour(Date date) {
|
||||
return Date.from(Instant.ofEpochMilli(date.getTime()).truncatedTo(ChronoUnit.HOURS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date from an amount of days ago.
|
||||
*
|
||||
* @param days The amount to go back.
|
||||
* @return The date.
|
||||
*/
|
||||
public static Date getDaysAgo(int days) {
|
||||
return Date.from(Instant.now().minus(days, ChronoUnit.DAYS));
|
||||
}
|
||||
}
|
||||
|
21
API/src/main/java/cc/fascinated/common/Tuple.java
Normal file
21
API/src/main/java/cc/fascinated/common/Tuple.java
Normal file
@ -0,0 +1,21 @@
|
||||
package cc.fascinated.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class Tuple<L, R> {
|
||||
/**
|
||||
* The left value of the tuple.
|
||||
*/
|
||||
private final L left;
|
||||
|
||||
/**
|
||||
* The right value of the tuple.
|
||||
*/
|
||||
private final R right;
|
||||
}
|
@ -3,6 +3,7 @@ package cc.fascinated.controller;
|
||||
import cc.fascinated.exception.impl.BadRequestException;
|
||||
import cc.fascinated.platform.Platform;
|
||||
import cc.fascinated.services.ScoreService;
|
||||
import cc.fascinated.services.UserService;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -22,9 +23,16 @@ public class ScoresController {
|
||||
@NonNull
|
||||
private final ScoreService scoreService;
|
||||
|
||||
/**
|
||||
* The user service to use
|
||||
*/
|
||||
@NonNull
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public ScoresController(@NonNull ScoreService scoreService) {
|
||||
public ScoresController(@NonNull ScoreService scoreService, @NonNull UserService userService) {
|
||||
this.scoreService = scoreService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,4 +62,40 @@ public class ScoresController {
|
||||
public ResponseEntity<?> getScoresCount(@PathVariable String platform) {
|
||||
return ResponseEntity.ok(scoreService.getTotalScores(Platform.Platforms.getPlatform(platform)));
|
||||
}
|
||||
|
||||
/**
|
||||
* A GET mapping to retrieve the score
|
||||
* history for a leaderboard
|
||||
*
|
||||
* @param platform the platform to get the history from
|
||||
* @return the score history
|
||||
* @throws BadRequestException if there were no history found
|
||||
*/
|
||||
@ResponseBody
|
||||
@GetMapping(value = "/history/{platform}/{playerId}/{leaderboardId}")
|
||||
public ResponseEntity<?> getScoreHistory(@PathVariable String platform, @PathVariable String playerId, @PathVariable String leaderboardId) {
|
||||
return ResponseEntity.ok(scoreService.getPreviousScore(
|
||||
Platform.Platforms.getPlatform(platform),
|
||||
userService.getUser(playerId),
|
||||
leaderboardId
|
||||
).getRight());
|
||||
}
|
||||
|
||||
/**
|
||||
* A GET mapping to retrieve the score
|
||||
* history for a leaderboard
|
||||
*
|
||||
* @param platform the platform to get the history from
|
||||
* @return the score history
|
||||
* @throws BadRequestException if there were no history found
|
||||
*/
|
||||
@ResponseBody
|
||||
@GetMapping(value = "/history/{platform}/{playerId}")
|
||||
public ResponseEntity<?> getScoreHistory(@PathVariable String platform, @PathVariable String playerId) {
|
||||
return ResponseEntity.ok(scoreService.getImprovedScores(
|
||||
Platform.Platforms.getPlatform(platform),
|
||||
userService.getUser(playerId),
|
||||
30
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import org.springframework.data.mongodb.repository.Aggregation;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -39,6 +40,21 @@ public interface ScoreRepository extends MongoRepository<Score, String> {
|
||||
})
|
||||
List<Score> getRankedScores(@NonNull Platform.Platforms platform);
|
||||
|
||||
/**
|
||||
* Gets the improved scores from the platform.
|
||||
*
|
||||
* @param platform the platform to get the scores from
|
||||
* @param playerId the player id to get the scores from
|
||||
* @param after the date to get the scores after
|
||||
* @return the scores
|
||||
*/
|
||||
@Aggregation(pipeline = {
|
||||
"{ $match: { platform: ?0, playerId: ?1, timestamp: { $gt: ?2 } } }",
|
||||
"{ $match: { 'previousScores.0': { $exists: true } } }",
|
||||
"{ $sort: { pp: -1 } }"
|
||||
})
|
||||
List<Score> getImprovedScores(@NonNull Platform.Platforms platform, @NonNull String playerId, @NonNull Date after);
|
||||
|
||||
/**
|
||||
* Gets a score from a platform and leaderboard id.
|
||||
*
|
||||
|
@ -3,6 +3,7 @@ package cc.fascinated.services;
|
||||
import cc.fascinated.common.DateUtils;
|
||||
import cc.fascinated.common.EnumUtils;
|
||||
import cc.fascinated.common.MathUtils;
|
||||
import cc.fascinated.common.Tuple;
|
||||
import cc.fascinated.model.leaderboard.Leaderboard;
|
||||
import cc.fascinated.model.score.Score;
|
||||
import cc.fascinated.model.score.TotalScoresResponse;
|
||||
@ -146,23 +147,15 @@ public class ScoreService {
|
||||
ScoreSaberScoreToken score = token.getScore();
|
||||
User user = userService.getUser(score.getLeaderboardPlayerInfo().getId());
|
||||
|
||||
Score previousScore = this.scoreRepository.findScore(Platform.Platforms.SCORESABER, user.getSteamId(), leaderboard.getId());
|
||||
List<Score> previousScores = new ArrayList<>();
|
||||
if (previousScore != null) { // There is a previous score
|
||||
if (previousScore.getPreviousScores() != null) {
|
||||
previousScores.addAll(previousScore.getPreviousScores()); // Add the previous scores
|
||||
}
|
||||
previousScore.setPreviousScores(null); // Clear the previous scores
|
||||
previousScores.add(previousScore); // Add the previous score
|
||||
|
||||
// Sort previous scores by timestamp (newest -> oldest)
|
||||
previousScores.sort(Comparator.comparing(Score::getTimestamp).reversed());
|
||||
|
||||
Tuple<Score, List<Score>> previousScoreTuple = this.getPreviousScore(Platform.Platforms.SCORESABER, user, leaderboard.getId());
|
||||
List<Score> previousScores = previousScoreTuple.getRight();
|
||||
Score previousScore = previousScoreTuple.getLeft();
|
||||
boolean previousScoreExists = previousScore != null && (previousScores != null && !previousScores.isEmpty());
|
||||
if (previousScoreExists) { // There is a previous score
|
||||
// Delete the previous score
|
||||
scoreRepository.delete(previousScore);
|
||||
}
|
||||
} else {
|
||||
// There are no previous scores, so set it to null to save data
|
||||
if (previousScores.isEmpty()) {
|
||||
previousScores = null;
|
||||
}
|
||||
|
||||
@ -193,8 +186,46 @@ public class ScoreService {
|
||||
score.getMaxCombo()
|
||||
);
|
||||
scoreRepository.save(scoreSaberScore);
|
||||
this.logScore(Platform.Platforms.SCORESABER, scoreSaberScore, user,
|
||||
previousScore != null && previousScore.getScore() < scoreSaberScore.getScore());
|
||||
this.logScore(Platform.Platforms.SCORESABER, Leaderboard.getFromScoreSaberToken(leaderboard), scoreSaberScore, user,
|
||||
previousScoreExists && previousScore.getScore() < scoreSaberScore.getScore());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous score of a user.
|
||||
*
|
||||
* @param platform The platform to get the score from.
|
||||
* @param user The user to get the score from.
|
||||
* @param leaderboardId The leaderboard id to get the score from.
|
||||
* @return The previous score.
|
||||
*/
|
||||
public Tuple<Score, List<Score>> getPreviousScore(@NonNull Platform.Platforms platform, @NonNull User user, @NonNull String leaderboardId) {
|
||||
Score score = this.scoreRepository.findScore(platform, user.getSteamId(), leaderboardId);
|
||||
List<Score> previousScores = new ArrayList<>();
|
||||
if (score == null) { // There is a previous score
|
||||
return new Tuple<>(null, previousScores);
|
||||
}
|
||||
if (score.getPreviousScores() != null) {
|
||||
previousScores.addAll(score.getPreviousScores()); // Add the previous scores
|
||||
}
|
||||
score.setPreviousScores(null); // Clear the previous scores
|
||||
previousScores.add(score); // Add the previous score
|
||||
|
||||
// Sort previous scores by timestamp (newest -> oldest)
|
||||
previousScores.sort(Comparator.comparing(Score::getTimestamp).reversed());
|
||||
|
||||
return new Tuple<>(score, previousScores);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the improved scores of a user.
|
||||
*
|
||||
* @param platform The platform to get the scores from.
|
||||
* @param user The user to get the scores from.
|
||||
* @param days The amount of days in the past to get the scores from.
|
||||
* @return The improved scores.
|
||||
*/
|
||||
public List<Score> getImprovedScores(@NonNull Platform.Platforms platform, @NonNull User user, int days) {
|
||||
return scoreRepository.getImprovedScores(platform, user.getSteamId(), DateUtils.getDaysAgo(days));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,10 +235,11 @@ public class ScoreService {
|
||||
* @param score The score to log.
|
||||
* @param user The user who set the score.
|
||||
*/
|
||||
private void logScore(@NonNull Platform.Platforms platform, @NonNull Score score, @NonNull User user, boolean improvedScore) {
|
||||
private void logScore(@NonNull Platform.Platforms platform, @NonNull Leaderboard leaderboard, @NonNull Score score,
|
||||
@NonNull User user, boolean improvedScore) {
|
||||
String platformName = EnumUtils.getEnumName(platform);
|
||||
boolean isRanked = score.getPp() != 0;
|
||||
log.info("[{}] {}Tracked{} Score! id: {}, acc: {}%, {} score id: {},{} leaderboard: {}, player: {}",
|
||||
log.info("[{}] {}Tracked{} Score! id: {}, acc: {}%, {} score id: {},{} leaderboard: {}, difficulty: {}, player: {} ({})",
|
||||
platformName,
|
||||
improvedScore ? "Improved " : "",
|
||||
isRanked ? " Ranked" : "",
|
||||
@ -216,7 +248,9 @@ public class ScoreService {
|
||||
platformName.toLowerCase(), score.getPlatformScoreId(),
|
||||
isRanked ? " pp: %s,".formatted(score.getPp()) : "",
|
||||
score.getLeaderboardId(),
|
||||
user.getUsername() == null ? user.getSteamId() : user.getUsername()
|
||||
leaderboard.getDifficulty().getDifficulty(),
|
||||
user.getUsername() == null ? user.getSteamId() : user.getUsername(),
|
||||
user.getSteamId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user