Add services and controllers for games #12

Merged
Egamorf merged 7 commits from release/add-services-controllers into main 2025-04-12 21:34:45 +02:00
23 changed files with 283 additions and 10 deletions
Showing only changes of commit 69a3570a60 - Show all commits

View File

@@ -21,7 +21,7 @@ public partial class GameFilter
]; ];
private readonly IEnumerable<SelectElement<Func<GameDto?, object?>>> GameProperties = [ private readonly IEnumerable<SelectElement<Func<GameDto?, object?>>> GameProperties = [
new() { Item = game => game?.Name, Label = "Nom", IsSelected = true }, new() { Item = game => game?.Title, Label = "Nom", IsSelected = true },
new() { Item = game => game?.ReleaseDate, Label = "Date de parution" } new() { Item = game => game?.ReleaseDate, Label = "Date de parution" }
]; ];
@@ -40,7 +40,7 @@ public partial class GameFilter
]; ];
private EditContext? EditContext; private EditContext? EditContext;
private SliderRangeParams SliderRangeParams = private readonly SliderRangeParams SliderRangeParams =
new() { Min = 1, ValueMin = 1, ValueMax = 5, Max = 5 }; new() { Min = 1, ValueMin = 1, ValueMax = 5, Max = 5 };
protected override void OnInitialized() protected override void OnInitialized()

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class DeveloperDto
{
public int? Id { get; set; }
public string? Name { get; set; }
}

View File

@@ -2,6 +2,19 @@
public class GameDto public class GameDto
{ {
public string? Name { get; set; } public int? Id { get; set; }
public string? ReleaseDate { get; set; } public string? Title { get; set; }
public DateTime? ReleaseDate { get; set; }
public DateTime? CreationDate { get; set; }
public UserDto? CreationUser { get; set; }
public DateTime? ModificationDate { get; set; }
public UserDto? ModificationUser { get; set; }
public double? StorageSpace { get; set; }
public string? Description { get; set; }
public int? Interest { get; set; }
public IEnumerable<PlatformDto>? Platforms { get; set; }
public IEnumerable<PropertyDto>? Properties { get; set; }
public IEnumerable<TagDto>? Tags { get; set; }
public IEnumerable<PublisherDto>? Publishers { get; set; }
public IEnumerable<DeveloperDto>? Developers { get; set; }
} }

View File

@@ -0,0 +1,18 @@
namespace GameIdeas.Shared.Dto;
public class GameFilterDto
{
public IEnumerable<string>? Platforms { get; set; }
public string? Name { get; set; }
public IEnumerable<string>? Tags { get; set; }
public IEnumerable<string>? Properties { get; set; }
public int? MinInterest { get; set; }
public int? MaxInterest { get; set; }
public IEnumerable<int>? ReleaseYears { get; set; }
public IEnumerable<int>? PublisherIds { get; set; }
public IEnumerable<int>? DeveloperIds { get; set; }
public IEnumerable<int>? CreationUserIds { get; set; }
public IEnumerable<int>? ModificationUserIds { get; set; }
public int CurrentPage { get; set; }
public int NumberPerPage { get; set; }
}

View File

@@ -1,7 +1,11 @@
namespace GameIdeas.Shared.Dto; using GameIdeas.Shared.Enum;
namespace GameIdeas.Shared.Dto;
public class LoginDto public class LoginDto
{ {
public int? Id { get; set; }
public string? Username { get; set; } public string? Username { get; set; }
public string? Password { get; set; } public string? Password { get; set; }
public Role? Role { get; set; }
} }

View File

