diff --git a/src/DevilDaggersInfo.Web.ApiSpec.Main/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs b/src/DevilDaggersInfo.Web.ApiSpec.Main/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs index 05a2e3684..63fe6515d 100644 --- a/src/DevilDaggersInfo.Web.ApiSpec.Main/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs +++ b/src/DevilDaggersInfo.Web.ApiSpec.Main/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs @@ -7,4 +7,6 @@ public record GetCustomLeaderboardAllowedCategory public required GameMode GameMode { get; init; } public required CustomLeaderboardRankSorting RankSorting { get; init; } + + public required int LeaderboardCount { get; init; } } diff --git a/src/DevilDaggersInfo.Web.ApiSpec.Tools/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs b/src/DevilDaggersInfo.Web.ApiSpec.Tools/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs index bca7ce63b..5f6a8b9a7 100644 --- a/src/DevilDaggersInfo.Web.ApiSpec.Tools/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs +++ b/src/DevilDaggersInfo.Web.ApiSpec.Tools/CustomLeaderboards/GetCustomLeaderboardAllowedCategory.cs @@ -5,4 +5,6 @@ public record GetCustomLeaderboardAllowedCategory public required SpawnsetGameMode GameMode { get; init; } public required CustomLeaderboardRankSorting RankSorting { get; init; } + + public required int LeaderboardCount { get; init; } } diff --git a/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.cs b/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.cs index 3de966690..06cbe05d0 100644 --- a/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.cs +++ b/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.cs @@ -61,7 +61,7 @@ protected override async Task OnInitializedAsync() GetTotalCustomLeaderboardData = await Http.GetTotalCustomLeaderboardData(); List allowedCategories = await Http.GetCustomLeaderboardAllowedCategories(); - _categories = allowedCategories.ConvertAll(a => new CategoryDropdown(a.GameMode, a.RankSorting)); + _categories = allowedCategories.ConvertAll(a => new CategoryDropdown(a.GameMode, a.RankSorting, a.LeaderboardCount)); } protected override async Task OnParametersSetAsync() @@ -135,10 +135,13 @@ private async Task Fetch() private sealed class CategoryDropdown { - public CategoryDropdown(GameMode gameMode, CustomLeaderboardRankSorting rankSorting) + private readonly int _leaderboardCount; + + public CategoryDropdown(GameMode gameMode, CustomLeaderboardRankSorting rankSorting, int leaderboardCount) { GameMode = gameMode; RankSorting = rankSorting; + _leaderboardCount = leaderboardCount; } public GameMode GameMode { get; } @@ -146,7 +149,9 @@ public CategoryDropdown(GameMode gameMode, CustomLeaderboardRankSorting rankSort public override string ToString() { - return $"{GameMode.ToCore().ToDisplayString()}: {RankSorting.ToDisplayString()}"; + string gameMode = GameMode.ToCore().ToDisplayString(); + string rankSorting = RankSorting.ToDisplayString(); + return $"{gameMode}: {rankSorting} ({_leaderboardCount})"; } } } diff --git a/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.razor b/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.razor index 96a17a857..0f4510da6 100644 --- a/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.razor +++ b/src/DevilDaggersInfo.Web.Client/Pages/Custom/Leaderboards/Index.razor @@ -22,23 +22,22 @@ Check out the global custom leaderboards here.

