Get users and role and add user row
All checks were successful
Game Ideas build for PR / build_blazor_app (pull_request) Successful in 57s
All checks were successful
Game Ideas build for PR / build_blazor_app (pull_request) Successful in 57s
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
@using GameIdeas.BlazorApp.Shared.Components.Select
|
||||||
|
@using GameIdeas.BlazorApp.Shared.Components.Select.Models
|
||||||
|
@using GameIdeas.BlazorApp.Shared.Constants
|
||||||
|
@using GameIdeas.Shared.Dto
|
||||||
|
|
||||||
|
<EditForm EditContext="EditContext" OnSubmit="HandleSubmitClicked">
|
||||||
|
<div class="row">
|
||||||
|
<div class="icon">
|
||||||
|
@Icons.Account
|
||||||
|
</div>
|
||||||
|
<div class="name">
|
||||||
|
<input type="text" class="input-name" @bind="@User.Username" disabled="@CanEdit">
|
||||||
|
</div>
|
||||||
|
<div class="password">
|
||||||
|
<input type="password" class="input-password" placeholder="********" @bind="@User.Password" disabled="@CanEdit">
|
||||||
|
</div>
|
||||||
|
<div class="role">
|
||||||
|
<Select TItem="RoleDto" THeader="object" DisableClicked=!CanEdit Type="SelectType.Single"
|
||||||
|
Theme="SelectTheme.Creation" Values="Roles" ValuesChanged="HandleValuesChanged" Params="SelectRoleParams">
|
||||||
|
<span class="role-label">@(User.Role?.Name ?? ResourcesKey.Unknown)</span>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<button class="remove" @onclick="HandleRemoveClicked">@Icons.Bin</button>
|
||||||
|
@if (!CanEdit)
|
||||||
|
{
|
||||||
|
<button class="edit" @onclick="HandleEditClicked">@Icons.Pen</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="submit" class="submit">@Icons.Check</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
using GameIdeas.BlazorApp.Shared.Components.Select;
|
||||||
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.Users.Components;
|
||||||
|
|
||||||
|
public partial class UserRow
|
||||||
|
{
|
||||||
|
[Parameter] public UserDto User { get; set; } = new();
|
||||||
|
[Parameter] public List<RoleDto> Roles { get; set; } = [];
|
||||||
|
[Parameter] public bool CanEdit { get; set; } = false;
|
||||||
|
[Parameter] public EventCallback<UserDto> OnRemove { get; set; }
|
||||||
|
[Parameter] public EventCallback<UserDto> OnSubmit { get; set; }
|
||||||
|
|
||||||
|
private SelectParams<RoleDto, object> SelectRoleParams = new();
|
||||||
|
private EditContext? EditContext;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
EditContext = new(User);
|
||||||
|
base.OnInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
SelectRoleParams = new()
|
||||||
|
{
|
||||||
|
GetItemLabel = role => role.Name,
|
||||||
|
Items = Roles
|
||||||
|
};
|
||||||
|
|
||||||
|
base.OnParametersSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleValuesChanged(IEnumerable<RoleDto> roles)
|
||||||
|
{
|
||||||
|
User.Role = roles.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleSubmitClicked()
|
||||||
|
{
|
||||||
|
if (EditContext?.Validate() == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanEdit = false;
|
||||||
|
await OnSubmit.InvokeAsync(User);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void HandleEditClicked()
|
||||||
|
{
|
||||||
|
CanEdit = true;
|
||||||
|
}
|
||||||
|
private async Task HandleRemoveClicked()
|
||||||
|
{
|
||||||
|
await OnRemove.InvokeAsync(User);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
.row {
|
||||||
|
height: 64px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 48px 1fr 1fr 1fr auto;
|
||||||
|
grid-gap: 8px;
|
||||||
|
padding: 0 8px;
|
||||||
|
background: var(--input-secondary);
|
||||||
|
box-shadow: var(--drop-shadow);
|
||||||
|
border-radius: var(--big-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.row > * {
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using GameIdeas.Resources;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.Users.Components;
|
||||||
|
|
||||||
|
public class UserValidator : AbstractValidator<UserDto>
|
||||||
|
{
|
||||||
|
public UserValidator()
|
||||||
|
{
|
||||||
|
RuleFor(user => user.Username)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(ResourcesKey.MissingField);
|
||||||
|
|
||||||
|
RuleFor(user => user.Password)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(ResourcesKey.MissingField);
|
||||||
|
|
||||||
|
RuleFor(user => user.Role)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(ResourcesKey.MissingField);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
@page "/Users"
|
@page "/Users"
|
||||||
@using GameIdeas.BlazorApp.Pages.Games.Header
|
@using GameIdeas.BlazorApp.Pages.Games.Header
|
||||||
@using GameIdeas.BlazorApp.Layouts
|
@using GameIdeas.BlazorApp.Layouts
|
||||||
|
@using GameIdeas.BlazorApp.Pages.Users.Components
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.Popup
|
@using GameIdeas.BlazorApp.Shared.Components.Popup
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.Search
|
@using GameIdeas.BlazorApp.Shared.Components.Search
|
||||||
|
@using GameIdeas.BlazorApp.Shared.Components.Select.Models
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.SelectSearch
|
@using GameIdeas.BlazorApp.Shared.Components.SelectSearch
|
||||||
@using GameIdeas.Shared.Dto
|
@using GameIdeas.Shared.Dto
|
||||||
|
|
||||||
@@ -14,7 +16,7 @@
|
|||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<SearchInput Placeholder="@ResourcesKey.EnterUsername" @bind-Text="FilterParams.Name" />
|
<SearchInput Placeholder="@ResourcesKey.EnterUsername" @bind-Text="FilterParams.Name" />
|
||||||
<SelectSearch TItem="RoleDto" Placeholder="@ResourcesKey.Roles" @bind-Values="FilterParams.Roles"
|
<SelectSearch TItem="RoleDto" Placeholder="@ResourcesKey.Roles" @bind-Values="FilterParams.Roles"
|
||||||
Items="Roles.ToList()" GetLabel="@(role => role.Name)"/>
|
Items="Roles.ToList()" GetLabel="@(role => role.Name)" Theme="SelectTheme.Filter" />
|
||||||
</div>
|
</div>
|
||||||
</GameHeader>
|
</GameHeader>
|
||||||
|
|
||||||
@@ -24,7 +26,7 @@
|
|||||||
{
|
{
|
||||||
@foreach (var user in UserList.Users ?? [])
|
@foreach (var user in UserList.Users ?? [])
|
||||||
{
|
{
|
||||||
|
<UserRow User="user" Roles="Roles.ToList()" OnRemove="HandleRemoveUser" OnSubmit="HandleSubmitUser" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -34,7 +36,6 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -43,4 +43,12 @@ public partial class Users
|
|||||||
IsLoading = false;
|
IsLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private Task HandleSubmitUser(UserDto args)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
private Task HandleRemoveUser(UserDto args)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,3 +8,13 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 20px 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1000px) {
|
||||||
|
.container {
|
||||||
|
padding: 20px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Blazored.LocalStorage;
|
|||||||
using GameIdeas.BlazorApp;
|
using GameIdeas.BlazorApp;
|
||||||
using GameIdeas.BlazorApp.Pages.Games.Gateways;
|
using GameIdeas.BlazorApp.Pages.Games.Gateways;
|
||||||
using GameIdeas.BlazorApp.Pages.UserMenu.Gateways;
|
using GameIdeas.BlazorApp.Pages.UserMenu.Gateways;
|
||||||
|
using GameIdeas.BlazorApp.Pages.Users.Gateways;
|
||||||
using GameIdeas.BlazorApp.Services;
|
using GameIdeas.BlazorApp.Services;
|
||||||
using GameIdeas.Resources;
|
using GameIdeas.Resources;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
@@ -37,6 +38,7 @@ services.AddScoped<IHttpClientService, HttpClientService>();
|
|||||||
|
|
||||||
services.AddScoped<IAuthGateway, AuthGateway>();
|
services.AddScoped<IAuthGateway, AuthGateway>();
|
||||||
services.AddScoped<IGameGateway, GameGateway>();
|
services.AddScoped<IGameGateway, GameGateway>();
|
||||||
|
services.AddScoped<IUserGateway, UserGateway>();
|
||||||
|
|
||||||
services.AddSingleton<TranslationService>();
|
services.AddSingleton<TranslationService>();
|
||||||
services.AddSingleton<Translations>();
|
services.AddSingleton<Translations>();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
@typeparam TItem
|
@typeparam TItem
|
||||||
|
|
||||||
<Select @ref=Select TItem="TItem" THeader="string" Theme="Theme" Type="SelectType.Multiple"
|
<Select @ref=Select TItem="TItem" THeader="string" Theme="Theme" Type="SelectType"
|
||||||
Params="SelectParams" Values=Values ValuesChanged="HandleValuesChanged" QuickAdd=QuickAdd>
|
Params="SelectParams" Values=Values ValuesChanged="HandleValuesChanged" QuickAdd=QuickAdd>
|
||||||
|
|
||||||
<div class="@SelectHelper.GetClassFromTheme(Theme)">
|
<div class="@SelectHelper.GetClassFromTheme(Theme)">
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public partial class SelectSearch<TItem>
|
|||||||
[Parameter] public string Placeholder { get; set; } = string.Empty;
|
[Parameter] public string Placeholder { get; set; } = string.Empty;
|
||||||
[Parameter] public bool QuickAdd { get; set; } = false;
|
[Parameter] public bool QuickAdd { get; set; } = false;
|
||||||
[Parameter] public Func<string, TItem>? AddItem { get; set; }
|
[Parameter] public Func<string, TItem>? AddItem { get; set; }
|
||||||
|
[Parameter] public SelectType SelectType { get; set; } = SelectType.Multiple;
|
||||||
|
|
||||||
private SelectParams<TItem, string> SelectParams = new();
|
private SelectParams<TItem, string> SelectParams = new();
|
||||||
private SearchInput? SearchInput;
|
private SearchInput? SearchInput;
|
||||||
|
|||||||
@@ -27,4 +27,16 @@ public static class Icons
|
|||||||
public readonly static MarkupString Account = new(OpenBraket +
|
public readonly static MarkupString Account = new(OpenBraket +
|
||||||
"<path d=\"M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z\" />" +
|
"<path d=\"M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z\" />" +
|
||||||
CloseBraket);
|
CloseBraket);
|
||||||
|
|
||||||
|
public readonly static MarkupString Bin = new(OpenBraket +
|
||||||
|
"<path d=\"M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z\" />" +
|
||||||
|
CloseBraket);
|
||||||
|
|
||||||
|
public readonly static MarkupString Pen = new(OpenBraket +
|
||||||
|
"<path d=\"M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z\" />" +
|
||||||
|
CloseBraket);
|
||||||
|
|
||||||
|
public readonly static MarkupString Check = new(OpenBraket +
|
||||||
|
"<path d=\"M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z\" />" +
|
||||||
|
CloseBraket);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class Translations (TranslationService translationService)
|
|||||||
public string Roles => translationService.Translate(nameof(Roles));
|
public string Roles => translationService.Translate(nameof(Roles));
|
||||||
public string ErrorFetchUsers => translationService.Translate(nameof(ErrorFetchUsers));
|
public string ErrorFetchUsers => translationService.Translate(nameof(ErrorFetchUsers));
|
||||||
public string ErrorFetchRoles => translationService.Translate(nameof(ErrorFetchRoles));
|
public string ErrorFetchRoles => translationService.Translate(nameof(ErrorFetchRoles));
|
||||||
|
public string MissingField => translationService.Translate(nameof(MissingField));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ResourcesKey
|
public static class ResourcesKey
|
||||||
@@ -122,4 +123,5 @@ public static class ResourcesKey
|
|||||||
public static string Roles => _instance?.Roles ?? throw new InvalidOperationException("ResourcesKey.Roles is not initialized.");
|
public static string Roles => _instance?.Roles ?? throw new InvalidOperationException("ResourcesKey.Roles is not initialized.");
|
||||||
public static string ErrorFetchUsers => _instance?.ErrorFetchUsers ?? throw new InvalidOperationException("ResourcesKey.ErrorFetchUsers is not initialized.");
|
public static string ErrorFetchUsers => _instance?.ErrorFetchUsers ?? throw new InvalidOperationException("ResourcesKey.ErrorFetchUsers is not initialized.");
|
||||||
public static string ErrorFetchRoles => _instance?.ErrorFetchRoles ?? throw new InvalidOperationException("ResourcesKey.ErrorFetchRoles is not initialized.");
|
public static string ErrorFetchRoles => _instance?.ErrorFetchRoles ?? throw new InvalidOperationException("ResourcesKey.ErrorFetchRoles is not initialized.");
|
||||||
|
public static string MissingField => _instance?.MissingField ?? throw new InvalidOperationException("ResourcesKey.MissingField is not initialized.");
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ namespace GameIdeas.Shared.Dto;
|
|||||||
|
|
||||||
public class UserDto
|
public class UserDto
|
||||||
{
|
{
|
||||||
public int? Id { get; set; }
|
public string? Id { get; set; }
|
||||||
public string? Username { get; set; }
|
public string? Username { get; set; }
|
||||||
public string? Password { get; set; }
|
public string? Password { get; set; }
|
||||||
public RoleDto? Role { get; set; }
|
public RoleDto? Role { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Constants;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
using GameIdeas.WebAPI.Exceptions;
|
using GameIdeas.WebAPI.Exceptions;
|
||||||
using GameIdeas.WebAPI.Services.Users;
|
using GameIdeas.WebAPI.Services.Users;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace GameIdeas.WebAPI.Controllers;
|
namespace GameIdeas.WebAPI.Controllers;
|
||||||
@@ -36,4 +38,34 @@ public class UserController(
|
|||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = GlobalConstants.ADMINISTRATOR)]
|
||||||
|
[HttpGet("Roles")]
|
||||||
|
public async Task<ActionResult<IEnumerable<RoleDto>>> GetRoles()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await userService.GetRoles());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while get roles");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = GlobalConstants.ADMINISTRATOR)]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<UserListDto>> GetUsers([FromQuery] UserFilterDto filter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await userService.GetUsers(filter));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while get users");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,5 +52,6 @@
|
|||||||
"UserLogoutFailed": "Déconnection de l'utilisateur échoué",
|
"UserLogoutFailed": "Déconnection de l'utilisateur échoué",
|
||||||
"Roles": "Rôles",
|
"Roles": "Rôles",
|
||||||
"ErrorFetchUsers": "Erreur lors de la récupération des utilisateurs",
|
"ErrorFetchUsers": "Erreur lors de la récupération des utilisateurs",
|
||||||
"ErrorFetchRoles": "Erreur lors de la récupération des rôles"
|
"ErrorFetchRoles": "Erreur lors de la récupération des rôles",
|
||||||
|
"MissingField": "Un champs est manquant"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using GameIdeas.Shared.Model;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Profiles;
|
||||||
|
|
||||||
|
public class UserProfile : Profile
|
||||||
|
{
|
||||||
|
public UserProfile()
|
||||||
|
{
|
||||||
|
CreateMap<IdentityRole, RoleDto>()
|
||||||
|
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForMember(d => d.Name, o => o.MapFrom(s => s.Name));
|
||||||
|
|
||||||
|
CreateMap<User, UserDto>()
|
||||||
|
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
|
||||||
|
.ForMember(d => d.Username, o => o.MapFrom(s => s.UserName));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ public class GameReadService(GameIdeasContext context, IMapper mapper, ICategory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyFilter(ref IQueryable<Game> query, GameFilterDto filter)
|
private static void ApplyFilter(ref IQueryable<Game> query, GameFilterDto filter)
|
||||||
{
|
{
|
||||||
if (filter.PlatformIds != null)
|
if (filter.PlatformIds != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,4 +5,6 @@ namespace GameIdeas.WebAPI.Services.Users;
|
|||||||
public interface IUserService
|
public interface IUserService
|
||||||
{
|
{
|
||||||
Task<TokenDto> Login(UserDto user);
|
Task<TokenDto> Login(UserDto user);
|
||||||
|
Task<IEnumerable<RoleDto>> GetRoles();
|
||||||
|
Task<UserListDto> GetUsers(UserFilterDto filter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
using GameIdeas.Resources;
|
using AutoMapper;
|
||||||
|
using GameIdeas.Resources;
|
||||||
using GameIdeas.Shared.Constants;
|
using GameIdeas.Shared.Constants;
|
||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Dto;
|
||||||
using GameIdeas.Shared.Model;
|
using GameIdeas.Shared.Model;
|
||||||
|
using GameIdeas.WebAPI.Context;
|
||||||
using GameIdeas.WebAPI.Exceptions;
|
using GameIdeas.WebAPI.Exceptions;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
@@ -11,8 +14,95 @@ using System.Text;
|
|||||||
|
|
||||||
namespace GameIdeas.WebAPI.Services.Users;
|
namespace GameIdeas.WebAPI.Services.Users;
|
||||||
|
|
||||||
public class UserService(UserManager<User> userManager) : IUserService
|
public class UserService(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
GameIdeasContext context,
|
||||||
|
IMapper mapper) : IUserService
|
||||||
{
|
{
|
||||||
|
public async Task<IEnumerable<RoleDto>> GetRoles()
|
||||||
|
{
|
||||||
|
var roles = await context.Roles
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return mapper.Map<IEnumerable<RoleDto>>(roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UserListDto> GetUsers(UserFilterDto filter)
|
||||||
|
{
|
||||||
|
var users = await context.Users
|
||||||
|
.OrderBy(u => u.UserName)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var count = users.Count;
|
||||||
|
ApplyStaticFilter(ref users, filter);
|
||||||
|
|
||||||
|
var usersDto = mapper.Map<IEnumerable<UserDto>>(users);
|
||||||
|
usersDto = await ApplyRoles(usersDto, filter);
|
||||||
|
|
||||||
|
return new UserListDto
|
||||||
|
{
|
||||||
|
Users = usersDto,
|
||||||
|
UsersCount = count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<UserDto>> ApplyRoles(IEnumerable<UserDto> users, UserFilterDto filter)
|
||||||
|
{
|
||||||
|
var userRolesQuery = context.UserRoles
|
||||||
|
.Where(ur => users.Select(u => u.Id).Contains(ur.UserId))
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
|
var rolesQuery = context.Roles.AsQueryable();
|
||||||
|
|
||||||
|
if (filter.RoleIds != null)
|
||||||
|
{
|
||||||
|
userRolesQuery = userRolesQuery
|
||||||
|
.Where(ur => filter.RoleIds.Contains(ur.RoleId));
|
||||||
|
|
||||||
|
rolesQuery = rolesQuery.Where(role => filter.RoleIds.Contains(role.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
var roles = await rolesQuery.ToListAsync();
|
||||||
|
var userRoles = await userRolesQuery.ToListAsync();
|
||||||
|
users = users.Where(user => userRoles.Select(ur => ur.UserId).Contains(user.Id));
|
||||||
|
|
||||||
|
foreach (var user in users)
|
||||||
|
{
|
||||||
|
var currentRoleId = userRoles.FirstOrDefault(ur => ur.UserId == user.Id)?.RoleId;
|
||||||
|
|
||||||
|
if (currentRoleId == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentRole = roles.FirstOrDefault(r => r.Id == currentRoleId);
|
||||||
|
user.Role = mapper.Map<RoleDto>(currentRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyStaticFilter(ref List<User> users, UserFilterDto filter)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(filter.Name))
|
||||||
|
{
|
||||||
|
var keywords = filter.Name?
|
||||||
|
.Split([' '], StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(k => k.Trim())
|
||||||
|
.ToArray() ?? [];
|
||||||
|
|
||||||
|
users = users
|
||||||
|
.Where(user => keywords.All(
|
||||||
|
kw => user.UserName?.Contains(kw, StringComparison.OrdinalIgnoreCase) ?? true
|
||||||
|
))
|
||||||
|
.OrderBy(user => keywords.Min(kw =>
|
||||||
|
user.UserName?.IndexOf(kw, StringComparison.OrdinalIgnoreCase)
|
||||||
|
))
|
||||||
|
.ThenBy(user => user.UserName?.Length)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TokenDto> Login(UserDto userDto)
|
public async Task<TokenDto> Login(UserDto userDto)
|
||||||
{
|
{
|
||||||
if (userDto.Username == null || userDto.Password == null)
|
if (userDto.Username == null || userDto.Password == null)
|
||||||
|
|||||||
Reference in New Issue
Block a user