@@ -0,0 +1,8 @@
namespace GameIdeas.Shared.Dto;
public class PlatformDto
{
public int? Id { get; set; }
public string? Label { get; set; }
public string? Url { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class PropertyDto
{
public int? Id { get; set; }
public string? Label { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class PublisherDto
{
public int? Id { get; set; }
public string? Name { get; set; }
}

View File

@@ -0,0 +1,8 @@

namespace GameIdeas.Shared.Dto;
public class TagDto
{
public int? Id { get; set; }
public string? Label { get; set; }
}

View File

@@ -0,0 +1,13 @@
using GameIdeas.Shared.Enum;
namespace GameIdeas.Shared.Dto;
public class UserDto
{
public int? Id { get; set; }
public string? Username { get; set; }
public string? Password { get; set; }
public Role? Role { get; set; }
public IEnumerable<GameDto>? CreationGames { get; set; }
public IEnumerable<GameDto>? ModificationGames { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace GameIdeas.Shared.Enum;
public enum Role
{
Guest = 1,
Member = 2,
Administrator = 3
}

View File

@@ -8,7 +8,7 @@ public partial class Platform
} }
public int Id { get; set; } public int Id { get; set; }
public string Libelle { get; set; } = null!; public string Label { get; set; } = null!;
public virtual ICollection<GamePlatform> GamePlatforms { get; set; } public virtual ICollection<GamePlatform> GamePlatforms { get; set; }

View File

@@ -0,0 +1,17 @@
using GameIdeas.Shared.Dto;
using GameIdeas.WebAPI.Services;
using Microsoft.AspNetCore.Mvc;
namespace GameIdeas.WebAPI.Controllers;
[ApiController]
[Route("api/[controller]")]
public class GameController(GameService gameService) : Controller
{
[HttpGet("Search")]
public async Task<IEnumerable<GameDto>> FetchGames([FromQuery] GameFilterDto filter)
{
return await gameService.SearchGames(filter);
}
}

View File

@@ -11,6 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">

View File

@@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace GameIdeas.WebAPI.Migrations namespace GameIdeas.WebAPI.Migrations
{ {
[DbContext(typeof(GameIdeasContext))] [DbContext(typeof(GameIdeasContext))]
[Migration("20250409210640_InitialCreate")] [Migration("20250409225125_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -176,7 +176,7 @@ namespace GameIdeas.WebAPI.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Libelle") b.Property<string>("Label")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");

View File

@@ -31,7 +31,7 @@ namespace GameIdeas.WebAPI.Migrations
{ {
Id = table.Column<int>(type: "integer", nullable: false) Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Libelle = table.Column<string>(type: "text", nullable: false) Label = table.Column<string>(type: "text", nullable: false)
}, },
constraints: table => constraints: table =>
{ {

View File

@@ -173,7 +173,7 @@ namespace GameIdeas.WebAPI.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Libelle") b.Property<string>("Label")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");

View File

@@ -0,0 +1,36 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Model;
namespace GameIdeas.WebAPI.Profiles;
public class CategoryProfile : Profile
{
public CategoryProfile()
{
CreateMap<Platform, PlatformDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Label, o => o.MapFrom(s => s.Label))
.ReverseMap();
CreateMap<Property, PropertyDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Label, o => o.MapFrom(s => s.Label))
.ReverseMap();
CreateMap<Tag, TagDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Label, o => o.MapFrom(s => s.Label))
.ReverseMap();
CreateMap<Developer, DeveloperDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Name, o => o.MapFrom(s => s.Name))
.ReverseMap();
CreateMap<Publisher, PublisherDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Name, o => o.MapFrom(s => s.Name))
.ReverseMap();
}
}

View File

@@ -0,0 +1,31 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Model;
namespace GameIdeas.WebAPI.Profiles;
public class GameProfile : Profile
{
public GameProfile()
{
CreateMap<Game, GameDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Title, o => o.MapFrom(s => s.Title))
.ForMember(d => d.ReleaseDate, o => o.MapFrom(s => s.ReleaseDate))
.ForMember(d => d.CreationDate, o => o.MapFrom(s => s.CreationDate))
.ForPath(d => d.CreationUser!.Id, o => o.MapFrom(s => s.CreationUserId))
.ForMember(d => d.CreationUser, o => o.MapFrom(s => s.CreationUser))
.ForMember(d => d.ModificationDate, o => o.MapFrom(s => s.ModificationDate))
.ForPath(d => d.ModificationUser!.Id, o => o.MapFrom(s => s.ModificationUserId))
.ForMember(d => d.ModificationUser, o => o.MapFrom(s => s.ModificationUser))
.ForMember(d => d.StorageSpace, o => o.MapFrom(s => s.StorageSpace))
.ForMember(d => d.Description, o => o.MapFrom(s => s.Description))
.ForMember(d => d.Interest, o => o.MapFrom(s => s.Interest))
.ForMember(d => d.Platforms, o => o.MapFrom(s => s.GamePlatforms.Select(p => new PlatformDto() { Id = p.Platform.Id, Label = p.Platform.Label, Url = p.Url })))
.ForMember(d => d.Properties, o => o.MapFrom(s => s.GameProperties.Select(p => p.Property)))
.ForMember(d => d.Tags, o => o.MapFrom(s => s.GameTags.Select(t => t.Tag)))
.ForMember(d => d.Publishers, o => o.MapFrom(s => s.GamePublishers.Select(p => p.Publisher)))
.ForMember(d => d.Developers, o => o.MapFrom(s => s.GameDevelopers.Select(gd => gd.Developer)))
.ReverseMap();
}
}

View File

@@ -0,0 +1,22 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Enum;
using GameIdeas.Shared.Model;
namespace GameIdeas.WebAPI.Profiles;
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<User, UserDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Username, o => o.MapFrom(s => s.Username))
.ForMember(d => d.Password, o => o.MapFrom(s => s.Password))
.ForMember(d => d.Role, o => o.MapFrom(s => s.Role))
.ForMember(d => d.CreationGames, o => o.MapFrom(s => s.CreationGames))
.ForMember(d => d.ModificationGames, o => o.MapFrom(s => s.ModificationGames))
.ReverseMap();
}
}

