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) {
|
public static Date alignToCurrentHour(Date date) {
|
||||||
return Date.from(Instant.ofEpochMilli(date.getTime()).truncatedTo(ChronoUnit.HOURS));
|
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.exception.impl.BadRequestException;
|
||||||
import cc.fascinated.platform.Platform;
|
import cc.fascinated.platform.Platform;
|
||||||
import cc.fascinated.services.ScoreService;
|
import cc.fascinated.services.ScoreService;
|
||||||
|
import cc.fascinated.services.UserService;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -22,9 +23,16 @@ public class ScoresController {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final ScoreService scoreService;
|
private final ScoreService scoreService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user service to use
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ScoresController(@NonNull ScoreService scoreService) {
|
public ScoresController(@NonNull ScoreService scoreService, @NonNull UserService userService) {
|
||||||
this.scoreService = scoreService;
|
this.scoreService = scoreService;
|
||||||
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,4 +62,40 @@ public class ScoresController {
|
|||||||
public ResponseEntity<?> getScoresCount(@PathVariable String platform) {
|
public ResponseEntity<?> getScoresCount(@PathVariable String platform) {
|
||||||
return ResponseEntity.ok(scoreService.getTotalScores(Platform.Platforms.getPlatform(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.mongodb.repository.MongoRepository;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,6 +40,21 @@ public interface ScoreRepository extends MongoRepository<Score, String> {
|
|||||||
})
|
})
|
||||||
List<Score> getRankedScores(@NonNull Platform.Platforms platform);
|
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.
|
* 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.DateUtils;
|
||||||
import cc.fascinated.common.EnumUtils;
|
import cc.fascinated.common.EnumUtils;
|
||||||
import cc.fascinated.common.MathUtils;
|
import cc.fascinated.common.MathUtils;
|
||||||
|
import cc.fascinated.common.Tuple;
|
||||||
import cc.fascinated.model.leaderboard.Leaderboard;
|
import cc.fascinated.model.leaderboard.Leaderboard;
|
||||||
import cc.fascinated.model.score.Score;
|
import cc.fascinated.model.score.Score;
|
||||||
import cc.fascinated.model.score.TotalScoresResponse;
|
import cc.fascinated.model.score.TotalScoresResponse;
|
||||||
@ -146,23 +147,15 @@ public class ScoreService {
|
|||||||
ScoreSaberScoreToken score = token.getScore();
|
ScoreSaberScoreToken score = token.getScore();
|
||||||
User user = userService.getUser(score.getLeaderboardPlayerInfo().getId());
|
User user = userService.getUser(score.getLeaderboardPlayerInfo().getId());
|
||||||
|
|
||||||
Score previousScore = this.scoreRepository.findScore(Platform.Platforms.SCORESABER, user.getSteamId(), leaderboard.getId());
|
Tuple<Score, List<Score>> previousScoreTuple = this.getPreviousScore(Platform.Platforms.SCORESABER, user, leaderboard.getId());
|
||||||
List<Score> previousScores = new ArrayList<>();
|
List<Score> previousScores = previousScoreTuple.getRight();
|
||||||
if (previousScore != null) { // There is a previous score
|
Score previousScore = previousScoreTuple.getLeft();
|
||||||
if (previousScore.getPreviousScores() != null) {
|
boolean previousScoreExists = previousScore != null && (previousScores != null && !previousScores.isEmpty());
|
||||||
previousScores.addAll(previousScore.getPreviousScores()); // Add the previous scores
|
if (previousScoreExists) { // There is a previous score
|
||||||
}
|
|
||||||
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());
|
|
||||||
|
|
||||||
// Delete the previous score
|
// Delete the previous score
|
||||||
scoreRepository.delete(previousScore);
|
scoreRepository.delete(previousScore);
|
||||||
}
|
} else {
|
||||||
// There are no previous scores, so set it to null to save data
|
// There are no previous scores, so set it to null to save data
|
||||||
if (previousScores.isEmpty()) {
|
|
||||||
previousScores = null;
|
previousScores = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,8 +186,46 @@ public class ScoreService {
|
|||||||
score.getMaxCombo()
|
score.getMaxCombo()
|
||||||
);
|
);
|
||||||
scoreRepository.save(scoreSaberScore);
|
scoreRepository.save(scoreSaberScore);
|
||||||
this.logScore(Platform.Platforms.SCORESABER, scoreSaberScore, user,
|
this.logScore(Platform.Platforms.SCORESABER, Leaderboard.getFromScoreSaberToken(leaderboard), scoreSaberScore, user,
|
||||||
previousScore != null && previousScore.getScore() < scoreSaberScore.getScore());
|
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 score The score to log.
|
||||||
* @param user The user who set the score.
|
* @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);
|
String platformName = EnumUtils.getEnumName(platform);
|
||||||
boolean isRanked = score.getPp() != 0;
|
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,
|
platformName,
|
||||||
improvedScore ? "Improved " : "",
|
improvedScore ? "Improved " : "",
|
||||||
isRanked ? " Ranked" : "",
|
isRanked ? " Ranked" : "",
|
||||||
@ -216,7 +248,9 @@ public class ScoreService {
|
|||||||
platformName.toLowerCase(), score.getPlatformScoreId(),
|
platformName.toLowerCase(), score.getPlatformScoreId(),
|
||||||
isRanked ? " pp: %s,".formatted(score.getPp()) : "",
|
isRanked ? " pp: %s,".formatted(score.getPp()) : "",
|
||||||
score.getLeaderboardId(),
|
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