Add services and controllers for games (#12)
Co-authored-by: Maxime Adler <madler@sqli.com> Reviewed-on: #12
This commit was merged in pull request #12.
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
<PageTitle>@ResourcesKey.GamesIdeas</PageTitle>
|
<PageTitle>@ResourcesKey.GamesIdeas</PageTitle>
|
||||||
|
|
||||||
<GamesHeader>
|
<GameHeader>
|
||||||
<GameFilter @bind-DisplayType=DisplayType
|
<GameFilter @bind-DisplayType=DisplayType
|
||||||
@bind-GameFilterParams=GameFilterParams />
|
@bind-GameFilterParams=GameFilterParams />
|
||||||
</GamesHeader>
|
</GameHeader>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -3,7 +3,7 @@ using GameIdeas.BlazorApp.Shared.Models;
|
|||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Pages.Games;
|
namespace GameIdeas.BlazorApp.Pages.Games;
|
||||||
|
|
||||||
public partial class GamesBase ()
|
public partial class GameBase ()
|
||||||
{
|
{
|
||||||
private DisplayType DisplayType = DisplayType.List;
|
private DisplayType DisplayType = DisplayType.List;
|
||||||
private GameFilterParams GameFilterParams = new();
|
private GameFilterParams GameFilterParams = new();
|
||||||
@@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Components;
|
|||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Pages.Games.Header;
|
namespace GameIdeas.BlazorApp.Pages.Games.Header;
|
||||||
|
|
||||||
public partial class GamesHeader : ComponentBase
|
public partial class GameHeader : ComponentBase
|
||||||
{
|
{
|
||||||
[Parameter] public EventCallback<AddType> AddTypeChanged { get; set; }
|
[Parameter] public EventCallback<AddType> AddTypeChanged { get; set; }
|
||||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||||
7
src/GameIdeas/GameIdeas.Shared/Dto/DeveloperDto.cs
Normal file
7
src/GameIdeas/GameIdeas.Shared/Dto/DeveloperDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
public class DeveloperDto
|
||||||
|
{
|
||||||
|
public int? Id { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
@@ -2,6 +2,21 @@
|
|||||||
|
|
||||||
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 int? CreationUserId { get; set; }
|
||||||
|
public DateTime? ModificationDate { get; set; }
|
||||||
|
public UserDto? ModificationUser { get; set; }
|
||||||
|
public int? ModificationUserId { 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; }
|
||||||
}
|
}
|
||||||
16
src/GameIdeas/GameIdeas.Shared/Dto/GameFilterDto.cs
Normal file
16
src/GameIdeas/GameIdeas.Shared/Dto/GameFilterDto.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/GameIdeas/GameIdeas.Shared/Dto/PaggingDto.cs
Normal file
7
src/GameIdeas/GameIdeas.Shared/Dto/PaggingDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
public class PaggingDto
|
||||||
|
{
|
||||||
|
public int CurrentPage { get; set; }
|
||||||
|
public int NumberPerPage { get; set; }
|
||||||
|
}
|
||||||
8
src/GameIdeas/GameIdeas.Shared/Dto/PlatformDto.cs
Normal file
8
src/GameIdeas/GameIdeas.Shared/Dto/PlatformDto.cs
Normal 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; }
|
||||||
|
}
|
||||||
7
src/GameIdeas/GameIdeas.Shared/Dto/PropertyDto.cs
Normal file
7
src/GameIdeas/GameIdeas.Shared/Dto/PropertyDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
public class PropertyDto
|
||||||
|
{
|
||||||
|
public int? Id { get; set; }
|
||||||
|
public string? Label { get; set; }
|
||||||
|
}
|
||||||
7
src/GameIdeas/GameIdeas.Shared/Dto/PublisherDto.cs
Normal file
7
src/GameIdeas/GameIdeas.Shared/Dto/PublisherDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
public class PublisherDto
|
||||||
|
{
|
||||||
|
public int? Id { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
8
src/GameIdeas/GameIdeas.Shared/Dto/TagDto.cs
Normal file
8
src/GameIdeas/GameIdeas.Shared/Dto/TagDto.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
namespace GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
public class TagDto
|
||||||
|
{
|
||||||
|
public int? Id { get; set; }
|
||||||
|
public string? Label { get; set; }
|
||||||
|
}
|
||||||
11
src/GameIdeas/GameIdeas.Shared/Dto/UserDto.cs
Normal file
11
src/GameIdeas/GameIdeas.Shared/Dto/UserDto.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
8
src/GameIdeas/GameIdeas.Shared/Enum/Role.cs
Normal file
8
src/GameIdeas/GameIdeas.Shared/Enum/Role.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace GameIdeas.Shared.Enum;
|
||||||
|
|
||||||
|
public enum Role
|
||||||
|
{
|
||||||
|
Guest = 1,
|
||||||
|
Member = 2,
|
||||||
|
Administrator = 3
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace GameIdeas.Shared.Exceptions;
|
||||||
|
|
||||||
|
public class NotFoundException(string msg, Exception? innerException = null) : Exception(msg, innerException);
|
||||||
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ public class GameIdeasContext : DbContext
|
|||||||
{
|
{
|
||||||
public GameIdeasContext(DbContextOptions<GameIdeasContext> option)
|
public GameIdeasContext(DbContextOptions<GameIdeasContext> option)
|
||||||
: base(option)
|
: base(option)
|
||||||
{ }
|
{
|
||||||
|
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||||
|
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual DbSet<User> Users { get; set; } = null!;
|
public virtual DbSet<User> Users { get; set; } = null!;
|
||||||
public virtual DbSet<Developer> Developers { get; set; } = null!;
|
public virtual DbSet<Developer> Developers { get; set; } = null!;
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
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, ILoggerFactory loggerFactory) : Controller
|
||||||
|
{
|
||||||
|
private readonly ILogger<GameController> logger = loggerFactory.CreateLogger<GameController>();
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<IEnumerable<GameDto>>> SearchGames([FromQuery] PaggingDto pagging)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await gameService.GetGames(pagging));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while search games");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}")]
|
||||||
|
public async Task<ActionResult<GameDto>> GetGameById(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await gameService.GetGameById(id));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while get game with id {id}", id);
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("Create")]
|
||||||
|
public async Task<ActionResult<GameDto>> CreateGame([FromBody] GameDto game)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Created("/Create", await gameService.CreateGame(game));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while create game");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("Update")]
|
||||||
|
public async Task<ActionResult<GameDto>> UpdateGame([FromBody] GameDto game)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Created($"/Update", await gameService.UpdateGame(game));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while update game");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("Delete/{id:int}")]
|
||||||
|
public async Task<ActionResult<bool>> DeleteGame(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await gameService.DeleteGame(id));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while delete game");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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">
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
@@ -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 =>
|
||||||
{
|
{
|
||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using GameIdeas.Shared.Model;
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Profiles;
|
||||||
|
|
||||||
|
public class CategoryProfile : Profile
|
||||||
|
{
|
||||||
|
public CategoryProfile()
|
||||||
|
{
|
||||||
|
CreatePlaformMap();
|
||||||
|
CreatePropertyMap();
|
||||||
|
CreateTagMap();
|
||||||
|
CreateDeveloperMap();
|
||||||
|
CreatePublisherMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreatePublisherMap()
|
||||||
|
{
|
||||||
|
CreateMap<Publisher, PublisherDto>()
|
||||||
|
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForMember(d => d.Name, o => o.MapFrom(s => s.Name))
|
||||||
|
.ReverseMap();
|
||||||
|
|
||||||
|
CreateMap<PublisherDto, GamePublisher>()
|
||||||
|
.ForMember(d => d.PublisherId, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Publisher.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Publisher.Name, o => o.MapFrom(s => s.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateDeveloperMap()
|
||||||
|
{
|
||||||
|
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<DeveloperDto, GameDeveloper>()
|
||||||
|
.ForMember(d => d.DeveloperId, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Developer.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Developer.Name, o => o.MapFrom(s => s.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateTagMap()
|
||||||
|
{
|
||||||
|
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<TagDto, GameTag>()
|
||||||
|
.ForMember(d => d.TagId, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Tag.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Tag.Label, o => o.MapFrom(s => s.Label));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreatePropertyMap()
|
||||||
|
{
|
||||||
|
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<PropertyDto, GameProperty>()
|
||||||
|
.ForMember(d => d.PropertyId, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Property.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Property.Label, o => o.MapFrom(s => s.Label));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreatePlaformMap()
|
||||||
|
{
|
||||||
|
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<PlatformDto, GamePlatform>()
|
||||||
|
.ForMember(d => d.PlatformId, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Platform.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForPath(d => d.Platform.Label, o => o.MapFrom(s => s.Label))
|
||||||
|
.ForMember(d => d.Url, o => o.MapFrom(s => s.Url));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
.ForMember(d => d.CreationUserId, 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))
|
||||||
|
.ForMember(d => d.ModificationUserId, 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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))
|
||||||
|
.ReverseMap();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
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 System.Text.Json.Serialization;
|
||||||
using System.Data;
|
|
||||||
using System.Data.Common;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
var services = builder.Services;
|
var services = builder.Services;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Load("../../../../.env");
|
LoadEnvironmentVariable("../../../../.env");
|
||||||
#else
|
#else
|
||||||
Load(".env");
|
LoadEnvironmentVariable(".env");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Action<DbContextOptionsBuilder> dbContextOptions = options =>
|
Action<DbContextOptionsBuilder> dbContextOptions = options =>
|
||||||
@@ -22,8 +22,7 @@ Action<DbContextOptionsBuilder> dbContextOptions = options =>
|
|||||||
{
|
{
|
||||||
npgOption.CommandTimeout(60);
|
npgOption.CommandTimeout(60);
|
||||||
npgOption.MigrationsAssembly("GameIdeas.WebAPI");
|
npgOption.MigrationsAssembly("GameIdeas.WebAPI");
|
||||||
})
|
});
|
||||||
.LogTo(Console.WriteLine);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
@@ -32,7 +31,14 @@ 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();
|
||||||
|
|
||||||
@@ -40,6 +46,7 @@ services.AddCors(option => option.AddDefaultPolicy(policy =>
|
|||||||
policy.WithOrigins("http://localhost:5172", "http://localhost:7060")
|
policy.WithOrigins("http://localhost:5172", "http://localhost:7060")
|
||||||
.AllowAnyHeader()
|
.AllowAnyHeader()
|
||||||
.WithMethods("GET", "POST", "PUT", "DELETE")));
|
.WithMethods("GET", "POST", "PUT", "DELETE")));
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
await LoadTranslations();
|
await LoadTranslations();
|
||||||
@@ -85,7 +92,7 @@ string GetConnectionString()
|
|||||||
return $"Host={host};Username={login};Password={pass};Database={database}";
|
return $"Host={host};Username={login};Password={pass};Database={database}";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Load(string filePath)
|
static void LoadEnvironmentVariable(string filePath)
|
||||||
{
|
{
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
return;
|
return;
|
||||||
|
|||||||
174
src/GameIdeas/Server/GameIdeas.WebAPI/Services/GameService.cs
Normal file
174
src/GameIdeas/Server/GameIdeas.WebAPI/Services/GameService.cs
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using GameIdeas.Shared.Exceptions;
|
||||||
|
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>> GetGames(PaggingDto pagging)
|
||||||
|
{
|
||||||
|
var games = await SelectGames()
|
||||||
|
.OrderBy(g => g.Title)
|
||||||
|
.Skip((pagging.CurrentPage - 1) * pagging.NumberPerPage)
|
||||||
|
.Take(pagging.NumberPerPage)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return mapper.Map<IEnumerable<GameDto>>(games);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GameDto> GetGameById(int gameId)
|
||||||
|
{
|
||||||
|
var game = await SelectGames()
|
||||||
|
.FirstOrDefaultAsync(g => g.Id == gameId);
|
||||||
|
|
||||||
|
return game == null
|
||||||
|
? throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameId} has not been found in context")
|
||||||
|
: mapper.Map<GameDto>(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GameDto> CreateGame(GameDto gameDto)
|
||||||
|
{
|
||||||
|
var gameToCreate = mapper.Map<Game>(gameDto);
|
||||||
|
|
||||||
|
await context.Games.AddAsync(gameToCreate);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
await HandlePlatformsCreation(gameDto.Platforms, gameToCreate.Id);
|
||||||
|
await HandlePropertiesCreation(gameDto.Properties, gameToCreate.Id);
|
||||||
|
await HandleTagsCreation(gameDto.Tags, gameToCreate.Id);
|
||||||
|
await HandlePublishersCreation(gameDto.Publishers, gameToCreate.Id);
|
||||||
|
await HandleDevelopersCreation(gameDto.Developers, gameToCreate.Id);
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return mapper.Map<GameDto>(gameToCreate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GameDto> UpdateGame(GameDto gameDto)
|
||||||
|
{
|
||||||
|
if (await context.Games.CountAsync(g => g.Id == gameDto.Id) == 0)
|
||||||
|
{
|
||||||
|
throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameDto.Id} has not been found in context");
|
||||||
|
}
|
||||||
|
|
||||||
|
var gameToUpdate = mapper.Map<Game>(gameDto);
|
||||||
|
|
||||||
|
await HandlePlatformsCreation(gameDto.Platforms, gameToUpdate.Id);
|
||||||
|
await HandlePropertiesCreation(gameDto.Properties, gameToUpdate.Id);
|
||||||
|
await HandleTagsCreation(gameDto.Tags, gameToUpdate.Id);
|
||||||
|
await HandlePublishersCreation(gameDto.Publishers, gameToUpdate.Id);
|
||||||
|
await HandleDevelopersCreation(gameDto.Developers, gameToUpdate.Id);
|
||||||
|
|
||||||
|
context.Games.Update(gameToUpdate);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return mapper.Map<GameDto>(gameToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DeleteGame(int gameId)
|
||||||
|
{
|
||||||
|
var gameToRemove = await context.Games
|
||||||
|
.FirstOrDefaultAsync(g => g.Id == gameId)
|
||||||
|
?? throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameId} has not been found in context");
|
||||||
|
|
||||||
|
context.Games.Remove(gameToRemove);
|
||||||
|
return await context.SaveChangesAsync() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQueryable<Game> SelectGames()
|
||||||
|
{
|
||||||
|
return 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandlePlatformsCreation(IEnumerable<PlatformDto>? categoriesToCreate, int gameId)
|
||||||
|
{
|
||||||
|
if (categoriesToCreate != null)
|
||||||
|
{
|
||||||
|
var gps = mapper.Map<ICollection<GamePlatform>>(categoriesToCreate);
|
||||||
|
|
||||||
|
foreach (var gp in gps)
|
||||||
|
{
|
||||||
|
gp.GameId = gameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Platforms.AttachRange(gps.Select(gp => gp.Platform));
|
||||||
|
await context.GamePlatforms.AddRangeAsync(gps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandlePropertiesCreation(IEnumerable<PropertyDto>? categoriesToCreate, int gameId)
|
||||||
|
{
|
||||||
|
if (categoriesToCreate != null)
|
||||||
|
{
|
||||||
|
var gps = mapper.Map<ICollection<GameProperty>>(categoriesToCreate);
|
||||||
|
|
||||||
|
foreach (var gp in gps)
|
||||||
|
{
|
||||||
|
gp.GameId = gameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Properties.AttachRange(gps.Select(gp => gp.Property));
|
||||||
|
await context.GameProperties.AddRangeAsync(gps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleTagsCreation(IEnumerable<TagDto>? categoriesToCreate, int gameId)
|
||||||
|
{
|
||||||
|
if (categoriesToCreate != null)
|
||||||
|
{
|
||||||
|
var gts = mapper.Map<ICollection<GameTag>>(categoriesToCreate);
|
||||||
|
|
||||||
|
foreach (var gt in gts)
|
||||||
|
{
|
||||||
|
gt.GameId = gameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Tags.AttachRange(gts.Select(gt => gt.Tag));
|
||||||
|
await context.GameTags.AddRangeAsync(gts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandlePublishersCreation(IEnumerable<PublisherDto>? categoriesToCreate, int gameId)
|
||||||
|
{
|
||||||
|
if (categoriesToCreate != null)
|
||||||
|
{
|
||||||
|
var gps = mapper.Map<ICollection<GamePublisher>>(categoriesToCreate);
|
||||||
|
|
||||||
|
foreach (var gp in gps)
|
||||||
|
{
|
||||||
|
gp.GameId = gameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Publishers.AttachRange(gps.Select(gp => gp.Publisher));
|
||||||
|
await context.GamePublishers.AddRangeAsync(gps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleDevelopersCreation(IEnumerable<DeveloperDto>? categoriesToCreate, int gameId)
|
||||||
|
{
|
||||||
|
if (categoriesToCreate != null)
|
||||||
|
{
|
||||||
|
var gds = mapper.Map<ICollection<GameDeveloper>>(categoriesToCreate);
|
||||||
|
|
||||||
|
foreach (var gd in gds)
|
||||||
|
{
|
||||||
|
gd.GameId = gameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Developers.AttachRange(gds.Select(gd => gd.Developer));
|
||||||
|
await context.GameDevelopers.AddRangeAsync(gds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
namespace GameIdeas.WebAPI.Services;
|
||||||
|
|
||||||
|
public class UserService
|
||||||
|
{
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user