View File

@@ -1,5 +1,7 @@
using GameIdeas.Resources; using GameIdeas.Resources;
using GameIdeas.WebAPI.Context; using GameIdeas.WebAPI.Context;
using GameIdeas.WebAPI.Profiles;
using GameIdeas.WebAPI.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Data; using System.Data;
@@ -32,6 +34,12 @@ services.AddDbContext<GameIdeasContext>(dbContextOptions);
services.AddSingleton<TranslationService>(); services.AddSingleton<TranslationService>();
services.AddSingleton<Translations>(); services.AddSingleton<Translations>();
services.AddScoped<GameService>();
services.AddAutoMapper(typeof(GameProfile).Assembly);
services.AddAutoMapper(typeof(UserProfile).Assembly);
services.AddAutoMapper(typeof(CategoryProfile).Assembly);
services.AddControllers(); services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
services.AddOpenApi(); services.AddOpenApi();

View File

@@ -0,0 +1,60 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Enum;
using GameIdeas.Shared.Model;
using GameIdeas.WebAPI.Context;
using Microsoft.EntityFrameworkCore;
namespace GameIdeas.WebAPI.Services;
public class GameService(GameIdeasContext context, IMapper mapper)
{
public async Task<IEnumerable<GameDto>> SearchGames(GameFilterDto filter)
{
var query = context.Games
.Include(g => g.CreationUser)
.Include(g => g.ModificationUser)
.Include(g => g.GamePlatforms).ThenInclude(p => p.Platform)
.Include(g => g.GameProperties).ThenInclude(p => p.Property)
.Include(g => g.GameTags).ThenInclude(p => p.Tag)
.Include(g => g.GamePublishers).ThenInclude(p => p.Publisher)
.Include(g => g.GameDevelopers).ThenInclude(p => p.Developer)
.AsQueryable();
ApplyFilter(ref query);
var games = await query
.OrderBy(g => g.Title)
.Skip(filter.CurrentPage * filter.NumberPerPage)
.Take(filter.NumberPerPage)
.ToListAsync();
List<Game> gamesTest = [ new ()
{
Id = 1,
Title = "Test",
CreationDate = DateTime.Today - TimeSpan.FromHours(-12),
CreationUser = new User() { Id = 1, Username = "Test", Role = (int)Role.Administrator },
CreationUserId = 1,
Description = "Test",
GameDevelopers = [ new() { Developer = new Developer() { Id = 1, Name = "THQNordic"} }],
GamePlatforms = [ new() { Platform = new Platform() { Id = 1, Label = "Steam" }, Url = "steam.com?app=55554131" }],
GameProperties = [ new () { Property = new Property() { Id = 1, Label = "Coop"} }],
GamePublishers = [ new () { Publisher = new Publisher() { Id = 1, Name = "Take-Two"} }],
GameTags = [ new () { Tag = new Tag() { Id = 1, Label = "RPG" } }],
Interest = 5,
ModificationDate = DateTime.Today ,
ModificationUser = new User() { Id = 2, Username = "Test 2", Role = (int)Role.Member },
ModificationUserId = 2,
ReleaseDate = new DateTime(2025, 2, 1),
StorageSpace = 40
} ];
return mapper.Map<IEnumerable<GameDto>>(gamesTest);
}
private void ApplyFilter(ref IQueryable<Game> query)
{
}
}

View File

@@ -0,0 +1,5 @@
namespace GameIdeas.WebAPI.Services;
public class UserService
{
}