diff --git a/LANCommander.Launcher.Models/DepotFilterModel.cs b/LANCommander.Launcher.Models/DepotFilterModel.cs index 32aeb602..a4678508 100644 --- a/LANCommander.Launcher.Models/DepotFilterModel.cs +++ b/LANCommander.Launcher.Models/DepotFilterModel.cs @@ -9,6 +9,7 @@ namespace LANCommander.Launcher.Models public GroupBy GroupBy { get; set; } = GroupBy.None; public SortBy SortBy { get; set; } = SortBy.Title; public SortDirection SortDirection { get; set; } = SortDirection.Ascending; + public ICollection Collections { get; set; } public ICollection Engines { get; set; } public ICollection Genres { get; set; } public ICollection Tags { get; set; } diff --git a/LANCommander.Launcher.Services/DepotService.cs b/LANCommander.Launcher.Services/DepotService.cs index dc2a84f3..761c482d 100644 --- a/LANCommander.Launcher.Services/DepotService.cs +++ b/LANCommander.Launcher.Services/DepotService.cs @@ -44,11 +44,11 @@ namespace LANCommander.Launcher.Services using (var op = Logger.BeginOperation(LogLevel.Trace, "Loading depot items from host")) { - var games = await Client.Depot.GetGamesAsync(); + var results = await Client.Depot.GetAsync(); - Filter.Populate(games); + Filter.Populate(results); - foreach (var item in games.Select(g => new ListItem(g)).OrderByTitle(g => !String.IsNullOrWhiteSpace(g.SortName) ? g.SortName : g.Name)) + foreach (var item in results.Games.Select(g => new ListItem(g)).OrderByTitle(g => !String.IsNullOrWhiteSpace(g.SortName) ? g.SortName : g.Name)) { Items.Add(item); } diff --git a/LANCommander.Launcher.Services/Models/DepotFilter.cs b/LANCommander.Launcher.Services/Models/DepotFilter.cs index 75272e5e..6343e319 100644 --- a/LANCommander.Launcher.Services/Models/DepotFilter.cs +++ b/LANCommander.Launcher.Services/Models/DepotFilter.cs @@ -25,53 +25,21 @@ namespace LANCommander.Launcher.Models public Func GroupSelector { get; set; } = _ => new string[] { }; - public void Populate(IEnumerable games) + public void Populate(DepotResults results) { - var multiplayerModes = games.Where(g => g.MultiplayerModes != null).SelectMany(g => g.MultiplayerModes); + var multiplayerModes = results.Games + .Where(g => g.MultiplayerModes != null) + .SelectMany(g => g.MultiplayerModes); - DataSource.Engines = games - .Select(i => i.Engine) - .Where(e => e != null) - .DistinctBy(e => e.Id) - .OrderBy(e => e.Name) - .ToList(); + DataSource.Collections = results.Collections.OrderBy(c => c.Name).ToList(); + DataSource.Engines = results.Engines.OrderBy(e => e.Name).ToList(); + DataSource.Genres = results.Genres.OrderBy(g => g.Name).ToList(); + DataSource.Tags = results.Tags.OrderBy(t => t.Name).ToList(); + DataSource.Platforms = results.Platforms.OrderBy(p => p.Name).ToList(); + DataSource.Developers = results.Companies.OrderBy(c => c.Name).ToList(); + DataSource.Publishers = results.Companies.OrderBy(c => c.Name).ToList(); - DataSource.Genres = games - .SelectMany(i => i.Genres) - .Where(g => g != null) - .DistinctBy(g => g.Id) - .OrderBy(g => g.Name) - .ToList(); - - DataSource.Tags = games - .SelectMany(i => i.Tags) - .Where(t => t != null) - .DistinctBy(t => t.Id) - .OrderBy(t => t.Name) - .ToList(); - - DataSource.Platforms = games - .SelectMany(i => i.Platforms) - .Where(p => p != null) - .DistinctBy(p => p.Id) - .OrderBy(p => p.Name) - .ToList(); - - DataSource.Developers = games - .SelectMany(i => i.Developers) - .Where(c => c != null) - .DistinctBy(c => c.Id) - .OrderBy(c => c.Name) - .ToList(); - - DataSource.Publishers = games - .SelectMany(i => i.Publishers) - .Where(c => c != null) - .DistinctBy(c => c.Id) - .OrderBy(c => c.Name) - .ToList(); - - if (games.Any(li => li.Singleplayer)) + if (results.Games.Any(li => li.Singleplayer)) DataSource.MinPlayers = 1; else if (multiplayerModes.Any()) DataSource.MinPlayers = multiplayerModes.Where(i => i != null).Min(i => i.MinPlayers); @@ -88,19 +56,25 @@ namespace LANCommander.Launcher.Models items = items.Where(i => i.Name?.IndexOf(SelectedOptions.Title, StringComparison.OrdinalIgnoreCase) >= 0 || i.SortName?.IndexOf(SelectedOptions.Title, StringComparison.OrdinalIgnoreCase) >= 0); if (SelectedOptions.Engines != null && SelectedOptions.Engines.Any()) - items = items.Where(i => SelectedOptions.Engines.Any(e => e.Id == (i.DataItem as DepotGame)?.Engine?.Id)); + items = items.Where(i => SelectedOptions.Engines.Any(e => (i.DataItem as DepotGame).EngineId == e.Id)); + + if (SelectedOptions.Collections != null && SelectedOptions.Collections.Any()) + items = items.Where(i => SelectedOptions.Collections.Any(fc => (i.DataItem as DepotGame).Collections.Contains(fc.Id))); if (SelectedOptions.Genres != null && SelectedOptions.Genres.Any()) - items = items.Where(i => SelectedOptions.Genres.Any(fg => (i.DataItem as DepotGame).Genres.Any(g => fg.Id == g.Id))); + items = items.Where(i => SelectedOptions.Genres.Any(fg => (i.DataItem as DepotGame).Genres.Contains(fg.Id))); if (SelectedOptions.Tags != null && SelectedOptions.Tags.Any()) - items = items.Where(i => SelectedOptions.Tags.Any(ft => (i.DataItem as DepotGame).Tags.Any(t => ft.Id == t.Id))); + items = items.Where(i => SelectedOptions.Tags.Any(ft => (i.DataItem as DepotGame).Tags.Contains(ft.Id))); if (SelectedOptions.Developers != null && SelectedOptions.Developers.Any()) - items = items.Where(i => SelectedOptions.Developers.Any(fc => (i.DataItem as DepotGame).Developers.Any(c => fc.Id == c.Id))); + items = items.Where(i => SelectedOptions.Developers.Any(fc => (i.DataItem as DepotGame).Developers.Contains(fc.Id))); if (SelectedOptions.Publishers != null && SelectedOptions.Publishers.Any()) - items = items.Where(i => SelectedOptions.Publishers.Any(fc => (i.DataItem as DepotGame).Publishers.Any(c => fc.Id == c.Id))); + items = items.Where(i => SelectedOptions.Publishers.Any(fc => (i.DataItem as DepotGame).Publishers.Contains(fc.Id))); + + if (SelectedOptions.Platforms != null && SelectedOptions.Platforms.Any()) + items = items.Where(i => SelectedOptions.Platforms.Any(fp => (i.DataItem as DepotGame).Platforms.Contains(fp.Id))); if (SelectedOptions.MinPlayers != null) items = items.Where(i => (i.DataItem as DepotGame).MultiplayerModes.Any(mm => mm.MinPlayers <= SelectedOptions.MinPlayers && mm.MaxPlayers >= SelectedOptions.MinPlayers)); @@ -137,25 +111,25 @@ namespace LANCommander.Launcher.Models case Enums.GroupBy.Collection: GroupSelector = (g) => - (g.DataItem as DepotGame)?.Collections? - .Where(c => c?.Name != null) + DataSource.Collections + .Where(c => (g.DataItem as DepotGame).Collections.Contains(c.Id)) .Select(c => c.Name) .ToArray() ?? Array.Empty(); break; case Enums.GroupBy.Genre: GroupSelector = (g) => - (g.DataItem as DepotGame)?.Genres? - .Where(ge => ge?.Name != null) - .Select(ge => ge.Name) + DataSource.Genres + .Where(ge => (g.DataItem as DepotGame).Genres.Contains(ge.Id)) + .Select(g => g.Name) .ToArray() ?? Array.Empty(); break; case Enums.GroupBy.Platform: GroupSelector = (g) => - (g.DataItem as DepotGame)?.Platforms? - .Where(p => p?.Name != null) - .Select(p => p.Name) + DataSource.Platforms + .Where(p => (g.DataItem as DepotGame).Platforms.Contains(p.Id)) + .Select(g => g.Name) .ToArray() ?? Array.Empty(); break; } diff --git a/LANCommander.Launcher/UI/Depot/Components/DepotFilter.razor b/LANCommander.Launcher/UI/Depot/Components/DepotFilter.razor index 88f286a1..dcca9e61 100644 --- a/LANCommander.Launcher/UI/Depot/Components/DepotFilter.razor +++ b/LANCommander.Launcher/UI/Depot/Components/DepotFilter.razor @@ -33,6 +33,9 @@ + + + diff --git a/LANCommander.SDK/Models/DepotGame.cs b/LANCommander.SDK/Models/DepotGame.cs index 53ba2d91..2c01ac40 100644 --- a/LANCommander.SDK/Models/DepotGame.cs +++ b/LANCommander.SDK/Models/DepotGame.cs @@ -21,13 +21,13 @@ namespace LANCommander.SDK.Models public bool InLibrary { get; set; } public GameType Type { get; set; } public Media Cover { get; set; } - public IEnumerable Collections { get; set; } - public IEnumerable Developers { get; set; } - public IEnumerable Publishers { get; set; } - public Engine Engine { get; set; } - public IEnumerable Genres { get; set; } + public IEnumerable Collections { get; set; } + public IEnumerable Developers { get; set; } + public IEnumerable Publishers { get; set; } + public Guid EngineId { get; set; } + public IEnumerable Genres { get; set; } public IEnumerable MultiplayerModes { get; set; } - public IEnumerable Platforms { get; set; } - public IEnumerable Tags { get; set; } + public IEnumerable Platforms { get; set; } + public IEnumerable Tags { get; set; } } } diff --git a/LANCommander.SDK/Models/DepotResults.cs b/LANCommander.SDK/Models/DepotResults.cs new file mode 100644 index 00000000..b5703d0f --- /dev/null +++ b/LANCommander.SDK/Models/DepotResults.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LANCommander.SDK.Models +{ + public class DepotResults + { + public ICollection Games { get; set; } + public ICollection Collections { get; set; } + public ICollection Companies { get; set; } + public ICollection Engines { get; set; } + public ICollection Genres { get; set; } + public ICollection Platforms { get; set; } + public ICollection Tags { get; set; } + } +} diff --git a/LANCommander.SDK/Services/DepotService.cs b/LANCommander.SDK/Services/DepotService.cs index 45cafaf7..30d018a6 100644 --- a/LANCommander.SDK/Services/DepotService.cs +++ b/LANCommander.SDK/Services/DepotService.cs @@ -27,9 +27,9 @@ namespace LANCommander.SDK.Services Logger = logger; } - public async Task> GetGamesAsync() + public async Task GetAsync() { - return await Client.GetRequestAsync>("/api/Depot/Games"); + return await Client.GetRequestAsync("/api/Depot"); } public async Task GetGameAsync(Guid gameId) diff --git a/LANCommander.Server.Services/LibraryService.cs b/LANCommander.Server.Services/LibraryService.cs index 1df4fe50..f7c8f926 100644 --- a/LANCommander.Server.Services/LibraryService.cs +++ b/LANCommander.Server.Services/LibraryService.cs @@ -29,7 +29,7 @@ namespace LANCommander.Server.Services public async Task GetByUserIdAsync(Guid userId) { - var library = await Include(l => l.Games.Select(g => g.Id)).FirstOrDefaultAsync(l => l.User.Id == userId); + var library = await Include(l => l.Games).FirstOrDefaultAsync(l => l.User.Id == userId); if (library == null) { diff --git a/LANCommander.Server/AutoMapper.cs b/LANCommander.Server/AutoMapper.cs index ec812a52..c6994f7e 100644 --- a/LANCommander.Server/AutoMapper.cs +++ b/LANCommander.Server/AutoMapper.cs @@ -49,7 +49,25 @@ namespace LANCommander.Server CreateMap() .ForMember(dest => dest.Cover, - opt => opt.MapFrom(src => src.Media.Where(m => m.Type == SDK.Enums.MediaType.Cover).FirstOrDefault())); + opt => opt.MapFrom(src => src.Media.Where(m => m.Type == SDK.Enums.MediaType.Cover).FirstOrDefault())) + .ForMember(dest => + dest.Collections, + opt => opt.MapFrom(src => src.Tags.Select(c => c.Id))) + .ForMember(dest => + dest.Developers, + opt => opt.MapFrom(src => src.Developers.Select(c => c.Id))) + .ForMember(dest => + dest.Publishers, + opt => opt.MapFrom(src => src.Publishers.Select(c => c.Id))) + .ForMember(dest => + dest.Genres, + opt => opt.MapFrom(src => src.Genres.Select(g => g.Id))) + .ForMember(dest => + dest.Platforms, + opt => opt.MapFrom(src => src.Platforms.Select(p => p.Id))) + .ForMember(dest => + dest.Tags, + opt => opt.MapFrom(src => src.Tags.Select(t => t.Id))); } } } diff --git a/LANCommander.Server/Controllers/Api/DepotController.cs b/LANCommander.Server/Controllers/Api/DepotController.cs index 537b9128..ede48cae 100644 --- a/LANCommander.Server/Controllers/Api/DepotController.cs +++ b/LANCommander.Server/Controllers/Api/DepotController.cs @@ -20,69 +20,66 @@ namespace LANCommander.Server.Controllers.Api private readonly IMapper Mapper; private readonly IFusionCache Cache; private readonly GameService GameService; + private readonly CollectionService CollectionService; + private readonly CompanyService CompanyService; + private readonly EngineService EngineService; + private readonly GenreService GenreService; + private readonly PlatformService PlatformService; + private readonly TagService TagService; private readonly LibraryService LibraryService; private readonly UserService UserService; + private readonly DatabaseContext DatabaseContext; public DepotController( ILogger logger, IMapper mapper, IFusionCache cache, GameService gameService, + CollectionService collectionService, + CompanyService companyService, + EngineService engineService, + GenreService genreService, + PlatformService platformService, + TagService tagService, LibraryService libraryService, - UserService userService) : base(logger) + UserService userService, + DatabaseContext databaseContext) : base(logger) { Mapper = mapper; Cache = cache; GameService = gameService; + CollectionService = collectionService; + CompanyService = companyService; + EngineService = engineService; + GenreService = genreService; + PlatformService = platformService; + TagService = tagService; LibraryService = libraryService; UserService = userService; + DatabaseContext = databaseContext; } - [HttpGet("Games")] - public async Task> GetGamesAsync() + [HttpGet] + public async Task GetAsync() { var user = await UserService.GetAsync(User?.Identity?.Name); var library = await LibraryService.GetByUserIdAsync(user.Id); - var libraryGameIds = library.Games.Where(g => g != null).Select(g => g.Id).ToList(); - - var games = await Cache.GetOrSetAsync("DepotGames", async _ => + var results = await Cache.GetOrSetAsync("DepotResults", async _ => { - return await GameService - .Include(g => g.Media.Where(m => m.Type == SDK.Enums.MediaType.Cover)) - .Include(g => g.Collections.Select(c => c.Id)) - .Include(g => g.Developers.Select(c => c.Id)) - .Include(g => g.Genres.Select(g => g.Id)) - .Include(g => g.MultiplayerModes) - .Include(g => g.Platforms.Select(p => p.Id)) - .Include(g => g.Publishers.Select(c => c.Id)) - .Include(g => g.Tags.Select(t => t.Id)) - .GetAsync(); - }, TimeSpan.MaxValue); - - var accessibleGames = games.ToList(); - - if (Settings.Roles.RestrictGamesByCollection && !User.IsInRole(RoleService.AdministratorRoleName)) - { - var roles = await UserService.GetRolesAsync(User?.Identity.Name); - - var accessibleCollectionIds = roles.SelectMany(r => r.Collections.Select(c => c.Id)).Distinct(); - - accessibleGames = games.Where(g => g.Collections.Any(c => accessibleCollectionIds.Contains(c.Id))).ToList(); - - foreach (var game in accessibleGames) + return new SDK.Models.DepotResults { - game.Collections = game.Collections.Where(c => accessibleCollectionIds.Contains(c.Id)); - } - } + Games = await GameService.GetAsync(), + Collections = await CollectionService.GetAsync(), + Companies = await CompanyService.GetAsync(), + Engines = await EngineService.GetAsync(), + Genres = await GenreService.GetAsync(), + Platforms = await PlatformService.GetAsync(), + Tags = await TagService.GetAsync(), + }; + }); - foreach (var game in accessibleGames) - { - if (libraryGameIds.Contains(game.Id)) - game.InLibrary = true; - } - - return accessibleGames; + return results; } [HttpGet("Games/{id}")] diff --git a/LANCommander.Server/LANCommander.Server.csproj b/LANCommander.Server/LANCommander.Server.csproj index c2437c2c..b9bee17a 100644 --- a/LANCommander.Server/LANCommander.Server.csproj +++ b/LANCommander.Server/LANCommander.Server.csproj @@ -106,6 +106,7 @@ + diff --git a/LANCommander.Server/Program.cs b/LANCommander.Server/Program.cs index c562e00d..8b4433d5 100644 --- a/LANCommander.Server/Program.cs +++ b/LANCommander.Server/Program.cs @@ -23,6 +23,7 @@ using LANCommander.Server.Jobs.Background; using Microsoft.Data.Sqlite; using Microsoft.OpenApi.Models; using Microsoft.CodeAnalysis.Options; +using Scalar.AspNetCore; namespace LANCommander.Server { @@ -234,7 +235,7 @@ namespace LANCommander.Server builder.Services.AddSwaggerGen(options => { options.CustomSchemaIds(type => type.ToString()); - options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = "Enter a valid access token", @@ -363,8 +364,11 @@ namespace LANCommander.Server app.UseHsts(); } - app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwagger(options => + { + options.RouteTemplate = "/openapi/{documentName}.json"; + }); + app.MapScalarApiReference(); app.UseHangfireDashboard(); // app.UseHttpsRedirection();