-@if (GetCustomLeaderboards == null) +@if (GetCustomLeaderboards == null || _categories == null) { } else { + CategoryDropdown defaultCategoryDropdown = _categories.Count > 0 ? _categories[0] : new CategoryDropdown(EnumConvert.GetGameMode(GameMode), EnumConvert.GetRankSorting(RankSorting), 0); +
Spawnset name - + Author name - - @if (_categories != null) - { - Category - - } + + Category +
@@ -71,7 +70,7 @@ else CustomLeaderboardRankSorting.TimeAsc or CustomLeaderboardRankSorting.TimeDesc => StringFormats.TimeFormat, _ => "0", }; - +
diff --git a/src/DevilDaggersInfo.Web.Server.Domain.Admin/Services/CustomLeaderboardService.cs b/src/DevilDaggersInfo.Web.Server.Domain.Admin/Services/CustomLeaderboardService.cs index 4987ef9f9..c613f2673 100644 --- a/src/DevilDaggersInfo.Web.Server.Domain.Admin/Services/CustomLeaderboardService.cs +++ b/src/DevilDaggersInfo.Web.Server.Domain.Admin/Services/CustomLeaderboardService.cs @@ -5,6 +5,7 @@ using DevilDaggersInfo.Web.ApiSpec.Admin.CustomEntries; using DevilDaggersInfo.Web.Server.Domain.Admin.Converters.ApiToDomain; using DevilDaggersInfo.Web.Server.Domain.Admin.Exceptions; +using DevilDaggersInfo.Web.Server.Domain.Converters.CoreToDomain; using DevilDaggersInfo.Web.Server.Domain.Entities; using DevilDaggersInfo.Web.Server.Domain.Entities.Enums; using DevilDaggersInfo.Web.Server.Domain.Entities.Values; @@ -466,7 +467,7 @@ private async Task ValidateCustomLeaderboardAsync( if (spawnsetBinary.GameMode == GameMode.TimeAttack && !spawnsetBinary.HasSpawns()) throw new CustomLeaderboardValidationException("Time Attack spawnset must have spawns."); - if (!CustomLeaderboardUtils.IsGameModeAndRankSortingCombinationAllowed(spawnsetBinary.GameMode, rankSorting)) + if (!CustomLeaderboardUtils.IsGameModeAndRankSortingCombinationAllowed(spawnsetBinary.GameMode.ToDomain(), rankSorting)) throw new CustomLeaderboardValidationException($"Combining game mode '{spawnsetBinary.GameMode}' and rank sorting '{rankSorting}' is not allowed."); CustomLeaderboardCriteriaOperator deathTypeOperator = deathTypeCriteria.Operator.ToDomain(); diff --git a/src/DevilDaggersInfo.Web.Server.Domain/Models/CustomLeaderboards/CustomLeaderboardAllowedCategory.cs b/src/DevilDaggersInfo.Web.Server.Domain/Models/CustomLeaderboards/CustomLeaderboardAllowedCategory.cs new file mode 100644 index 000000000..6be0c9262 --- /dev/null +++ b/src/DevilDaggersInfo.Web.Server.Domain/Models/CustomLeaderboards/CustomLeaderboardAllowedCategory.cs @@ -0,0 +1,12 @@ +using DevilDaggersInfo.Web.Server.Domain.Entities.Enums; + +namespace DevilDaggersInfo.Web.Server.Domain.Models.CustomLeaderboards; + +public record CustomLeaderboardAllowedCategory +{ + public required SpawnsetGameMode GameMode { get; init; } + + public required CustomLeaderboardRankSorting RankSorting { get; init; } + + public required int LeaderboardCount { get; init; } +} diff --git a/src/DevilDaggersInfo.Web.Server.Domain/Repositories/CustomLeaderboardRepository.cs b/src/DevilDaggersInfo.Web.Server.Domain/Repositories/CustomLeaderboardRepository.cs index c7b1e01f9..c91dbbeca 100644 --- a/src/DevilDaggersInfo.Web.Server.Domain/Repositories/CustomLeaderboardRepository.cs +++ b/src/DevilDaggersInfo.Web.Server.Domain/Repositories/CustomLeaderboardRepository.cs @@ -344,6 +344,23 @@ public async Task GetCustomLeaderboardIdBySpawnsetHashAsync(byte[] hash) return customLeaderboard.Id; } + public async Task> GetCustomLeaderboardAllowedCategories() + { + List<(SpawnsetGameMode GameMode, CustomLeaderboardRankSorting RankSorting)> allowedCategories = CustomLeaderboardUtils.GetAllowedGameModeAndRankSortingCombinations(); + + // ! Navigation property. + var customLeaderboards = await _dbContext.CustomLeaderboards + .Select(cl => new { cl.Spawnset!.GameMode, cl.RankSorting }) + .ToListAsync(); + + return allowedCategories.ConvertAll(ac => new CustomLeaderboardAllowedCategory + { + GameMode = ac.GameMode, + RankSorting = ac.RankSorting, + LeaderboardCount = customLeaderboards.Count(cl => cl.GameMode == ac.GameMode && cl.RankSorting == ac.RankSorting), + }); + } + private static CustomLeaderboardOverview ToOverview(CustomLeaderboardData cl) { if (cl.CustomLeaderboard.Spawnset == null) diff --git a/src/DevilDaggersInfo.Web.Server.Domain/Utils/CustomLeaderboardUtils.cs b/src/DevilDaggersInfo.Web.Server.Domain/Utils/CustomLeaderboardUtils.cs index a312ef2ab..cf9a2c48e 100644 --- a/src/DevilDaggersInfo.Web.Server.Domain/Utils/CustomLeaderboardUtils.cs +++ b/src/DevilDaggersInfo.Web.Server.Domain/Utils/CustomLeaderboardUtils.cs @@ -1,4 +1,3 @@ -using DevilDaggersInfo.Core.Spawnset; using DevilDaggersInfo.Web.Server.Domain.Entities.Enums; using DevilDaggersInfo.Web.Server.Domain.Extensions; using DevilDaggersInfo.Web.Server.Domain.Models.CustomLeaderboards; @@ -53,24 +52,24 @@ public static CustomLeaderboardDagger GetDaggerFromStat(CustomLeaderboardRankSor return CustomLeaderboardDagger.Default; } - public static bool IsGameModeAndRankSortingCombinationAllowed(GameMode gameMode, CustomLeaderboardRankSorting rankSorting) + public static bool IsGameModeAndRankSortingCombinationAllowed(SpawnsetGameMode gameMode, CustomLeaderboardRankSorting rankSorting) { // Allow all rank sortings for Survival. - if (gameMode == GameMode.Survival) + if (gameMode == SpawnsetGameMode.Survival) return true; // Allow both time rank sortings for Race. - if (gameMode == GameMode.Race) + if (gameMode == SpawnsetGameMode.Race) return rankSorting is CustomLeaderboardRankSorting.TimeAsc or CustomLeaderboardRankSorting.TimeDesc; // Only allow ascending time sort for TimeAttack for now. return rankSorting == CustomLeaderboardRankSorting.TimeAsc; } - public static List<(GameMode GameMode, CustomLeaderboardRankSorting RankSorting)> GetAllowedGameModeAndRankSortingCombinations() + public static List<(SpawnsetGameMode GameMode, CustomLeaderboardRankSorting RankSorting)> GetAllowedGameModeAndRankSortingCombinations() { - List<(GameMode GameMode, CustomLeaderboardRankSorting RankSorting)> allowedCombinations = []; - foreach (GameMode gameMode in Enum.GetValues()) + List<(SpawnsetGameMode GameMode, CustomLeaderboardRankSorting RankSorting)> allowedCombinations = []; + foreach (SpawnsetGameMode gameMode in Enum.GetValues()) { foreach (CustomLeaderboardRankSorting rankSorting in Enum.GetValues().Where(rs => IsGameModeAndRankSortingCombinationAllowed(gameMode, rs))) allowedCombinations.Add((gameMode, rankSorting)); diff --git a/src/DevilDaggersInfo.Web.Server/Controllers/Main/CustomLeaderboardsController.cs b/src/DevilDaggersInfo.Web.Server/Controllers/Main/CustomLeaderboardsController.cs index 4d172f73e..675178b3f 100644 --- a/src/DevilDaggersInfo.Web.Server/Controllers/Main/CustomLeaderboardsController.cs +++ b/src/DevilDaggersInfo.Web.Server/Controllers/Main/CustomLeaderboardsController.cs @@ -4,13 +4,12 @@ using DevilDaggersInfo.Web.Client; using DevilDaggersInfo.Web.Server.Converters.ApiToDomain.Main; using DevilDaggersInfo.Web.Server.Converters.DomainToApi.Main; -using DevilDaggersInfo.Web.Server.Domain.Converters.CoreToDomain; using DevilDaggersInfo.Web.Server.Domain.Main.Converters.DomainToApi; using DevilDaggersInfo.Web.Server.Domain.Repositories; using DevilDaggersInfo.Web.Server.Domain.Utils; using Microsoft.AspNetCore.Mvc; using System.ComponentModel.DataAnnotations; -using Model = DevilDaggersInfo.Web.Server.Domain.Models.CustomLeaderboards; +using MainApi = DevilDaggersInfo.Web.Server.Domain.Models.CustomLeaderboards; namespace DevilDaggersInfo.Web.Server.Controllers.Main; @@ -38,7 +37,7 @@ public async Task>> GetCustomLea CustomLeaderboardSorting? sortBy = null, bool ascending = false) { - Domain.Models.Page cls = await _customLeaderboardRepository.GetCustomLeaderboardOverviewsAsync( + Domain.Models.Page cls = await _customLeaderboardRepository.GetCustomLeaderboardOverviewsAsync( rankSorting: rankSorting.ToDomain(), gameMode: gameMode.ToDomain(), spawnsetFilter: spawnsetFilter, @@ -61,7 +60,7 @@ public async Task>> GetCustomLea [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> GetGlobalCustomLeaderboardForCategory([Required] GameMode gameMode, [Required] CustomLeaderboardRankSorting rankSorting) { - Model.GlobalCustomLeaderboard globalCustomLeaderboard = await _customLeaderboardRepository.GetGlobalCustomLeaderboardAsync(gameMode.ToDomain(), rankSorting.ToDomain()); + MainApi.GlobalCustomLeaderboard globalCustomLeaderboard = await _customLeaderboardRepository.GetGlobalCustomLeaderboardAsync(gameMode.ToDomain(), rankSorting.ToDomain()); return new GetGlobalCustomLeaderboard { Entries = globalCustomLeaderboard.Entries @@ -97,7 +96,7 @@ public async Task> GetGlobalCustomLeade [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetTotalCustomLeaderboardData() { - Model.CustomLeaderboardsTotalData totalData = await _customLeaderboardRepository.GetCustomLeaderboardsTotalDataAsync(); + MainApi.CustomLeaderboardsTotalData totalData = await _customLeaderboardRepository.GetCustomLeaderboardsTotalDataAsync(); return new GetTotalCustomLeaderboardData { LeaderboardsPerGameMode = totalData.LeaderboardsPerGameMode.ToDictionary(kvp => kvp.Key.ToMainApi(), kvp => kvp.Value), @@ -113,19 +112,15 @@ public async Task> GetTotalCustomLea [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetCustomLeaderboardById(int id) { - Model.SortedCustomLeaderboard cl = await _customLeaderboardRepository.GetSortedCustomLeaderboardByIdAsync(id); + MainApi.SortedCustomLeaderboard cl = await _customLeaderboardRepository.GetSortedCustomLeaderboardByIdAsync(id); return cl.ToMainApi(); } [HttpGet("allowed-categories")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetCustomLeaderboardAllowedCategories() + public async Task>> GetCustomLeaderboardAllowedCategories() { - List<(DevilDaggersInfo.Core.Spawnset.GameMode GameMode, Domain.Entities.Enums.CustomLeaderboardRankSorting RankSorting)> allowedCategories = CustomLeaderboardUtils.GetAllowedGameModeAndRankSortingCombinations(); - return allowedCategories.ConvertAll(ac => new GetCustomLeaderboardAllowedCategory - { - GameMode = ac.GameMode.ToDomain().ToMainApi(), - RankSorting = ac.RankSorting.ToMainApi(), - }); + List allowedCategories = await _customLeaderboardRepository.GetCustomLeaderboardAllowedCategories(); + return allowedCategories.ConvertAll(ac => ac.ToMainApi()); } } diff --git a/src/DevilDaggersInfo.Web.Server/Controllers/Tools/CustomLeaderboardsController.cs b/src/DevilDaggersInfo.Web.Server/Controllers/Tools/CustomLeaderboardsController.cs index ce1a28104..693ec19e5 100644 --- a/src/DevilDaggersInfo.Web.Server/Controllers/Tools/CustomLeaderboardsController.cs +++ b/src/DevilDaggersInfo.Web.Server/Controllers/Tools/CustomLeaderboardsController.cs @@ -67,13 +67,9 @@ public async Task CustomLeaderboardExistsBySpawnsetHash([FromQuery [HttpGet("allowed-categories")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetCustomLeaderboardAllowedCategories() + public async Task>> GetCustomLeaderboardAllowedCategories() { - List<(DevilDaggersInfo.Core.Spawnset.GameMode GameMode, Domain.Entities.Enums.CustomLeaderboardRankSorting RankSorting)> allowedCategories = CustomLeaderboardUtils.GetAllowedGameModeAndRankSortingCombinations(); - return allowedCategories.ConvertAll(ac => new GetCustomLeaderboardAllowedCategory - { - GameMode = ac.GameMode.ToDomain().ToToolsApi(), - RankSorting = ac.RankSorting.ToToolsApi(), - }); + List customLeaderboardAllowedCategories = await _customLeaderboardRepository.GetCustomLeaderboardAllowedCategories(); + return customLeaderboardAllowedCategories.ConvertAll(ac => ac.ToToolsApi()); } } diff --git a/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Main/CustomLeaderboardConverters.cs b/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Main/CustomLeaderboardConverters.cs index 36b5a3c27..4095d8e2b 100644 --- a/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Main/CustomLeaderboardConverters.cs +++ b/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Main/CustomLeaderboardConverters.cs @@ -88,6 +88,16 @@ private static MainApi.GetCustomEntry ToMainApi(this CustomEntry customEntry, Sp }; } + public static MainApi.GetCustomLeaderboardAllowedCategory ToMainApi(this CustomLeaderboardAllowedCategory allowedCategory) + { + return new MainApi.GetCustomLeaderboardAllowedCategory + { + GameMode = allowedCategory.GameMode.ToMainApi(), + RankSorting = allowedCategory.RankSorting.ToMainApi(), + LeaderboardCount = allowedCategory.LeaderboardCount, + }; + } + private static MainApi.GetCustomLeaderboardDaggers ToMainApi(this CustomLeaderboardDaggers customLeaderboardDaggers, bool isTime) { return new MainApi.GetCustomLeaderboardDaggers diff --git a/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Tools/CustomLeaderboardConverters.cs b/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Tools/CustomLeaderboardConverters.cs index df0fc7be8..2d9b7212d 100644 --- a/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Tools/CustomLeaderboardConverters.cs +++ b/src/DevilDaggersInfo.Web.Server/Converters/DomainToApi/Tools/CustomLeaderboardConverters.cs @@ -161,6 +161,16 @@ public static ToolsApi.GetCustomLeaderboardForOverview ToToolsApi(this CustomLea }; } + public static ToolsApi.GetCustomLeaderboardAllowedCategory ToToolsApi(this CustomLeaderboardAllowedCategory customLeaderboardAllowedCategory) + { + return new ToolsApi.GetCustomLeaderboardAllowedCategory + { + GameMode = customLeaderboardAllowedCategory.GameMode.ToToolsApi(), + RankSorting = customLeaderboardAllowedCategory.RankSorting.ToToolsApi(), + LeaderboardCount = customLeaderboardAllowedCategory.LeaderboardCount, + }; + } + private static ToolsApi.GetCustomLeaderboardCriteria ToToolsApi(this CustomLeaderboardCriteria customLeaderboardCriteria) { return new ToolsApi.GetCustomLeaderboardCriteria