Add leaderboard API endpoint
This commit is contained in:
parent
ce276c790a
commit
35f2448e00
@ -11,7 +11,12 @@ namespace GameDatabase.Entities
|
||||
public uint BestRate { get; set; }
|
||||
public CrownType BestCrown { get; set; }
|
||||
public ScoreRank BestScoreRank { get; set; }
|
||||
|
||||
public uint GoodCount { get; set; }
|
||||
public uint OkCount { get; set; }
|
||||
public uint MissCount { get; set; }
|
||||
public uint ComboCount { get; set; }
|
||||
public uint HitCount { get; set; }
|
||||
public uint DrumrollCount { get; set; }
|
||||
public virtual UserDatum? Ba { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace SharedProject.Models.Responses;
|
||||
|
||||
public class SongLeaderboardResponse
|
||||
{
|
||||
public List<SongLeaderboard> Leaderboard { get; set; } = new();
|
||||
}
|
@ -46,6 +46,5 @@ public class SongBestData
|
||||
public List<AiSectionBestData> AiSectionBestData { get; set; } = new();
|
||||
|
||||
public bool ShowAiData { get; set; }
|
||||
|
||||
public List<SongPlayDatumDto> RecentPlayData { get; set; } = new();
|
||||
}
|
27
SharedProject/Models/SongLeaderboard.cs
Normal file
27
SharedProject/Models/SongLeaderboard.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using SharedProject.Enums;
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class SongLeaderboard
|
||||
{
|
||||
public uint Rank { get; set; }
|
||||
|
||||
public uint Baid { get; set; }
|
||||
|
||||
public uint BestScore { get; set; }
|
||||
|
||||
public uint BestRate { get; set; }
|
||||
|
||||
public CrownType BestCrown { get; set; }
|
||||
|
||||
public ScoreRank BestScoreRank { get; set; }
|
||||
|
||||
public uint GoodCount { get; set; }
|
||||
public uint OkCount { get; set; }
|
||||
public uint MissCount { get; set; }
|
||||
public uint ComboCount { get; set; }
|
||||
public uint HitCount { get; set; }
|
||||
public uint DrumrollCount { get; set; }
|
||||
|
||||
public string? UserName { get; set; }
|
||||
}
|
43
TaikoLocalServer/Controllers/Api/SongLeaderboardData.cs
Normal file
43
TaikoLocalServer/Controllers/Api/SongLeaderboardData.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using SharedProject.Models;
|
||||
using SharedProject.Models.Responses;
|
||||
using TaikoLocalServer.Filters;
|
||||
using TaikoLocalServer.Settings;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
|
||||
public class SongLeaderboardData(ISongLeaderboardService songLeaderboardService,IAuthService authService, IOptions<AuthSettings> settings)
|
||||
: BaseController<SongLeaderboardData>
|
||||
{
|
||||
private readonly AuthSettings authSettings = settings.Value;
|
||||
|
||||
[HttpGet("{baid}/{songId}/{difficulty}")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
|
||||
public async Task<ActionResult<SongLeaderboardResponse>> GetSongLeaderboard(uint baid, uint songId, uint difficulty)
|
||||
{
|
||||
if (authSettings.AuthenticationRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
if (tokenInfo.Value.baid != baid && !tokenInfo.Value.isAdmin)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
}
|
||||
|
||||
var leaderboard = await songLeaderboardService.GetSongLeaderboard(songId, (Difficulty)difficulty, (int)baid);
|
||||
|
||||
return Ok(new SongLeaderboardResponse
|
||||
{
|
||||
Leaderboard = leaderboard
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace TaikoLocalServer.Services.Interfaces;
|
||||
|
||||
using SharedProject.Models;
|
||||
public interface ISongLeaderboardService
|
||||
{
|
||||
public Task<List<SongLeaderboard>> GetSongLeaderboard(uint songId, Difficulty difficulty, int baid, int limit = 10);
|
||||
}
|
97
TaikoLocalServer/Services/SongLeaderboardService.cs
Normal file
97
TaikoLocalServer/Services/SongLeaderboardService.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using GameDatabase.Context;
|
||||
using SharedProject.Models;
|
||||
|
||||
namespace TaikoLocalServer.Services;
|
||||
|
||||
public class SongLeaderboardService : ISongLeaderboardService
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
public SongLeaderboardService(TaikoDbContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public async Task<List<SongLeaderboard>> GetSongLeaderboard(uint songId, Difficulty difficulty, int baid,
|
||||
int limit = 10)
|
||||
{
|
||||
if (baid == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(baid));
|
||||
}
|
||||
|
||||
// get all scores for the song from every user
|
||||
var scores = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty)
|
||||
.OrderByDescending(x => x.BestScore)
|
||||
.ThenByDescending(x => x.BestRate)
|
||||
.Take(limit)
|
||||
.ToListAsync();
|
||||
|
||||
// get the user data for each score
|
||||
var leaderboard = new List<SongLeaderboard>();
|
||||
|
||||
// get the user data for each score
|
||||
foreach (var score in scores)
|
||||
{
|
||||
var user = await context.UserData
|
||||
.Where(x => x.Baid == score.Baid)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
leaderboard.Add(new SongLeaderboard
|
||||
{
|
||||
Rank = (uint)leaderboard.Count + 1,
|
||||
Baid = score.Baid,
|
||||
UserName = user?.MyDonName,
|
||||
BestScore = score.BestScore,
|
||||
BestRate = score.BestRate,
|
||||
BestCrown = score.BestCrown,
|
||||
BestScoreRank = score.BestScoreRank,
|
||||
GoodCount = score.GoodCount,
|
||||
OkCount = score.OkCount,
|
||||
MissCount = score.MissCount,
|
||||
ComboCount = score.ComboCount,
|
||||
HitCount = score.HitCount,
|
||||
DrumrollCount = score.DrumrollCount
|
||||
});
|
||||
}
|
||||
|
||||
// get current user score if it exists
|
||||
var currentUserScore = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty && x.Baid == baid)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (currentUserScore != null)
|
||||
{
|
||||
// check if they are in the limit
|
||||
var userRank = leaderboard.FindIndex(x => x.Baid == baid);
|
||||
|
||||
if (userRank >= limit)
|
||||
{
|
||||
// get the user data for the current user
|
||||
var user = await context.UserData
|
||||
.Where(x => x.Baid == baid)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
leaderboard.Add(new SongLeaderboard
|
||||
{
|
||||
Rank = (uint)userRank + 1,
|
||||
Baid = currentUserScore.Baid,
|
||||
UserName = user?.MyDonName,
|
||||
BestScore = currentUserScore.BestScore,
|
||||
BestRate = currentUserScore.BestRate,
|
||||
BestCrown = currentUserScore.BestCrown,
|
||||
BestScoreRank = currentUserScore.BestScoreRank,
|
||||
GoodCount = currentUserScore.GoodCount,
|
||||
OkCount = currentUserScore.OkCount,
|
||||
MissCount = currentUserScore.MissCount,
|
||||
ComboCount = currentUserScore.ComboCount,
|
||||
HitCount = currentUserScore.HitCount,
|
||||
DrumrollCount = currentUserScore.DrumrollCount
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return leaderboard;
|
||||
}
|
||||
}
|
2
TaikoWebUI/Components/Song/SongLeaderboardCard.razor
Normal file
2
TaikoWebUI/Components/Song/SongLeaderboardCard.razor
Normal file
@ -0,0 +1,2 @@
|
||||
@using TaikoWebUI.Utilities;
|
||||
|
Loading…
x
Reference in New Issue
Block a user