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 uint BestRate { get; set; }
|
||||||
public CrownType BestCrown { get; set; }
|
public CrownType BestCrown { get; set; }
|
||||||
public ScoreRank BestScoreRank { 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; }
|
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 List<AiSectionBestData> AiSectionBestData { get; set; } = new();
|
||||||
|
|
||||||
public bool ShowAiData { get; set; }
|
public bool ShowAiData { get; set; }
|
||||||
|
|
||||||
public List<SongPlayDatumDto> RecentPlayData { get; set; } = new();
|
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