diff --git a/Blazing.Api/Controllers/Category/CategoryController.cs b/Blazing.Api/Controllers/Category/CategoryController.cs index 071e5c8..6852e92 100644 --- a/Blazing.Api/Controllers/Category/CategoryController.cs +++ b/Blazing.Api/Controllers/Category/CategoryController.cs @@ -1,5 +1,5 @@ using Blazing.Application.Dto; -using Blazing.Ecommerce.Repository; +using Blazing.Ecommerce.Interface; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -14,7 +14,6 @@ public class CategoryController(ILogger logger, ICategoryInf private readonly ILogger _logger = logger; private readonly ICategoryInfrastructureRepository _categoriaRepository = categoriaRepository; - /// /// Adds a list of new categories. /// @@ -59,7 +58,7 @@ public class CategoryController(ILogger logger, ICategoryInf /// List of category DTOs to delete. [Authorize] [HttpDelete("delete")] - public async Task> DeleteCategories(IEnumerable id, CancellationToken cancellationToken) + public async Task> DeleteCategories([FromQuery]IEnumerable id, CancellationToken cancellationToken) { var categoriesDeleted = await _categoriaRepository.DeleteCategory(id, cancellationToken); @@ -92,9 +91,13 @@ public async Task> GetCategoryById([FromQuery] IEnumer /// List of category DTOs. [Authorize] [HttpGet] - public async Task>> GetAllCategories(CancellationToken cancellationToken) + public async Task>> GetAllCategories([FromQuery]int page, int pageSize, CancellationToken cancellationToken) { - var categories = await _categoriaRepository.GetAll(cancellationToken); + if (pageSize > 50) + { + pageSize = 50; + } + var categories = await _categoriaRepository.GetAll(page, pageSize,cancellationToken); _logger.LogInformation("Categoria recuperados com sucesso. Total de categorias: {TotalCategories}", categories.Count()); diff --git a/Blazing.Api/Controllers/Product/ProductController.cs b/Blazing.Api/Controllers/Product/ProductController.cs index a843f2d..60cb847 100644 --- a/Blazing.Api/Controllers/Product/ProductController.cs +++ b/Blazing.Api/Controllers/Product/ProductController.cs @@ -1,8 +1,8 @@ using Blazing.Application.Dto; -using Blazing.Ecommerce.Repository; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Net; +using Blazing.Ecommerce.Interface; namespace Blazing.Api.Controllers.Product { @@ -15,7 +15,7 @@ namespace Blazing.Api.Controllers.Product /// This class requires an instance of ILogger and IProductAppService to be passed in the constructor. /// /// The type of the logger. - /// The type of the product infrastructure service. + /// The type of the product infrastructure service. [Route("api/[controller]")] [ApiController] public class ProductController(ILogger logger, IProductInfrastructureRepository produtoRepository) : ControllerBase @@ -103,8 +103,8 @@ public async Task>> DeleteProducts([FromBod /// the identifier of the productDto. /// productDto. [Authorize] - [HttpGet("productId")] - public async Task>> GetProductById([FromQuery] IEnumerable id, CancellationToken cancellationToken) + [HttpGet("id")] + public async Task>> GetProductById([FromQuery]IEnumerable id, CancellationToken cancellationToken) { var productsById = await _productInfraRepository.GetProductById(id, cancellationToken); @@ -122,6 +122,10 @@ public async Task>> DeleteProducts([FromBod [HttpGet] public async Task>> GetAll([FromQuery]int page, int pageSize, CancellationToken cancellationToken) { + if (pageSize > 50) + pageSize = 50; + + var products = await _productInfraRepository.GetAll(page, pageSize, cancellationToken); _logger.LogInformation("Produtos recuperados com sucesso. Total de produtos: {TotalProducts}.", diff --git a/Blazing.Api/Controllers/User/RoleController.cs b/Blazing.Api/Controllers/User/RoleController.cs new file mode 100644 index 0000000..d2b0f28 --- /dev/null +++ b/Blazing.Api/Controllers/User/RoleController.cs @@ -0,0 +1,42 @@ +using Blazing.Identity.Dto; +using Blazing.Identity.Interface; +using Blazing.Identity.Repository; +using Microsoft.AspNetCore.Mvc; + +namespace Blazing.Api.Controllers.User +{ + [ApiController] + [Route("api/[controller]")] + public class RoleController(ILogger logger,IRoleInfrastructureRepository roleInfrastructureRepository) : ControllerBase + { + private readonly ILogger _logger = logger; + private readonly IRoleInfrastructureRepository _roleInfrastructureRepository = roleInfrastructureRepository; + + [HttpPost] + public async Task AddRole(IEnumerable roleDto, + CancellationToken cancellationToken) + { + var result = await _roleInfrastructureRepository.Add(roleDto, cancellationToken); + _logger.LogInformation("Funções adicionadas com sucesso. Total adicionado: {result}", result.Count()); + return Ok(result); + } + + [HttpPut("Update")] + public async Task UpdateRole(IEnumerable roleDto, + CancellationToken cancellationToken) + { + var id = roleDto.Select(r => r.Id).AsEnumerable(); + var result = await _roleInfrastructureRepository.Update(id ,roleDto, cancellationToken); + _logger.LogInformation("Funções atualizadas com sucesso. Total atualizado: {result}", result.Count()); + return Ok(result); + } + + [HttpGet] + public async Task>> GetAllRole(int page, int pageSize, CancellationToken cancellationToken) + { + var result = await _roleInfrastructureRepository.GetAll(page, pageSize, cancellationToken); + _logger.LogInformation("Funções recuperadas com sucesso. Total recuperado: {result}", result.Count()); + return Ok(result); + } + } +} diff --git a/Blazing.Api/Controllers/User/UserController.cs b/Blazing.Api/Controllers/User/UserController.cs index 45777d9..e2b840e 100644 --- a/Blazing.Api/Controllers/User/UserController.cs +++ b/Blazing.Api/Controllers/User/UserController.cs @@ -1,6 +1,7 @@ using Blazing.Application.Dto; using Blazing.Domain.Exceptions.User; using Blazing.Identity.Entities; +using Blazing.Identity.Interface; using Blazing.Identity.Repository; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; @@ -102,8 +103,8 @@ public async Task DeleteUsers(IEnumerable id, /// This method requires the user to be authenticated. /// [Authorize] - [HttpGet("Id")] - public async Task> GetUserById(IEnumerable id, + [HttpGet("id")] + public async Task> GetUserById([FromQuery]IEnumerable id, CancellationToken cancellationToken) { var result = await _userInfrastructureRepository.GetUsersByIdAsync(id, cancellationToken); @@ -120,14 +121,19 @@ public async Task> GetUserById(IEnumerable id, /// /// Retrieves all users from the database. /// + /// /// A cancellation token to cancel the operation. + /// /// An asynchronous task that represents the operation. The task result contains an action result indicating the success of the operation. /// The result contains a list of all users. [Authorize] [HttpGet] - public async Task> GetAllUser(CancellationToken cancellationToken) + public async Task> GetAllUser([FromQuery]int page, int pageSize, CancellationToken cancellationToken) { - var result = await _userInfrastructureRepository.GetAllUsersAsync(cancellationToken); + if (pageSize > 50) + pageSize = 50; + + var result = await _userInfrastructureRepository.GetAllUsersAsync(page, pageSize, cancellationToken); _logger.LogInformation("A recuperação dos usuários foi realizada com sucesso. Total Usuários: {TotalUsuários}", result.Count()); @@ -138,7 +144,7 @@ public async Task> GetAllUser(CancellationToken ca /// /// Asynchronously handles the login request. /// - /// The email of the user. + /// The email of the user. /// The password of the user. /// A boolean indicating whether the user wants to be remembered. /// The cancellation token. @@ -155,43 +161,42 @@ public async Task> LoginAsync(Login login, switch (result) { case { Succeeded: true }: - if (!string.IsNullOrEmpty(login.Email) && login.Email.Contains("@")) + if (!string.IsNullOrEmpty(login.LoginIdentifier) && login.LoginIdentifier.Contains("@")) { - _logger.LogInformation("O login foi realizado com sucesso. E-mail: {email}", login.Email); + _logger.LogInformation("O login foi realizado com sucesso. E-mail: {email}", login.LoginIdentifier); return Ok(new { status = "success", message = "Login bem-sucedido." }); } else { - _logger.LogInformation("O login foi realizado com sucesso. Nome do usuário: {userName}", login.Email); + _logger.LogInformation("O login foi realizado com sucesso. Nome do usuário: {userName}", login.LoginIdentifier ); return Ok(new { status = "success", message = "Login bem-sucedido." }); } case { IsNotAllowed: true }: - _logger.LogWarning("Tentativa de login falhou. O login não é permitido para este usuário. E-mail: {email}", login.Email); + _logger.LogWarning("Tentativa de login falhou. O login não é permitido para este usuário. E-mail: {email}", login.LoginIdentifier ); return Unauthorized(new { status = "error", message = "Login não permitido para este usuário." }); case { RequiresTwoFactor: true }: - _logger.LogInformation("Tentativa de login requer autenticação de dois fatores. E-mail: {email}", login.Email); + _logger.LogInformation("Tentativa de login requer autenticação de dois fatores. E-mail: {email}", login.LoginIdentifier ); return Unauthorized(new { status = "2fa_required", message = "Autenticação de dois fatores é necessária." }); case { Succeeded: false }: - if (!string.IsNullOrEmpty(login.Email) && login.Email.Contains("@")) + if (!string.IsNullOrEmpty(login.LoginIdentifier ) && login.LoginIdentifier .Contains("@")) { - _logger.LogWarning("Tentativa de login falhou. Credenciais inválidas. E-mail: {email}", login.Email); + _logger.LogWarning("Tentativa de login falhou. Credenciais inválidas. E-mail: {email}", login.LoginIdentifier ); return Unauthorized(new { status = "error", message = "Credenciais inválidas." }); } else { - _logger.LogWarning("Tentativa de login falhou. Credenciais inválidas. Nome do usuário: {email}", login.Email); + _logger.LogWarning("Tentativa de login falhou. Credenciais inválidas. Nome do usuário: {email}", login.LoginIdentifier ); return Unauthorized(new { status = "error", message = "Credenciais inválidas." }); } default: - _logger.LogWarning("Falha no login. Credenciais inválidas. E-mail: {email}", login.Email); + _logger.LogWarning("Falha no login. Credenciais inválidas. E-mail: {email}", login.LoginIdentifier ); return Unauthorized(new { status = "error", message = "Credenciais inválidas." }); } - } /// diff --git a/Blazing.Api/Dependencies/ConfigServiceCollectionExtensionsAPi.cs b/Blazing.Api/Dependencies/ConfigServiceCollectionExtensionsAPi.cs new file mode 100644 index 0000000..e12fa39 --- /dev/null +++ b/Blazing.Api/Dependencies/ConfigServiceCollectionExtensionsAPi.cs @@ -0,0 +1,28 @@ +using Blazing.Application.Dto; +using Blazing.Application.Mappings; +using Blazing.Application.Services; +using Blazing.Domain.Entities; +using Blazing.Domain.Interfaces.Services; +using Blazing.Domain.Services; +using Blazing.Ecommerce.Data; +using Blazing.Identity.Data; +using Microsoft.EntityFrameworkCore; +using System.Text.Json; +using System.Text.Json.Serialization; + + +namespace Blazing.Api.Dependencies +{ + public static class ConfigServiceCollectionExtensionsAPi + { + public static IServiceCollection AddConfigApi( + this IServiceCollection services, IConfiguration config) + { + services.AddAutoMapper(typeof(BlazingProfile)); + + services.AddSwaggerGen(); + + return services; + } + } +} diff --git a/Blazing.Api/Dependencies/ConfigServiceCollectionExtensiosApi.cs b/Blazing.Api/Dependencies/ConfigServiceCollectionExtensiosApi.cs deleted file mode 100644 index e2e3f37..0000000 --- a/Blazing.Api/Dependencies/ConfigServiceCollectionExtensiosApi.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Blazing.Application.Dto; -using Blazing.Application.Interfaces.Category; -using Blazing.Application.Interfaces.Product; -using Blazing.Application.Mappings; -using Blazing.Application.Services; -using Blazing.Domain.Entities; -using Blazing.Domain.Interfaces.Services; -using Blazing.Domain.Services; -using Blazing.Ecommerce.Data; -using Blazing.Ecommerce.Repository; -using Blazing.Ecommerce.Service; -using Blazing.Identity.Data; -using Microsoft.EntityFrameworkCore; -using System.Text.Json; -using System.Text.Json.Serialization; - - -namespace Blazing.Api.Dependencies -{ - public static class ConfigServiceCollectionExtensiosAPi - { - public static IServiceCollection AddConfigApi( - this IServiceCollection Services, IConfiguration Config) - { - //Context Identity - Services.AddAutoMapper(typeof(BlazingProfile)); - - Services.AddSwaggerGen(); - - - JsonSerializerOptions options = new() - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault - }; - - return Services; - } - } -} diff --git a/Blazing.Api/Program.cs b/Blazing.Api/Program.cs index d221600..f3b432c 100644 --- a/Blazing.Api/Program.cs +++ b/Blazing.Api/Program.cs @@ -8,6 +8,7 @@ using Microsoft.Identity.Web; using Serilog; using System.Text.Json.Serialization; +using Blazing.Ecommerce.Dependencies; var builder = WebApplication.CreateBuilder(args); diff --git a/Blazing.Api/appsettings.json b/Blazing.Api/appsettings.json index d7c55a1..54b31b3 100644 --- a/Blazing.Api/appsettings.json +++ b/Blazing.Api/appsettings.json @@ -5,7 +5,7 @@ before the project can be successfully executed. For more info see https://aka.ms/dotnet-template-ms-identity-platform */ "ConnectionStrings": { - "Blazing": "Server=host.docker.internal,1200;Database=Blazing;User Id=sa;Password=019Uf%HG0!{;TrustServerCertificate=True" + "Blazing": "Server=192.168.0.10,1200;Database=Blazing;User Id=sa;Password=019Uf%HG0!{;TrustServerCertificate=True" }, "AzureAd": { @@ -44,13 +44,13 @@ For more info see https://aka.ms/dotnet-template-ms-identity-platform "path": "./Logs/log-development-.json", "rollingInterval": "Day", "rollOnFileSizeLimit": true, - //"formatter": "Blazing.Api.FormatterLogs.CompactJsonFormatter, Blazing.Api" + "formatter": "Blazing.Api.FormatterLogs.CompactJsonFormatter, Blazing.Api" } }, { "Name": "MSSqlServer", "Args": { - "connectionString": "Server=host.docker.internal,1200;Database=BlazingLogs;User Id=sa;Password=019Uf%HG0!{;TrustServerCertificate=True;", + "connectionString": "Server=192.168.0.10,1200;Database=BlazingLogs;User Id=sa;Password=019Uf%HG0!{;TrustServerCertificate=True;", "tableName": "Logs", "autoCreateSqlTable": true, "restrictedToMinimumLevel": "Error", diff --git a/Blazing.Application/Repository/Category/ICategoryAppService.cs b/Blazing.Application/Interface/Category/ICategoryAppService.cs similarity index 92% rename from Blazing.Application/Repository/Category/ICategoryAppService.cs rename to Blazing.Application/Interface/Category/ICategoryAppService.cs index cbbf771..8d316b5 100644 --- a/Blazing.Application/Repository/Category/ICategoryAppService.cs +++ b/Blazing.Application/Interface/Category/ICategoryAppService.cs @@ -1,11 +1,6 @@ using Blazing.Application.Dto; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Blazing.Application.Interfaces.Category +namespace Blazing.Application.Interface.Category { #region Interface Category App Service public interface ICategoryAppService where T : BaseEntityDto @@ -50,7 +45,10 @@ public interface ICategoryAppService where T : BaseEntityDto /// /// A boolean flag indicating whether to check for the existence of categoriesDto. /// A boolean flag indicating whether to check for the existence of categoriesDto. - Task ExistsCategories(bool id, bool nameExists, IEnumerable categoryDto, CancellationToken cancellationToken); + /// + /// + Task ExistsCategories(bool id, bool nameExists, IEnumerable categoryDto, + CancellationToken cancellationToken); } #endregion } diff --git a/Blazing.Application/Repository/Product/IProductAppService.cs b/Blazing.Application/Interface/Product/IProductAppService.cs similarity index 97% rename from Blazing.Application/Repository/Product/IProductAppService.cs rename to Blazing.Application/Interface/Product/IProductAppService.cs index 186b860..46a3711 100644 --- a/Blazing.Application/Repository/Product/IProductAppService.cs +++ b/Blazing.Application/Interface/Product/IProductAppService.cs @@ -1,8 +1,6 @@ using Blazing.Application.Dto; -using Blazing.Domain.Entities; -using System.Xml.Linq; -namespace Blazing.Application.Interfaces.Product +namespace Blazing.Application.Interface.Product { #region Interface product App Service. /// diff --git a/Blazing.Application/Repository/User/IUserAppService.cs b/Blazing.Application/Interface/User/IUserAppService.cs similarity index 83% rename from Blazing.Application/Repository/User/IUserAppService.cs rename to Blazing.Application/Interface/User/IUserAppService.cs index 6258ea0..f056488 100644 --- a/Blazing.Application/Repository/User/IUserAppService.cs +++ b/Blazing.Application/Interface/User/IUserAppService.cs @@ -1,12 +1,6 @@ using Blazing.Application.Dto; -using Blazing.Domain.Entities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Blazing.Application.Interfaces.User +namespace Blazing.Application.Interface.User { public interface IUserAppService where T : BaseEntityDto { @@ -22,15 +16,21 @@ public interface IUserAppService where T : BaseEntityDto /// /// The ID of the userDto to be updated. /// The updated userDto details. + /// + /// /// A task representing the asynchronous operation, with the updated userDto. - Task> UpdateUsers(IEnumerable id, IEnumerable userDto, IEnumerable productDtosUpdate, CancellationToken cancellationToken); + Task> UpdateUsers(IEnumerable id, IEnumerable userDto, + IEnumerable productDtosUpdate, CancellationToken cancellationToken); /// /// Deletes a collection of userDto by their IDs. /// /// A collection of userDto IDs to be deleted. + /// + /// /// A task representing the asynchronous operation, with a collection of the deleted userDto. - Task> DeleteUsers(IEnumerable id, IEnumerable userDto, CancellationToken cancellationToken); + Task> DeleteUsers(IEnumerable id, IEnumerable userDto, + CancellationToken cancellationToken); /// /// Retrieves a userDto by its ID. diff --git a/Blazing.Application/Services/CategoryAppService.cs b/Blazing.Application/Services/CategoryAppService.cs index cce631f..80c5a43 100644 --- a/Blazing.Application/Services/CategoryAppService.cs +++ b/Blazing.Application/Services/CategoryAppService.cs @@ -1,6 +1,5 @@ using AutoMapper; using Blazing.Application.Dto; -using Blazing.Application.Interfaces.Category; using Blazing.Domain.Entities; using Blazing.Domain.Interfaces.Repository; using Blazing.Domain.Interfaces.Services; @@ -10,6 +9,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Blazing.Application.Interface.Category; namespace Blazing.Application.Services { @@ -101,8 +101,12 @@ public class CategoryAppService(ICrudDomainService categoriasDomainSer /// /// Checks if categories exist based on the provided flag. /// + /// + /// /// A boolean flag indicating the existence check. - public async Task ExistsCategories(bool id, bool existsName, IEnumerable categoryDto, CancellationToken cancellationToken) + /// + public async Task ExistsCategories(bool id, bool existsName, IEnumerable categoryDto, + CancellationToken cancellationToken) { var category = _mapper.Map>(categoryDto); await _categoriaDomainService.ExistsAsync(id, existsName, category, cancellationToken); diff --git a/Blazing.Application/Services/ProductAppService.cs b/Blazing.Application/Services/ProductAppService.cs index 6779e04..3a40fc8 100644 --- a/Blazing.Application/Services/ProductAppService.cs +++ b/Blazing.Application/Services/ProductAppService.cs @@ -1,6 +1,6 @@ using AutoMapper; using Blazing.Application.Dto; -using Blazing.Application.Interfaces.Product; +using Blazing.Application.Interface.Product; using Blazing.Domain.Entities; using Blazing.Domain.Interfaces.Services; diff --git a/Blazing.Application/Services/UserAppService.cs b/Blazing.Application/Services/UserAppService.cs index e11a1d9..555628f 100644 --- a/Blazing.Application/Services/UserAppService.cs +++ b/Blazing.Application/Services/UserAppService.cs @@ -1,6 +1,6 @@ using AutoMapper; using Blazing.Application.Dto; -using Blazing.Application.Interfaces.User; +using Blazing.Application.Interface.User; using Blazing.Domain.Entities; using Blazing.Domain.Interfaces.Services; using Blazing.Domain.Interfaces.Services.User; @@ -34,8 +34,11 @@ public class UserAppService(IMapper mapper, IUserDomainService userDomainService /// /// The ID of the userDto to update. /// The userDto object containing the updated data. + /// + /// /// The updated userDto, if found. - public async Task> UpdateUsers(IEnumerable id, IEnumerable usersDto, IEnumerable usersDtoUpdate, CancellationToken cancellationToken) + public async Task> UpdateUsers(IEnumerable id, IEnumerable usersDto, + IEnumerable usersDtoUpdate, CancellationToken cancellationToken) { var users = _mapper.Map>(usersDto); var userUpdate = _mapper.Map>(usersDtoUpdate); @@ -51,8 +54,11 @@ public class UserAppService(IMapper mapper, IUserDomainService userDomainService /// Deletes UserDto based on a list of provided IDs. /// /// The list of UserDto IDs to be deleted. + /// + /// /// The list of UserDto that were deleted. - public async Task> DeleteUsers(IEnumerable id, IEnumerable usersDto, CancellationToken cancellationToken) + public async Task> DeleteUsers(IEnumerable id, IEnumerable usersDto, + CancellationToken cancellationToken) { var users = _mapper.Map>(usersDto); @@ -96,7 +102,11 @@ public class UserAppService(IMapper mapper, IUserDomainService userDomainService /// /// Checks if UserDto exist based on the provided flag. /// - /// A boolean flag indicating the existence check. + /// A boolean flag indicating the existence check. + /// + /// + /// + /// public async Task ExistsUsers(bool id, bool existsName, bool existsEmail, IEnumerable userDto, CancellationToken cancellationToken) { var users = _mapper.Map>(userDto); diff --git a/Blazing.Domain/Exceptions/Product/ProductException.cs b/Blazing.Domain/Exceptions/Product/ProductException.cs index 6d5aea3..ff8cda5 100644 --- a/Blazing.Domain/Exceptions/Product/ProductException.cs +++ b/Blazing.Domain/Exceptions/Product/ProductException.cs @@ -86,7 +86,7 @@ public class ProductNotFoundException : DomainException /// Initializes a new instance of the class with the specified product list. /// /// The list of products that was not found or is empty. - public ProductNotFoundException(IEnumerable produtos) + public ProductNotFoundException(IEnumerable produtos) : base("A lista de produtos está vazia.") { } diff --git a/Blazing.Domain/Exceptions/User/UserException.cs b/Blazing.Domain/Exceptions/User/UserException.cs index db657d0..3e2c484 100644 --- a/Blazing.Domain/Exceptions/User/UserException.cs +++ b/Blazing.Domain/Exceptions/User/UserException.cs @@ -36,7 +36,7 @@ public static UserLockedOutException FromLockedOutExceptionUserName(string userN /// /// The email of the locked out user. /// A new instance of the class. - public static UserLockedOutException FromLockedOutExceptionEmail(string email) + public static UserLockedOutException FromLockedOutExceptionEmail(string? email) { return new UserLockedOutException( $"Tentativa de login falhou. A conta está bloqueada. E-mail: {email}"); @@ -61,7 +61,7 @@ private UserAlreadyExistsException(string message) /// /// The identifiers of the users that already exist. /// A new instance of the class. - public static UserAlreadyExistsException FromExistingId(string id) + public static UserAlreadyExistsException FromExistingId(string? id) { return new UserAlreadyExistsException( $"Identificador já existe: {string.Join(", ", id)}"); @@ -83,7 +83,7 @@ public static UserAlreadyExistsException FromExistingUsers(IEnumerable /// The names of the users that already exist. /// A new instance of the class. - public static UserAlreadyExistsException FromNameExistingUser(string usersName) + public static UserAlreadyExistsException FromNameExistingUser(string? usersName) { return new UserAlreadyExistsException( $"O nome do usuário: {string.Join(", ", usersName)} já existe."); diff --git a/Blazing.Domain/Interfaces/Repository/IAggregateRoot.cs b/Blazing.Domain/Interface/Repository/IAggregateRoot.cs similarity index 100% rename from Blazing.Domain/Interfaces/Repository/IAggregateRoot.cs rename to Blazing.Domain/Interface/Repository/IAggregateRoot.cs diff --git a/Blazing.Domain/Interfaces/Repository/IAppLogger.cs b/Blazing.Domain/Interface/Repository/IAppLogger.cs similarity index 100% rename from Blazing.Domain/Interfaces/Repository/IAppLogger.cs rename to Blazing.Domain/Interface/Repository/IAppLogger.cs diff --git a/Blazing.Domain/Interfaces/Repository/ICrudDomainRepository.cs b/Blazing.Domain/Interface/Repository/ICrudDomainRepository.cs similarity index 100% rename from Blazing.Domain/Interfaces/Repository/ICrudDomainRepository.cs rename to Blazing.Domain/Interface/Repository/ICrudDomainRepository.cs diff --git a/Blazing.Domain/Interfaces/Services/ICrudDomainService.cs b/Blazing.Domain/Interface/Services/ICrudDomainService.cs similarity index 87% rename from Blazing.Domain/Interfaces/Services/ICrudDomainService.cs rename to Blazing.Domain/Interface/Services/ICrudDomainService.cs index 941aa30..14666f4 100644 --- a/Blazing.Domain/Interfaces/Services/ICrudDomainService.cs +++ b/Blazing.Domain/Interface/Services/ICrudDomainService.cs @@ -12,6 +12,7 @@ public interface ICrudDomainService where T : BaseEntity /// Adds a collection of object. /// /// A collection of boject to be added. + /// /// A task representing the asynchronous operation, with a collection of the added object. Task> Add(IEnumerable obj, CancellationToken cancellationToken); @@ -20,6 +21,8 @@ public interface ICrudDomainService where T : BaseEntity /// /// The ID of the object to be updated. /// The updated object details. + /// + /// /// A task representing the asynchronous operation, with the updated object. Task> Update(IEnumerable id, IEnumerable obj, IEnumerable objUpdate, CancellationToken cancellationToken); @@ -28,6 +31,7 @@ public interface ICrudDomainService where T : BaseEntity /// /// A collection of object IDs to be deleted. /// A collection of object to be deleted. + /// /// A task representing the asynchronous operation, with a collection of the deleted object. Task> Delete(IEnumerable id, IEnumerable obj, CancellationToken cancellationToken); @@ -36,6 +40,7 @@ public interface ICrudDomainService where T : BaseEntity /// /// The ID of the object to be retrieved. /// The product details. + /// /// A task representing the asynchronous operation, with the object details. Task> GetById(IEnumerable id, IEnumerable obj, CancellationToken cancellationToken); @@ -43,8 +48,9 @@ public interface ICrudDomainService where T : BaseEntity /// Retrieves all object. /// /// The object details. + /// /// A task representing the asynchronous operation, with a collection of all object. - Task> GetAll(IEnumerable obj, CancellationToken cancellationToken); + Task> GetAll(IEnumerable obj, CancellationToken cancellationToken); /// /// Checks if a specified condition exists asynchronously. diff --git a/Blazing.Domain/Interfaces/Services/User/IUserDomainService.cs b/Blazing.Domain/Interface/Services/User/IUserDomainService.cs similarity index 100% rename from Blazing.Domain/Interfaces/Services/User/IUserDomainService.cs rename to Blazing.Domain/Interface/Services/User/IUserDomainService.cs diff --git a/Blazing.Domain/Services/ProductDomainService.cs b/Blazing.Domain/Services/ProductDomainService.cs index 21c5ceb..d044fc6 100644 --- a/Blazing.Domain/Services/ProductDomainService.cs +++ b/Blazing.Domain/Services/ProductDomainService.cs @@ -282,13 +282,14 @@ private static string NormalizeString(string? input) public async Task> GetAll(IEnumerable products, CancellationToken cancellationToken) { - if (products == null || !products.Any()) + var enumerable = products.ToList(); + if (products == null || enumerable.Count == 0) throw new ProductExceptions.ProductNotFoundException(products ?? []); try { await Task.CompletedTask; - return products; + return enumerable; } catch (DomainException) { diff --git a/Blazing.Domain/Services/UserDomainService.cs b/Blazing.Domain/Services/UserDomainService.cs index 2cb8c11..07622ed 100644 --- a/Blazing.Domain/Services/UserDomainService.cs +++ b/Blazing.Domain/Services/UserDomainService.cs @@ -209,19 +209,22 @@ private static string NormalizeString(string? input) /// Thrown if the user collection is null or empty. public async Task> Delete(IEnumerable id, IEnumerable user, CancellationToken cancellationToken) { + var enumerable = user.ToList(); + if (id == null || Guid.Empty == id.FirstOrDefault() || !id.Any()) - throw DomainException.IdentityInvalidException.Identities(id ?? []); - if (user == null || !user.Any()) - throw UserException.UserNotFoundException.UserNotFound(user); + throw DomainException.IdentityInvalidException.Identities(id ?? []); + + if (user == null || !enumerable.Any()) + throw UserException.UserNotFoundException.UserNotFound(enumerable); try { - foreach (var item in user) + foreach (var item in enumerable) { item.PasswordHash = null; } await Task.CompletedTask; - return user; + return enumerable; } catch (DomainException ) { @@ -240,21 +243,23 @@ private static string NormalizeString(string? input) /// Thrown when no users matching the provided IDs are found in the user collection. public async Task> GetById(IEnumerable id, IEnumerable users, CancellationToken cancellationToken) { - if (id == null || !id.Any() || Guid.Empty == id.FirstOrDefault()) - throw DomainException.IdentityInvalidException.Identities(id ?? []); - if (users == null || !users.Any()) - throw UserException.UserNotFoundException.UserNotFound(users); + var usersManager = users.ToList(); + var byId = id.ToList(); + if (id == null || !byId.Any() || Guid.Empty == byId.FirstOrDefault()) + throw DomainException.IdentityInvalidException.Identities(id ?? []); + if (users == null || !byId.Any()) + throw UserException.UserNotFoundException.UserNotFound(usersManager); try { - foreach (var user in users) + foreach (var user in usersManager) { user.PasswordHash = null; } await Task.CompletedTask; - return users; + return usersManager; } catch (DomainException ) { @@ -270,7 +275,7 @@ private static string NormalizeString(string? input) /// A cancellation token that can be used to cancel the operation. /// A task representing the asynchronous operation. The task result contains a collection of User objects. /// Thrown when there are no users to retrieve or if the input collection is null or empty. - public async Task> GetAll(IEnumerable users, CancellationToken cancellationToken) + public async Task> GetAll(IEnumerable users, CancellationToken cancellationToken) { if(users is null || !users.Any()) throw DomainException.NotFoundException.FoundException(); @@ -315,19 +320,19 @@ public async Task ExistsAsync(bool id, bool userName, IEnumerable us /// A task representing the asynchronous operation, with a result indicating whether the user exists (true if the ID, username, or email exists, false otherwise). /// Thrown when the user with the specified ID, username, or email already exists. /// Thrown when there is an error checking for the existence of the user. - public async Task UserExistsAsync(bool id, bool userName, bool email, IEnumerable users, CancellationToken cancellationToken) + public Task UserExistsAsync(bool id, bool userName, bool email, IEnumerable users, CancellationToken cancellationToken) { try { - return users != null && users.Any() switch + var enumerable = users.ToList(); + return Task.FromResult(users != null && enumerable.Any() switch { - true when id => throw UserException.UserAlreadyExistsException.FromExistingId(users.Select(u => u.Id).ToString()), - true when userName => throw UserException.UserAlreadyExistsException.FromNameExistingUser(users.Select(u => u.UserName).ToString()), - true when email => throw UserException.UserAlreadyExistsException.FromEmailExistingUser(users.Select(u => u.Email).ToString()), + true when id => throw UserException.UserAlreadyExistsException.FromExistingId(enumerable.Select(u => u.Id).ToString()), + true when userName => throw UserException.UserAlreadyExistsException.FromNameExistingUser(enumerable.Select(u => u.UserName).ToString()), + true when email => throw UserException.UserAlreadyExistsException.FromEmailExistingUser(enumerable.Select(u => u.Email).ToString()), _ => false - }; - await Task.CompletedTask; + }); } catch (DomainException) { diff --git a/Blazing.Test/Api/Controller/ControllerRepositoryFixtureTest.cs b/Blazing.Test/Api/Controller/ControllerRepositoryFixtureTest.cs index a647bd1..200ad47 100644 --- a/Blazing.Test/Api/Controller/ControllerRepositoryFixtureTest.cs +++ b/Blazing.Test/Api/Controller/ControllerRepositoryFixtureTest.cs @@ -1,5 +1,4 @@ using Blazing.Api.Controllers.Product; -using Blazing.Ecommerce.Repository; using Blazing.Test.Data; using BlazingPizzaTest.Controller; using BlazingPizzaTest.Data; @@ -11,6 +10,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Blazing.Ecommerce.Interface; namespace Blazing.Test.Api.Controller { diff --git a/Blazing.Test/Infrastructure/CategoryRepositoryFixtureTest.cs b/Blazing.Test/Infrastructure/CategoryRepositoryFixtureTest.cs index d98fc50..d749940 100644 --- a/Blazing.Test/Infrastructure/CategoryRepositoryFixtureTest.cs +++ b/Blazing.Test/Infrastructure/CategoryRepositoryFixtureTest.cs @@ -42,6 +42,8 @@ public CategoryRepositoryFixtureTest(RepositoryFixtureTest fixture) [Fact] public async Task CategoriesAllTest() { + var page = 1; + var pageSize = 3; var cts = CancellationToken.None; // Check if category exists @@ -52,12 +54,11 @@ public async Task CategoriesAllTest() // Update categories in the repository var resultUpdateAsync = await _fixture.CategoryInfrastructureRepository.UpdateCategory(_categoryIds, _categories, cts); - // Get category by ID var resultGetByIdAsync = await _fixture.CategoryInfrastructureRepository.GetCategoryById(_categoryIds, cts); // Get all categories - var resultGetAllAsync = await _fixture.CategoryInfrastructureRepository.GetAll(cts); + var resultGetAllAsync = await _fixture.CategoryInfrastructureRepository.GetAll(page, pageSize, cts); // Delete categories var resultDeleteAsync = await _fixture.CategoryInfrastructureRepository.DeleteCategory(_categoryIds, cts); diff --git a/Blazing.Test/Infrastructure/RepositoryFixtureTest.cs b/Blazing.Test/Infrastructure/RepositoryFixtureTest.cs index e71ade6..4260c67 100644 --- a/Blazing.Test/Infrastructure/RepositoryFixtureTest.cs +++ b/Blazing.Test/Infrastructure/RepositoryFixtureTest.cs @@ -4,8 +4,8 @@ using Blazing.Domain.Services; using Blazing.Ecommerce.Data; using Blazing.Ecommerce.Dependency; +using Blazing.Ecommerce.Interface; using Blazing.Ecommerce.Repository; -using Blazing.Ecommerce.Service; using Blazing.Identity.Data; using Blazing.Identity.Entities; using Blazing.Identity.Mappings; @@ -18,236 +18,244 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; -using UserInfrastructureRepository = Blazing.Identity.Service.UserInfrastructureRepository; -namespace Blazing.Test.Infrastructure; - -/// -/// Represents a fixture for testing the ProductRepository. -/// -public class RepositoryFixtureTest : IDisposable +namespace Blazing.Test.Infrastructure { - private bool _disposed; - - private readonly IMemoryCache _memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); /// - /// Gets the AutoMapper instance. + /// Represents a fixture for testing the ProductRepository. /// - public IMapper Mapper { get; } + public class RepositoryFixtureTest : IDisposable + { + private bool _disposed; - /// - /// Gets the PeopleOfData instance. - /// - public PeopleOfData PeopleOfData { get; } - /// - /// Gets the AppDbContext instance. - /// - public BlazingDbContext DbContext { get; } + private readonly IMemoryCache _memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); - /// - /// Gets the DependencyInjection instance. - /// - public DependencyInjection InjectServiceDbContext { get; } + /// + /// Gets the AutoMapper instance. + /// + public IMapper Mapper { get; } - /// - /// Gets the ProductInfrastructureRepository instance. - /// - public ProductInfrastructureRepository ProductInfrastructureRepository { get; } + /// + /// Gets the PeopleOfData instance. + /// + public PeopleOfData PeopleOfData { get; } - /// - /// Gets the ProductAppService instance. - /// - public ProductAppService ProductAppService { get; } + /// + /// Gets the AppDbContext instance. + /// + public BlazingDbContext DbContext { get; } - public ProductDomainService ProductDomainService { get; } + /// + /// Gets the DependencyInjection instance. + /// + public DependencyInjection InjectServiceDbContext { get; } + /// + /// Gets the ProductInfrastructureRepository instance. + /// + public ProductInfrastructureRepository ProductInfrastructureRepository { get; } - //Category + /// + /// Gets the ProductAppService instance. + /// + public ProductAppService ProductAppService { get; } - /// - /// Gets the CategoryInfrastructureRepository instance. - /// - public CategoryInfrastructureRepository CategoryInfrastructureRepository { get; } + public ProductDomainService ProductDomainService { get; } - /// - /// Gets the CategoryAppService instance. - /// - public CategoryAppService CategoryAppService { get; } - public CategoryDomainService CategoryDomainService { get; } + //Category + /// + /// Gets the CategoryInfrastructureRepository instance. + /// + public CategoryInfrastructureRepository CategoryInfrastructureRepository { get; } - //User Identity + /// + /// Gets the CategoryAppService instance. + /// + public CategoryAppService CategoryAppService { get; } - public BlazingIdentityDbContext BlazingIdentityDbContext { get; } - public UserInfrastructureRepository UserInfrastructureRepository { get; } + public CategoryDomainService CategoryDomainService { get; } - public Identity.Dependency.DependencyInjection InjectServiceIdentityDbContext { get; } - public UserManager UserManagerIdentity { get; } + //User Identity - public SignInManager SignInManagerIdentity { get; } + public Identity.Data.BlazingIdentityDbContext? BlazingIdentityDbContext { get; } - public BlazingIdentityMapper IdentityMapper { get; } + public Identity.Dependency.DependencyInjection InjectServiceIdentityDbContext { get; } + public UserManager UserManagerIdentity { get; } - //User Ecommerce + public SignInManager SignInManagerIdentity { get; } - public Ecommerce.Service.UserInfrastructureRepository UserEcommerceRepository { get; } + public BlazingIdentityMapper IdentityMapper { get; } - public UserDomainService UserDomainService { get; } + public UserAppService UserAppServiceIdentity { get; } - public UserAppService UserAppService { get; } + //User Ecommerce - /// - /// Initializes a new instance of the ProductRepositoryFixture class. - /// - public RepositoryFixtureTest() - { - //Product + public UserInfrastructureRepository UserEcommerceRepository { get; } - // Create a new instance of the PeopleOfData class - PeopleOfData = new PeopleOfData(); + public UserDomainService UserDomainService { get; } - // Create a new instance of the MapperConfiguration class - var config = new MapperConfiguration(cfg => + public UserAppService UserAppService { get; } + + + /// + /// Initializes a new instance of the ProductRepositoryFixture class. + /// + public RepositoryFixtureTest() { - // Add the BlazingProfile to the MapperConfiguration - cfg.AddProfile(); - }); + //Product - // Create a new instance of the Mapper class - Mapper = config.CreateMapper(); + // Create a new instance of the PeopleOfData class + PeopleOfData = new PeopleOfData(); - // Create a new instance of the MockDb class and create a new instance of the BlazingDbContext class - DbContext = new MockDb().CreateDbContext(); + // Create a new instance of the MapperConfiguration class + var config = new MapperConfiguration(cfg => + { + // Add the BlazingProfile to the MapperConfiguration + cfg.AddProfile(); + }); - // Create a new instance of the DependencyInjection class - InjectServiceDbContext = new DependencyInjection(DbContext, Mapper); + // Create a new instance of the Mapper class + Mapper = config.CreateMapper(); + // Create a new instance of the MockDb class and create a new instance of the BlazingDbContext class + DbContext = new MockDb().CreateDbContext(); - //Product + // Create a new instance of the DependencyInjection class + InjectServiceDbContext = new DependencyInjection(DbContext, Mapper); - // Create a new instance of the ProductDomainService class - ProductDomainService = new ProductDomainService(); - // Create a new instance of the ProductAppService class - ProductAppService = new ProductAppService(Mapper, ProductDomainService); + //Product - // Create a new instance of the ProductInfrastructureRepository class - ProductInfrastructureRepository = - new ProductInfrastructureRepository(_memoryCache, InjectServiceDbContext, ProductAppService); + // Create a new instance of the ProductDomainService class + ProductDomainService = new ProductDomainService(); - //Category + // Create a new instance of the ProductAppService class + ProductAppService = new ProductAppService(Mapper, ProductDomainService); - // Create a new instance of the CategoryDomainService class - CategoryDomainService = new CategoryDomainService(); + // Create a new instance of the ProductInfrastructureRepository class + ProductInfrastructureRepository = + new ProductInfrastructureRepository(_memoryCache, InjectServiceDbContext, ProductAppService); - // Create a new instance of the CategoryAppService class - CategoryAppService = new CategoryAppService(CategoryDomainService, Mapper); + //Category - // Create a new instance of the CategoryInfrastructureRepository class - CategoryInfrastructureRepository = - new CategoryInfrastructureRepository(CategoryAppService, InjectServiceDbContext); + // Create a new instance of the CategoryDomainService class + CategoryDomainService = new CategoryDomainService(); - //User Ecommerce + // Create a new instance of the CategoryAppService class + CategoryAppService = new CategoryAppService(CategoryDomainService, Mapper); - // Cria um mock de ICrudDomainService - UserDomainService = new UserDomainService(); + // Create a new instance of the CategoryInfrastructureRepository class + CategoryInfrastructureRepository = + new CategoryInfrastructureRepository(_memoryCache, CategoryAppService, InjectServiceDbContext); - // Cria a instância do UserAppService com os mocks injetados - UserAppService = new UserAppService(Mapper, UserDomainService); + //User Ecommerce - UserEcommerceRepository = - new Ecommerce.Service.UserInfrastructureRepository(UserAppService, InjectServiceDbContext); + // Cria um mock de ICrudDomainService + UserDomainService = new UserDomainService(); - //User Identity + // Cria a instância do UserAppService com os mocks injetados + UserAppService = new UserAppService(Mapper, UserDomainService); - // Create a new instance of the DependencyInjection class - InjectServiceIdentityDbContext = new Identity.Dependency.DependencyInjection(BlazingIdentityDbContext, Mapper); + UserEcommerceRepository = + new UserInfrastructureRepository(_memoryCache, UserAppService, + InjectServiceDbContext); - //Create a new instance of the Mock class - var userRepositoryMock = new Mock(); + //User Identity - UserManagerIdentity = GetUserManager(); + // Create a new instance of the DependencyInjection class + InjectServiceIdentityDbContext = new Identity.Dependency.DependencyInjection(BlazingIdentityDbContext, Mapper); - SignInManagerIdentity = GetSignInManager(); + //Create a new instance of the Mock class + var userRepositoryMock = new Mock(); - IdentityMapper = new BlazingIdentityMapper(); + UserManagerIdentity = GetUserManager(); - UserInfrastructureRepository = new UserInfrastructureRepository(InjectServiceIdentityDbContext, - UserManagerIdentity, SignInManagerIdentity, IdentityMapper, userRepositoryMock.Object); - } + SignInManagerIdentity = GetSignInManager(); - /// - /// Disposes the resources used by the ProductRepositoryFixture. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + IdentityMapper = new BlazingIdentityMapper(); - protected virtual void Dispose(bool disposing) - { - if (_disposed) return; - if (disposing) - DbContext?.Dispose(); + UserAppServiceIdentity = new UserAppService(Mapper, UserDomainService); - _disposed = true; - } + //UserInfrastructureRepository = new UserInfrastructureRepository(_memoryCache, UserAppServiceIdentity, + // InjectServiceIdentityDbContext, + // UserManagerIdentity, SignInManagerIdentity, IdentityMapper, userRepositoryMock.Object); + } - public static UserManager GetUserManager() - { - var store = new Mock>(); - var identityOptions = new Mock>(); - var passwordHasher = new Mock>(); - var userValidators = new List> - { new Mock>().Object }; - var passwordValidators = new List> - { new Mock>().Object }; - var keyNormalizer = new Mock(); - var errors = new Mock(); - var services = new Mock(); - var logger = new Mock>>(); - - return new UserManager( - store.Object, - identityOptions.Object, - passwordHasher.Object, - userValidators, - passwordValidators, - keyNormalizer.Object, - errors.Object, - services.Object, - logger.Object); - } + /// + /// Disposes the resources used by the ProductRepositoryFixture. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - public static SignInManager GetSignInManager() - { - var httpContextAccessor = new Mock(); + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + if (disposing) + DbContext?.Dispose(); + + _disposed = true; + } + + + public static UserManager GetUserManager() + { + var store = new Mock>(); + var identityOptions = new Mock>(); + var passwordHasher = new Mock>(); + var userValidators = new List> + { new Mock>().Object }; + var passwordValidators = new List> + { new Mock>().Object }; + var keyNormalizer = new Mock(); + var errors = new Mock(); + var services = new Mock(); + var logger = new Mock>>(); + + return new UserManager( + store.Object, + identityOptions.Object, + passwordHasher.Object, + userValidators, + passwordValidators, + keyNormalizer.Object, + errors.Object, + services.Object, + logger.Object); + } + + public static SignInManager GetSignInManager() + { + var httpContextAccessor = new Mock(); - var claimsPrincipalFactory = new Mock>(); + var claimsPrincipalFactory = new Mock>(); - var option = new Mock>(); + var option = new Mock>(); - var logger = new Mock>>(); + var logger = new Mock>>(); - var authentication = new Mock(); + var authentication = new Mock(); - var userConfirmation = new Mock>(); + var userConfirmation = new Mock>(); - return new SignInManager( - GetUserManager(), - httpContextAccessor.Object, - claimsPrincipalFactory.Object, - option.Object, - logger.Object, - authentication.Object, - userConfirmation.Object); + return new SignInManager( + GetUserManager(), + httpContextAccessor.Object, + claimsPrincipalFactory.Object, + option.Object, + logger.Object, + authentication.Object, + userConfirmation.Object); + } } } \ No newline at end of file diff --git a/Blazing.Test/Infrastructure/UserRepositoryFixtureTest.cs b/Blazing.Test/Infrastructure/UserRepositoryFixtureTest.cs index fe83704..07de6e8 100644 --- a/Blazing.Test/Infrastructure/UserRepositoryFixtureTest.cs +++ b/Blazing.Test/Infrastructure/UserRepositoryFixtureTest.cs @@ -36,13 +36,14 @@ public UserEcommerceRepositoryFixtureTest(RepositoryFixtureTest fixture) _UserToUpdate = _fixture.PeopleOfData.GetUpdateUsers(); } - /// /// Tests the functionality of the UserEcommerceRepository class. /// [Fact] public async Task UserAllTest() { + int page = 1; + int pageSize = 3; // Create a cancellation token with no cancellation. var cts = CancellationToken.None; @@ -53,7 +54,7 @@ public async Task UserAllTest() var resultAdd = await _fixture.UserEcommerceRepository.AddUsers(_user, cts); // Get all users from the repository. - var resultUserAll = await _fixture.UserEcommerceRepository.GetAllUsers(cts); + var resultUserAll = await _fixture.UserEcommerceRepository.GetAllUsers(page,pageSize,cts); // Update users in the repository. var resultToUpdate = await _fixture.UserEcommerceRepository.UpdateUsers(_userId, _UserToUpdate, cts); diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Data/BlazingDbContext.cs b/Blazing.infrastructure/Blazing.Ecommerce/Data/BlazingDbContext.cs index 8f63884..9f77292 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Data/BlazingDbContext.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Data/BlazingDbContext.cs @@ -37,7 +37,6 @@ protected override void ConfigureConventions(ModelConfigurationBuilder configura } protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); base.OnModelCreating(modelBuilder); } diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Dependencies/ConfigServiceCollectionExtensiosInfraEcommerce.cs b/Blazing.infrastructure/Blazing.Ecommerce/Dependencies/ConfigServiceCollectionExtensionsInfraEcommerce.cs similarity index 86% rename from Blazing.infrastructure/Blazing.Ecommerce/Dependencies/ConfigServiceCollectionExtensiosInfraEcommerce.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Dependencies/ConfigServiceCollectionExtensionsInfraEcommerce.cs index 37dc9c8..e2be532 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Dependencies/ConfigServiceCollectionExtensiosInfraEcommerce.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Dependencies/ConfigServiceCollectionExtensionsInfraEcommerce.cs @@ -1,21 +1,21 @@ using Blazing.Application.Dto; -using Blazing.Application.Interfaces.Category; -using Blazing.Application.Interfaces.Product; +using Blazing.Application.Interface.Category; +using Blazing.Application.Interface.Product; using Blazing.Application.Services; using Blazing.Domain.Entities; using Blazing.Domain.Interfaces.Services; using Blazing.Domain.Interfaces.Services.User; using Blazing.Domain.Services; using Blazing.Ecommerce.Data; +using Blazing.Ecommerce.Interface; using Blazing.Ecommerce.Repository; -using Blazing.Ecommerce.Service; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace Blazing.Ecommerce.Dependency +namespace Blazing.Ecommerce.Dependencies { - public static class ConfigServiceCollectionExtensiosInfraEcommerce + public static class ConfigServiceCollectionExtensionsInfraEcommerce { public static IServiceCollection AddConfigInfraEcommerce( diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Repository/ICategoryInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Ecommerce/Interface/ICategoryInfrastructureRepository.cs similarity index 80% rename from Blazing.infrastructure/Blazing.Ecommerce/Repository/ICategoryInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Interface/ICategoryInfrastructureRepository.cs index 537bf14..7241ba3 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Repository/ICategoryInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Interface/ICategoryInfrastructureRepository.cs @@ -1,7 +1,6 @@ using Blazing.Application.Dto; - -namespace Blazing.Ecommerce.Repository +namespace Blazing.Ecommerce.Interface { public interface ICategoryInfrastructureRepository { @@ -13,6 +12,6 @@ public interface ICategoryInfrastructureRepository Task> GetCategoryById(IEnumerable id, CancellationToken cancellationToken); - Task> GetAll(CancellationToken cancellationToken); + Task> GetAll(int page, int pageSize, CancellationToken cancellationToken); } } diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Repository/IProductInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Ecommerce/Interface/IProductInfrastructureRepository.cs similarity index 91% rename from Blazing.infrastructure/Blazing.Ecommerce/Repository/IProductInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Interface/IProductInfrastructureRepository.cs index 5b02a9c..63edae5 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Repository/IProductInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Interface/IProductInfrastructureRepository.cs @@ -1,7 +1,6 @@ using Blazing.Application.Dto; - -namespace Blazing.Ecommerce.Repository +namespace Blazing.Ecommerce.Interface { #region Interface Product Infrastructure Repository. public interface IProductInfrastructureRepository @@ -10,6 +9,7 @@ public interface IProductInfrastructureRepository /// Adds a collection of products to the repository. /// /// A collection of objects representing the products to be added. + /// /// A task representing the asynchronous operation, with a result of a collection of objects that were added. Task> AddProducts(IEnumerable productDto, CancellationToken cancellationToken); @@ -18,6 +18,7 @@ public interface IProductInfrastructureRepository /// /// A collection of product IDs to be updated. /// A collection of objects containing the updated product information. + /// /// A task representing the asynchronous operation, with a result of a collection of objects that were updated. Task> UpdateProduct(IEnumerable id, IEnumerable productDto, CancellationToken cancellationToken); @@ -25,6 +26,7 @@ public interface IProductInfrastructureRepository /// Retrieves products that belong to specified categories. /// /// A collection of category IDs. + /// /// A task representing the asynchronous operation, with a result of a collection of objects associated with the specified category IDs. Task> GetProductsByCategoryId(IEnumerable id, CancellationToken cancellationToken); @@ -32,6 +34,7 @@ public interface IProductInfrastructureRepository /// Deletes products based on their IDs. /// /// A collection of product IDs to be deleted. + /// /// A task representing the asynchronous operation, with a result of a collection of objects that were deleted. Task> DeleteProducts(IEnumerable id, CancellationToken cancellationToken); @@ -39,6 +42,7 @@ public interface IProductInfrastructureRepository /// Retrieves products by their IDs. /// /// A collection of product IDs. + /// /// A task representing the asynchronous operation, with a result of a collection of objects that match the specified IDs. Task> GetProductById(IEnumerable id, CancellationToken cancellationToken); @@ -52,6 +56,7 @@ public interface IProductInfrastructureRepository /// Checks if the specified products exist in the repository. /// /// A collection of objects to check for existence. + /// /// A task representing the asynchronous operation, with a result indicating whether the products exist (true if they exist, false otherwise). Task ExistsAsyncProduct(IEnumerable productDto, CancellationToken cancellationToken); diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Repository/IUserInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Ecommerce/Interface/IUserInfrastructureRepository.cs similarity index 68% rename from Blazing.infrastructure/Blazing.Ecommerce/Repository/IUserInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Interface/IUserInfrastructureRepository.cs index 8b61ad3..470048e 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Repository/IUserInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Interface/IUserInfrastructureRepository.cs @@ -1,17 +1,18 @@ using Blazing.Application.Dto; -namespace Blazing.Ecommerce.Repository +namespace Blazing.Ecommerce.Interface { public interface IUserInfrastructureRepository { Task> AddUsers(IEnumerable userDto, CancellationToken cancellationToken); - Task> UpdateUsers(IEnumerable id, IEnumerable userDto, CancellationToken cancellationToken); + Task> UpdateUsers(IEnumerable id, IEnumerable userDto, + CancellationToken cancellationToken); Task> DeleteUsers(IEnumerable id, CancellationToken cancellationToken); Task> GetUsersById(IEnumerable id, CancellationToken cancellationToken); - Task> GetAllUsers(CancellationToken cancellationToken); + Task> GetAllUsers(int page, int pageSize, CancellationToken cancellationToken); } } diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Service/CategoryInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Ecommerce/Repository/CategoryInfrastructureRepository.cs similarity index 74% rename from Blazing.infrastructure/Blazing.Ecommerce/Service/CategoryInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Repository/CategoryInfrastructureRepository.cs index 2e17578..182e818 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Service/CategoryInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Repository/CategoryInfrastructureRepository.cs @@ -1,23 +1,18 @@ using Blazing.Application.Dto; -using Blazing.Application.Interfaces.Category; -using Blazing.Application.Interfaces.Product; +using Blazing.Application.Interface.Category; using Blazing.Domain.Entities; using Blazing.Domain.Exceptions; -using Blazing.Domain.Exceptions.Category; using Blazing.Ecommerce.Dependency; -using Blazing.Ecommerce.Repository; +using Blazing.Ecommerce.Interface; using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Memory; -namespace Blazing.Ecommerce.Service +namespace Blazing.Ecommerce.Repository { #region Responsibility for searching data in the database in the category table. - public class CategoryInfrastructureRepository(ICategoryAppService categoryAppService, DependencyInjection dependencyInjection) : ICategoryInfrastructureRepository + public class CategoryInfrastructureRepository(IMemoryCache memoryCache,ICategoryAppService categoryAppService, DependencyInjection dependencyInjection) : ICategoryInfrastructureRepository { + private readonly IMemoryCache _memoryCache = memoryCache; private readonly ICategoryAppService _categoryAppService = categoryAppService; private readonly DependencyInjection _dependencyInjection = dependencyInjection; @@ -50,20 +45,22 @@ public class CategoryInfrastructureRepository(ICategoryAppService c /// A task representing the asynchronous operation, with a result of the collection of that were updated. public async Task> UpdateCategory(IEnumerable id, IEnumerable categoryUpdate, CancellationToken cancellationToken) { - if (id == null || !id.Any() || Guid.Empty == id.First()) + var enumerable = id.ToList(); + if (id == null || enumerable.Count == 0 || Guid.Empty == enumerable.First()) { - throw DomainException.IdentityInvalidException.Identities(id); + throw DomainException.IdentityInvalidException.Identities(enumerable); } var existingCategories = await _dependencyInjection._appContext.Category - .Where(c => id.Contains(c.Id)) + .Where(c => enumerable.Contains(c.Id)) .ToListAsync(cancellationToken: cancellationToken); - var categoryDtos = _dependencyInjection._mapper.Map>(existingCategories); + var categoryDto = _dependencyInjection._mapper.Map>(existingCategories); - var categoryDtoUpdateResult = await _categoryAppService.UpdateCategory(id, categoryDtos, categoryUpdate, cancellationToken); + var categoryDtoUpdateResult = await _categoryAppService.UpdateCategory(enumerable, categoryDto, categoryUpdate, cancellationToken); - foreach (var updateCategoryDto in categoryDtoUpdateResult) + var updateCategory = categoryDtoUpdateResult.ToList(); + foreach (var updateCategoryDto in updateCategory) { var existingCategory = existingCategories.SingleOrDefault(c => c.Id == updateCategoryDto.Id); if (existingCategory != null) @@ -73,7 +70,7 @@ public class CategoryInfrastructureRepository(ICategoryAppService c } await _dependencyInjection._appContext.SaveChangesAsync(cancellationToken); - return categoryDtoUpdateResult; + return updateCategory; } @@ -81,6 +78,7 @@ public class CategoryInfrastructureRepository(ICategoryAppService c /// Deletes categories based on their IDs. /// /// A collection of category IDs to be deleted. + /// /// A task representing the asynchronous operation, with a result of the collection of that were deleted. public async Task> DeleteCategory(IEnumerable id, CancellationToken cancellationToken) { @@ -150,27 +148,47 @@ public class CategoryInfrastructureRepository(ICategoryAppService c /// Retrieves categories by their IDs. /// /// A collection of category IDs. + /// /// A task representing the asynchronous operation, with a result of the collection of objects that match the specified IDs. public async Task> GetCategoryById(IEnumerable id, CancellationToken cancellationToken) { - var category = await _dependencyInjection._appContext.Category - .Where(c => id.Contains(c.Id)).ToListAsync(cancellationToken); + var enumerable = id.ToList(); + var cacheId = enumerable; + if (!_memoryCache.TryGetValue(cacheId, out IEnumerable? category)) + { + category = await _dependencyInjection._appContext.Category + .Take(5) + .Where(c => enumerable.Contains(c.Id)) + .ToListAsync(cancellationToken); + _memoryCache.Set(cacheId, category, TimeSpan.FromMinutes(5)); + } + var categoryDto = _dependencyInjection._mapper.Map>(category); - await _categoryAppService.GetById(id, categoryDto, cancellationToken); + var categoryById = categoryDto.ToList(); + await _categoryAppService.GetById(enumerable, categoryById, cancellationToken); - return categoryDto; + return categoryById; } /// /// Retrieves all categories from the repository. /// /// A task representing the asynchronous operation, with a result of a collection of all objects. - public async Task> GetAll(CancellationToken cancellationToken) + public async Task> GetAll(int page, int pageSize,CancellationToken cancellationToken) { - var categories = await _dependencyInjection._appContext.Category - .ToListAsync(cancellationToken: cancellationToken); + var cachePage = $"{page}, {pageSize}"; + if (!_memoryCache.TryGetValue(cachePage, out IEnumerable? categories)) + { + categories = await _dependencyInjection._appContext.Category + .AsNoTracking() + .Skip((page - 1 ) * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken: cancellationToken); + + _memoryCache.Set(cachePage, categories, TimeSpan.FromMinutes(5)); + } var categoryDto = _dependencyInjection._mapper.Map>(categories); @@ -183,15 +201,16 @@ public class CategoryInfrastructureRepository(ICategoryAppService c /// /// Checks if the specified categories exist in the repository. /// - /// A collection of objects to check for existence. + /// A collection of objects to check for existence. + /// /// A task representing the asynchronous operation, with a result indicating whether the categories exist (true if they exist, false otherwise). public async Task ExistsAsync(IEnumerable categories, CancellationToken cancellationToken) { var category = _dependencyInjection._mapper.Map>(categories); - var resultId = await _dependencyInjection._appContext.Category.AnyAsync(p => category.Select(c => c.Id).Contains(p.Id)); + var resultId = await _dependencyInjection._appContext.Category.AnyAsync(p => category.Select(c => c.Id).Contains(p.Id), cancellationToken: cancellationToken); - var resultName = await _dependencyInjection._appContext.Category.AnyAsync(p => category.Select(x => x.Name).Contains(p.Name)); + var resultName = await _dependencyInjection._appContext.Category.AnyAsync(p => category.Select(x => x.Name).Contains(p.Name), cancellationToken: cancellationToken); await _categoryAppService.ExistsCategories(resultId, resultName, categories, cancellationToken); diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Service/ProductInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Ecommerce/Repository/ProductInfrastructureRepository.cs similarity index 79% rename from Blazing.infrastructure/Blazing.Ecommerce/Service/ProductInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Repository/ProductInfrastructureRepository.cs index debb7d7..3513cdc 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Service/ProductInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Repository/ProductInfrastructureRepository.cs @@ -1,19 +1,14 @@ using BenchmarkDotNet.Attributes; using Blazing.Application.Dto; -using Blazing.Application.Interfaces.Product; +using Blazing.Application.Interface.Product; using Blazing.Domain.Entities; using Blazing.Domain.Exceptions; using Blazing.Ecommerce.Dependency; -using Blazing.Ecommerce.Repository; +using Blazing.Ecommerce.Interface; using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; -namespace Blazing.Ecommerce.Service +namespace Blazing.Ecommerce.Repository { #region Responsibility for searching data in the database in the product table. /// @@ -53,7 +48,7 @@ public class ProductInfrastructureRepository(IMemoryCache memoryCache,Dependency /// Updates a product in the repository. /// /// The ID of the product to update. - /// The updated product. + /// The updated product. /// The updated product. public async Task> UpdateProduct(IEnumerable id, IEnumerable productDtoUpdate, CancellationToken cancellationToken) { @@ -104,16 +99,21 @@ public class ProductInfrastructureRepository(IMemoryCache memoryCache,Dependency /// The products in the category. public async Task> GetProductsByCategoryId(IEnumerable id, CancellationToken cancellationToken) { + var cacheId = id; - var ProductCategory = await _dependencyInjection._appContext.Products - .Include(a => a.Assessment) - .ThenInclude(r => r.RevisionDetail) - .Include(a => a.Attributes) - .Include(a => a.Availability) - .Include(i => i.Image) - .Where(p => id.Contains(p.CategoryId)).ToListAsync(cancellationToken); + if (!_memoryCache.TryGetValue(cacheId, out IEnumerable? productsCategories)) + { + productsCategories = await _dependencyInjection._appContext.Products + .Include(a => a.Assessment) + .ThenInclude(r => r.RevisionDetail) + .Include(a => a.Attributes) + .Include(a => a.Availability) + .Include(i => i.Image) + .Take(5) + .Where(p => id.Contains(p.CategoryId)).ToListAsync(cancellationToken); + } - var categoryResultDto = _dependencyInjection._mapper.Map>(ProductCategory); + var categoryResultDto = _dependencyInjection._mapper.Map>(productsCategories); await _productAppService.GetProductsByCategoryId(id, categoryResultDto, cancellationToken); @@ -189,16 +189,23 @@ public class ProductInfrastructureRepository(IMemoryCache memoryCache,Dependency /// The product. public async Task> GetProductById(IEnumerable id, CancellationToken cancellationToken) { - var product = await _dependencyInjection._appContext.Products - .Include(a => a.Assessment) - .ThenInclude(r => r.RevisionDetail) - .Include(d => d.Dimensions) - .Include(a => a.Attributes) - .Include(a => a.Availability) - .Include(i => i.Image) - .Where(p => id.Contains(p.Id)).ToListAsync(cancellationToken); + var cacheId = id; + if (!_memoryCache.TryGetValue(cacheId, out IEnumerable? products)) + { + products = await _dependencyInjection._appContext.Products + .Include(a => a.Assessment) + .ThenInclude(r => r.RevisionDetail) + .Include(d => d.Dimensions) + .Include(a => a.Attributes) + .Include(a => a.Availability) + .Include(i => i.Image) + .AsNoTracking() + .Take(5) + .Where(p => id.Contains(p.Id)) + .ToListAsync(cancellationToken); + } - var productResultDto = _dependencyInjection._mapper.Map>(product); + var productResultDto = _dependencyInjection._mapper.Map>(products); var productResult = await _productAppService.GetProductById(id, productResultDto, cancellationToken); @@ -206,13 +213,18 @@ public class ProductInfrastructureRepository(IMemoryCache memoryCache,Dependency } - public async Task> GetAll(int page, int pageSize, CancellationToken cancellationToken) - { + public async Task> GetAll(int page, int pageSize, CancellationToken cancellationToken) + { var cacheKey = $"products_{page}_{pageSize}"; - if (!_memoryCache.TryGetValue(cacheKey, out IEnumerable products)) + if (!_memoryCache.TryGetValue(cacheKey, out IEnumerable? products)) { products = await _dependencyInjection._appContext.Products + .Include(a => a.Assessment) + .ThenInclude(r => r.RevisionDetail) + .Include(d => d.Dimensions) + .Include(a => a.Attributes) + .Include(a => a.Availability) .Include(i => i.Image) .AsNoTracking() .Skip((page - 1) * pageSize) @@ -226,24 +238,7 @@ public class ProductInfrastructureRepository(IMemoryCache memoryCache,Dependency var productResultDto = _dependencyInjection._mapper.Map>(products); return productResultDto; - - - //var products = await _dependencyInjection._appContext.Products - // .Include(a => a.Assessment) - // .ThenInclude(r => r.RevisionDetail) - // .Include(d => d.Dimensions) - // .Include(a => a.Attributes) - // .Include(a => a.Availability) - // .Include(i => i.Image) - // .AsNoTracking() - // .Skip((pageNumber - 1) * pageSize) - // .Take(pageSize) - // .ToListAsync(cancellationToken); - - //var productResultDto = _dependencyInjection._mapper.Map>(products); - - //return productResultDto; - } + } /// /// Checks if any products with the specified names exist in the database. diff --git a/Blazing.infrastructure/Blazing.Ecommerce/Service/UserInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Ecommerce/Repository/UserInfrastructureRepository.cs similarity index 82% rename from Blazing.infrastructure/Blazing.Ecommerce/Service/UserInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Ecommerce/Repository/UserInfrastructureRepository.cs index daea978..8eb8597 100644 --- a/Blazing.infrastructure/Blazing.Ecommerce/Service/UserInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Ecommerce/Repository/UserInfrastructureRepository.cs @@ -1,18 +1,21 @@ using Blazing.Application.Dto; -using Blazing.Application.Interfaces.User; +using Blazing.Application.Interface.User; using Blazing.Domain.Entities; using Blazing.Domain.Exceptions; using Blazing.Domain.Exceptions.User; using Blazing.Ecommerce.Dependency; -using Blazing.Ecommerce.Repository; +using Blazing.Ecommerce.Interface; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; -namespace Blazing.Ecommerce.Service +namespace Blazing.Ecommerce.Repository { #region InfraEcommerceUserDtoRepository. - public class UserInfrastructureRepository(IUserAppService userAppService, DependencyInjection dependencyInjection) : IUserInfrastructureRepository + public class UserInfrastructureRepository(IMemoryCache memoryCache, + IUserAppService userAppService, DependencyInjection dependencyInjection) : IUserInfrastructureRepository { + private readonly IMemoryCache _memoryCache = memoryCache; private readonly IUserAppService _userAppService = userAppService; private readonly DependencyInjection _dependencyInjection = dependencyInjection; @@ -44,31 +47,33 @@ public class UserInfrastructureRepository(IUserAppService userAppServic /// The updated UserDto. /// /// The updated UserDto. - public async Task> UpdateUsers(IEnumerable id, IEnumerable usersDtoUpdate, CancellationToken cancellationToken) + public async Task> UpdateUsers(IEnumerable id, IEnumerable usersDtoUpdate, + CancellationToken cancellationToken) { - if (!id.Any() || Guid.Empty == id.First()) + var enumerable = id.ToList(); + if (enumerable.Count == 0 || Guid.Empty == enumerable.First()) { - throw DomainException.IdentityInvalidException.Identities(id); + throw DomainException.IdentityInvalidException.Identities(enumerable); } - // Obtém os usuários existentes com suas propriedades relacionadas carregadas var existingUsers = await _dependencyInjection._appContext.Users .Include(u => u.Addresses) .Include(u => u.ShoppingCarts) - .Where(u => id.Contains(u.Id)).ToListAsync(cancellationToken); + .Where(u => enumerable.Contains(u.Id)).ToListAsync(cancellationToken); - if (!existingUsers.Any()) + if (existingUsers.Count == 0) { throw UserException.UserNotFoundException.UserNotFound(existingUsers); } var usersExistingDto = _dependencyInjection._mapper.Map>(existingUsers); - usersDtoUpdate = await _userAppService.UpdateUsers(id, usersExistingDto, usersDtoUpdate, cancellationToken ); + usersDtoUpdate = await _userAppService.UpdateUsers(enumerable, usersExistingDto, usersDtoUpdate, cancellationToken ); var users = _dependencyInjection._mapper.Map>(usersDtoUpdate); - foreach (var userDto in usersDtoUpdate) + var updateUsers = usersDtoUpdate.ToList(); + foreach (var userDto in updateUsers) { var existingUser = existingUsers.SingleOrDefault(u => u.Id == userDto.Id); await UpdateUserDetailsAsync(userDto, existingUser, cancellationToken); @@ -99,7 +104,7 @@ public class UserInfrastructureRepository(IUserAppService userAppServic await _dependencyInjection._appContext.SaveChangesAsync(cancellationToken); // Retorna os DTOs atualizados - return usersDtoUpdate; + return updateUsers; } /// @@ -112,7 +117,7 @@ public class UserInfrastructureRepository(IUserAppService userAppServic /// /// Thrown if the users name or email already exists and is different from the existing user. /// - private async Task UpdateUserDetailsAsync(UserDto originalUserDto, User updatedUserDto, CancellationToken cancellationToken) + private async Task UpdateUserDetailsAsync(UserDto? originalUserDto, User? updatedUserDto, CancellationToken cancellationToken) { var userNameExists = await IsUserNameExistsAsync(originalUserDto.UserName, cancellationToken); var emailExists = await IsUserEmailExistsAsync(originalUserDto.Email, cancellationToken); @@ -170,7 +175,7 @@ private async Task UpdateUserDetailsAsync(UserDto originalUserDto, User updatedU } } - var usersDto = _dependencyInjection._mapper.Map>(users); + IEnumerable usersDto = _dependencyInjection._mapper.Map>(users); usersDto = await _userAppService.DeleteUsers(id, usersDto, cancellationToken); @@ -189,12 +194,19 @@ private async Task UpdateUserDetailsAsync(UserDto originalUserDto, User updatedU /// A collection of UserDto objects corresponding to the given IDs. public async Task> GetUsersById(IEnumerable id, CancellationToken cancellationToken) { - var users = await _dependencyInjection._appContext.Users - .Include(a => a.Addresses) - .Where(p => id.Contains(p.Id)).ToListAsync(cancellationToken); - + var cacheId = id; + if (!_memoryCache.TryGetValue(cacheId, out IEnumerable? users)) + { + users = await _dependencyInjection._appContext.Users + .Include(a => a.Addresses) + .AsNoTracking() + .Take(5) + .Where(p => id.Contains(p.Id)) + .ToListAsync(cancellationToken); + + _memoryCache.Set(cacheId, users, TimeSpan.FromMinutes(5)); + } var usersResultDto = _dependencyInjection._mapper.Map>(users); - var result = await _userAppService.GetUserById(id, usersResultDto, cancellationToken); return result; @@ -204,13 +216,25 @@ private async Task UpdateUserDetailsAsync(UserDto originalUserDto, User updatedU /// Retrieves all UserDto objects from the repository. /// This method includes related entities such as addresses. /// + /// + /// /// The cancellation token to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a collection of UserDto objects. - public async Task> GetAllUsers(CancellationToken cancellationToken) + public async Task> GetAllUsers(int page, int pageSize,CancellationToken cancellationToken) { - var users = await _dependencyInjection._appContext.Users - .Include(a => a.Addresses) - .ToListAsync(cancellationToken); + var userCache = $"{page}_{pageSize}"; + + if (!_memoryCache.TryGetValue(userCache, out IEnumerable? users)) + { + users = await _dependencyInjection._appContext.Users + .Include(a => a.Addresses) + .AsNoTracking() + .Skip((page - 1) * pageSize ) + .Take(pageSize) + .ToListAsync(cancellationToken); + + _memoryCache.Set(userCache, users, TimeSpan.FromMinutes(5)); + } var productResultDto = _dependencyInjection._mapper.Map>(users); diff --git a/Blazing.infrastructure/Blazing.Identity/Dependencies/ConfigServiceCollectionExtensionsInfraIdentity.cs b/Blazing.infrastructure/Blazing.Identity/Dependencies/ConfigServiceCollectionExtensionsInfraIdentity.cs new file mode 100644 index 0000000..c356503 --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Dependencies/ConfigServiceCollectionExtensionsInfraIdentity.cs @@ -0,0 +1,81 @@ +using Blazing.Application.Dto; +using Blazing.Application.Interface.User; +using Blazing.Application.Services; +using Blazing.Domain.Entities; +using Blazing.Domain.Interfaces.Services; +using Blazing.Domain.Services; +using Blazing.Ecommerce.Interface; +using Blazing.Ecommerce.Repository; +using Blazing.Identity.Data; +using Blazing.Identity.Dependency; +using Blazing.Identity.Entities; +using Blazing.Identity.Mappings; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Blazing.Identity.Dependencies +{ + public static class ConfigServiceCollectionExtensionsInfraIdentity + { + public static IServiceCollection AddConfigInfraIdentity( + this IServiceCollection services, IConfiguration config) + { + services.AddDbContext(options => + options.UseSqlServer(config.GetConnectionString("Blazing"), + b => b.MigrationsAssembly("Blazing.Identity"))); + + services.AddIdentity(options => + { + options.SignIn.RequireConfirmedAccount = true; + }) + .AddEntityFrameworkStores() + .AddDefaultUI() + .AddDefaultTokenProviders(); + + + services.Configure(options => + { + // Password settings + options.Password.RequireDigit = true; + options.Password.RequireLowercase = true; + options.Password.RequireUppercase = true; + options.Password.RequireNonAlphanumeric = false; + options.Password.RequiredLength = 8; + options.Password.RequiredUniqueChars = 0; + + // Lockout settings + options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); + options.Lockout.MaxFailedAccessAttempts = 5; + options.Lockout.AllowedForNewUsers = true; + + // User settings + options.User.AllowedUserNameCharacters = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; + options.User.RequireUniqueEmail = true; + + options.SignIn.RequireConfirmedEmail = true; + }); + + services.AddAutoMapper(typeof(IdentityMapper)); + // Configure Authorization + services.AddAuthorization(); + + // Register additional services + services.AddScoped(); + services.AddScoped(); + + // Users + services.AddScoped, UserDomainService>(); + services.AddScoped, UserAppService>(); + services.AddScoped(); + services.AddScoped(); + + // Roles + services.AddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/Blazing.infrastructure/Blazing.Identity/Dependencies/ConfigServiceCollectionExtensiosInfraIdentity.cs b/Blazing.infrastructure/Blazing.Identity/Dependencies/ConfigServiceCollectionExtensiosInfraIdentity.cs deleted file mode 100644 index 7318ec7..0000000 --- a/Blazing.infrastructure/Blazing.Identity/Dependencies/ConfigServiceCollectionExtensiosInfraIdentity.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Blazing.Application.Dto; -using Blazing.Application.Interfaces.User; -using Blazing.Application.Services; -using Blazing.Domain.Entities; -using Blazing.Domain.Interfaces.Services; -using Blazing.Domain.Services; -using Blazing.Ecommerce.Repository; -using Blazing.Ecommerce.Service; -using Blazing.Identity.Data; -using Blazing.Identity.Dependency; -using Blazing.Identity.Entities; -using Blazing.Identity.Mappings; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace Blazing.Identity.Dependencies; - -public static class ConfigServiceCollectionExtensionsInfraIdentity -{ - public static IServiceCollection AddConfigInfraIdentity( - this IServiceCollection services, IConfiguration config) - { - services.AddDbContext(options => - options.UseSqlServer(config.GetConnectionString("Blazing"), b => b.MigrationsAssembly("Blazing.Identity"))); - - - services.AddIdentity(options => - { - options.SignIn.RequireConfirmedAccount = true; - }) - .AddEntityFrameworkStores() - .AddDefaultUI() - .AddDefaultTokenProviders(); - - - services.Configure(options => - { - // // Password settings - options.Password.RequireDigit = true; - options.Password.RequireLowercase = true; - options.Password.RequireUppercase = true; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequiredLength = 8; - options.Password.RequiredUniqueChars = 0; - - // Lockout settings - options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); - options.Lockout.MaxFailedAccessAttempts = 5; - options.Lockout.AllowedForNewUsers = true; - - // User settings - options.User.AllowedUserNameCharacters = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; - options.User.RequireUniqueEmail = true; - - options.SignIn.RequireConfirmedEmail = true; - }); - - - // Configure Authorization - services.AddAuthorization(); - - // Register additional services - services.AddScoped(); - services.AddScoped(); - - services.AddScoped, UserDomainService>(); - services.AddScoped, UserAppService>(); - services.AddScoped(); - services.AddScoped(); - - return services; - } -} \ No newline at end of file diff --git a/Blazing.infrastructure/Blazing.Identity/Dependencies/DependencyInjection.cs b/Blazing.infrastructure/Blazing.Identity/Dependencies/DependencyInjection.cs index a53a7ef..1cd9f7f 100644 --- a/Blazing.infrastructure/Blazing.Identity/Dependencies/DependencyInjection.cs +++ b/Blazing.infrastructure/Blazing.Identity/Dependencies/DependencyInjection.cs @@ -5,9 +5,9 @@ namespace Blazing.Identity.Dependency { - public class DependencyInjection(BlazingIdentityDbContext IdentityAppDbContext, IMapper mapper) + public class DependencyInjection(BlazingIdentityDbContext? IdentityAppDbContext, IMapper mapper) { - public readonly BlazingIdentityDbContext _appContext = IdentityAppDbContext; + public readonly BlazingIdentityDbContext? _appContext = IdentityAppDbContext; public readonly IMapper _mapper = mapper; } diff --git a/Blazing.infrastructure/Blazing.Identity/Dto/ApplicationRoleDto.cs b/Blazing.infrastructure/Blazing.Identity/Dto/ApplicationRoleDto.cs new file mode 100644 index 0000000..a672faa --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Dto/ApplicationRoleDto.cs @@ -0,0 +1,12 @@ + + +namespace Blazing.Identity.Dto +{ + /// + /// Represents a role in the application. + /// + public record ApplicationRoleDto(Guid Id, string Name, string Description, int Page, int PageSize); + +} + + \ No newline at end of file diff --git a/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRole.cs b/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRole.cs index 4703332..d6cd19d 100644 --- a/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRole.cs +++ b/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRole.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -8,9 +9,15 @@ namespace Blazing.Identity.Entities { - public partial class ApplicationRole : IdentityRole + public partial class ApplicationRole() : IdentityRole { [StringLength(256)] - public string Description { get; set; } = ""; + public string Description { get; set; } = string.Empty; + + [NotMapped] + public int Page { get; set; } + + [NotMapped] + public int PageSize { get; set; } } } diff --git a/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRoleClaim.cs b/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRoleClaim.cs index 2660c79..ec7d0f8 100644 --- a/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRoleClaim.cs +++ b/Blazing.infrastructure/Blazing.Identity/Entities/ApplicationRoleClaim.cs @@ -9,8 +9,8 @@ namespace Blazing.Identity.Entities { public partial class ApplicationRoleClaim : IdentityRoleClaim { - //public DateTime DataCreated { get; set; } = DateTime.Now; - //public DateTime DataUpdated { get; set; } - //public DateTime DataDeleted { get; set; } + public DateTime DataCreated { get; set; } = DateTime.Now; + public DateTime DataUpdated { get; set; } + public DateTime DataDeleted { get; set; } } } diff --git a/Blazing.infrastructure/Blazing.Identity/Entities/Login.cs b/Blazing.infrastructure/Blazing.Identity/Entities/Login.cs index 152deda..26adda9 100644 --- a/Blazing.infrastructure/Blazing.Identity/Entities/Login.cs +++ b/Blazing.infrastructure/Blazing.Identity/Entities/Login.cs @@ -6,30 +6,30 @@ namespace Blazing.Identity.Entities { - public record class Login + public record Login { - public string Email { get; protected set; } = string.Empty; + public string LoginIdentifier { get; protected set; } = string.Empty; public string Password { get; protected set; } = string.Empty; public string TwoFactorCode { get; protected set; } public string TwoFactorRecoveryCode { get; protected set; } public bool RememberMe { get; set; } - public Login(string email, string password, string twoFactorCode = "", string twoFactorRecoveryCode = "", bool rememberMe = false) + public Login(string LoginIdentifier, string password, string twoFactorCode = "", string twoFactorRecoveryCode = "", bool rememberMe = false) { - SetEmail(email); + SetLoginIdentifier(LoginIdentifier); SetPassword(password); TwoFactorCode = twoFactorCode; TwoFactorRecoveryCode = twoFactorRecoveryCode; RememberMe = rememberMe; } - public void SetEmail(string email) + public void SetLoginIdentifier(string email) { if (string.IsNullOrWhiteSpace(email)) { throw new ArgumentException("Email cannot be empty", nameof(email)); } - Email = email; + LoginIdentifier = email; } public void SetPassword(string password) diff --git a/Blazing.infrastructure/Blazing.Identity/Interface/ICrudInfrastructureIdentityRepository.cs b/Blazing.infrastructure/Blazing.Identity/Interface/ICrudInfrastructureIdentityRepository.cs new file mode 100644 index 0000000..6b87aba --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Interface/ICrudInfrastructureIdentityRepository.cs @@ -0,0 +1,57 @@ +namespace Blazing.Identity.Interface +{ + public interface ICrudInfrastructureIdentityRepository + { + /// + /// Adds a collection of object. + /// + /// A collection of object to be added. + /// A task representing the asynchronous operation, with a collection of the added object. + Task> Add(IEnumerable obj, CancellationToken cancellationToken); + + /// + /// Updates a object by its ID. + /// + /// The ID of the object to be updated. + /// The updated object details. + /// + /// A task representing the asynchronous operation, with the updated object. + Task> Update(IEnumerable id, IEnumerable obj, CancellationToken cancellationToken); + + /// + /// Deletes a collection of object by their IDs. + /// + /// A collection of object IDs to be deleted. + /// A collection of object to be deleted. + /// + /// A task representing the asynchronous operation, with a collection of the deleted object. + Task> Delete(IEnumerable id, IEnumerable obj, CancellationToken cancellationToken); + + /// + /// Retrieves a object by its ID. + /// + /// The ID of the object to be retrieved. + /// + /// A task representing the asynchronous operation, with the object details. + Task> GetById(IEnumerable id, CancellationToken cancellationToken); + + /// + /// Retrieves all object. + /// + /// + /// + /// + /// A task representing the asynchronous operation, with a collection of all object. + Task> GetAll(int page, int pageSize, CancellationToken cancellationToken); + + /// + /// Checks if a specified condition exists asynchronously. + /// + /// A boolean value indicating whether the condition to check exists. + /// + /// + /// + /// A Task representing the asynchronous operation, with a boolean result indicating the existence of the condition. + Task ExistsAsync(bool boolean, bool booleanI, IEnumerable obj, CancellationToken cancellationToken); + } +} diff --git a/Blazing.infrastructure/Blazing.Identity/Interface/IRoleInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Identity/Interface/IRoleInfrastructureRepository.cs new file mode 100644 index 0000000..4f5ef13 --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Interface/IRoleInfrastructureRepository.cs @@ -0,0 +1,13 @@ +using Blazing.Domain.Interfaces.Repository; +using Blazing.Identity.Dto; +using Blazing.Identity.Entities; +using Blazing.Identity.Interface; +using Microsoft.AspNetCore.Identity; + +namespace Blazing.Identity.Interface +{ + public interface IRoleInfrastructureRepository : ICrudInfrastructureIdentityRepository + { + + } +} diff --git a/Blazing.infrastructure/Blazing.Identity/Repository/IUserInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Identity/Interface/IUserInfrastructureRepository.cs similarity index 88% rename from Blazing.infrastructure/Blazing.Identity/Repository/IUserInfrastructureRepository.cs rename to Blazing.infrastructure/Blazing.Identity/Interface/IUserInfrastructureRepository.cs index e2a4f0c..f7da50d 100644 --- a/Blazing.infrastructure/Blazing.Identity/Repository/IUserInfrastructureRepository.cs +++ b/Blazing.infrastructure/Blazing.Identity/Interface/IUserInfrastructureRepository.cs @@ -2,7 +2,7 @@ using Blazing.Identity.Entities; using Microsoft.AspNetCore.Identity; -namespace Blazing.Identity.Repository +namespace Blazing.Identity.Interface { #region ContratcsUserIdentity @@ -19,7 +19,7 @@ public interface IUserInfrastructureRepository Task> GetUsersByIdAsync(IEnumerable id, CancellationToken cancellationToken); - Task> GetAllUsersAsync(CancellationToken cancellationToken); + Task> GetAllUsersAsync(int page, int pageSize, CancellationToken cancellationToken); Task LoginAsync(Login login, CancellationToken cancellationToken); diff --git a/Blazing.infrastructure/Blazing.Identity/Mappings/IdentityMapper.cs b/Blazing.infrastructure/Blazing.Identity/Mappings/IdentityMapper.cs new file mode 100644 index 0000000..e9e5dbc --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Mappings/IdentityMapper.cs @@ -0,0 +1,21 @@ +using AutoMapper; +using Blazing.Identity.Dto; +using Blazing.Identity.Entities; + +namespace Blazing.Identity.Mappings +{ + public class IdentityMapper : Profile + { + public IdentityMapper() + { + CreateMap().ReverseMap(); + //.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) + //.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)) + //.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); + + //.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) + //.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)) + //.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); + } + } +} diff --git a/Blazing.infrastructure/Blazing.Identity/Repository/RoleInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Identity/Repository/RoleInfrastructureRepository.cs new file mode 100644 index 0000000..54237e7 --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Repository/RoleInfrastructureRepository.cs @@ -0,0 +1,194 @@ +using AutoMapper; +using Blazing.Identity.Dependency; +using Blazing.Identity.Entities; +using Blazing.Identity.Dto; +using Blazing.Identity.Interface; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; + +namespace Blazing.Identity.Repository +{ + public class RoleInfrastructureRepository(IMemoryCache memoryCache,DependencyInjection dependencyInjection,RoleManager roleManager) + : IRoleInfrastructureRepository + { + private readonly IMemoryCache _memoryCache = memoryCache; + private readonly DependencyInjection _dependencyInjection = dependencyInjection; + private readonly RoleManager _roleManager = roleManager; + + public async Task> Add(IEnumerable roleDto, CancellationToken cancellationToken) + { + if (roleDto == null || !roleDto.Any()) + { + throw new ArgumentException("A lista de papéis está vazia.", nameof(roleDto)); + } + + var results = new List(); + + foreach (var item in roleDto) + { + if (item == null) + { + results.Add(IdentityResult.Failed(new IdentityError { Description = "Umas das funções fornecidos é nulo." })); + continue; + } + + if (cancellationToken.IsCancellationRequested) + { + results.Add(IdentityResult.Failed(new IdentityError { Description = "Operação cancelada." })); + break; + } + + var roleExists = await _roleManager.RoleExistsAsync(item.Name); + if (roleExists) + { + results.Add(IdentityResult.Failed(new IdentityError { Description = $"O função '{item.Name}' já existe." })); + continue; + } + + var applicationRole = _dependencyInjection._mapper.Map(item); + + var result = await _roleManager.CreateAsync(applicationRole); + UpdateCacheRoles(roleDto); + results.Add(result); + } + + return results; + } + + public async Task> Update(IEnumerable id, IEnumerable roleDto, CancellationToken cancellationToken) + { + if (roleDto == null) + { + throw new ArgumentException("O identificado da função não podem ficar vazios."); + } + + var results = new List(); + foreach (var item in roleDto) + { + var role = await _roleManager.FindByIdAsync(item.Id.ToString()); + if (role == null) + { + throw new InvalidOperationException("O papel do usuário não existe."); + } + + var applicationRole = _dependencyInjection._mapper.Map(item, role); + var result = await _roleManager.UpdateAsync(applicationRole); + results.Add(result); + if (result.Succeeded) + { + UpdateCacheRoles(roleDto); + } + } + + return results; + } + + public Task> Delete(IEnumerable id, IEnumerable obj, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> GetById(IEnumerable id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + + public async Task> GetAll(int page, int pageSize, + CancellationToken cancellationToken) + { + if (page <= 0) + { + throw new ArgumentException("A página deve ser maior que zero.", nameof(page)); + } + + if (pageSize > 50) + { + pageSize = 50; + } + var cacheKey = $"{page}-{pageSize}"; + try + { + if(!_memoryCache.TryGetValue(cacheKey, out IEnumerable? applicationRoles)) + { + applicationRoles = await _dependencyInjection._appContext.Roles + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + + + _memoryCache.Set(cacheKey, applicationRoles, TimeSpan.FromMinutes(5)); + } + var applicationRolesRto = _dependencyInjection._mapper.Map>(applicationRoles); + var result = CacheMemoryManagerRoles(page, pageSize, applicationRolesRto); + + return result; + } + catch (AutoMapperMappingException ex) + { + throw new Exception(ex.Message); + } + } + + public Task ExistsAsync(bool boolean, bool booleanI, IEnumerable obj, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + + private static IEnumerable CacheMemoryManagerRoles(int page, int pageSize, IEnumerable role) + { + return role.Select(item => item with { Page = page, PageSize = pageSize }); + } + + + /// + /// Updates the cache with the provided roles. If the cache already contains roles for the given page and page size, + /// it updates the existing roles with the provided ones. Otherwise, it adds the provided roles to the cache. + /// + /// The roles to update or add to the cache. + private void UpdateCacheRoles(IEnumerable roleDto) + { + if (roleDto == null || !roleDto.Any()) + return; + + var page = roleDto.First().Page; + var pageSize = roleDto.First().PageSize; + var cacheKey = $"{page}-{pageSize}"; + try + { + if (_memoryCache.TryGetValue(cacheKey, out List? cacheAppRole)) + { + var updatedRoles = roleDto.Select(dto => _dependencyInjection._mapper.Map(dto)).ToList(); + + foreach (var updatedRole in updatedRoles) + { + var index = cacheAppRole.FindIndex(r => r.Id == updatedRole.Id); + if (index >= 0) + { + cacheAppRole[index] = updatedRole; + } + else + { + cacheAppRole.Add(updatedRole); + } + } + + _memoryCache.Set(cacheKey, cacheAppRole, TimeSpan.FromMinutes(5)); + } + else + { + var newCacheAppRole = roleDto.Select(dto => _dependencyInjection._mapper.Map(dto)).ToList(); + _memoryCache.Set(cacheKey, newCacheAppRole, TimeSpan.FromMinutes(5)); + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + } +} diff --git a/Blazing.infrastructure/Blazing.Identity/Repository/UserInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Identity/Repository/UserInfrastructureRepository.cs new file mode 100644 index 0000000..fe4c0ed --- /dev/null +++ b/Blazing.infrastructure/Blazing.Identity/Repository/UserInfrastructureRepository.cs @@ -0,0 +1,425 @@ +using Blazing.Application.Dto; +using Blazing.Domain.Exceptions; +using Blazing.Domain.Exceptions.User; +using Blazing.Identity.Dependency; +using Blazing.Identity.Entities; +using Blazing.Identity.Mappings; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using static System.Text.RegularExpressions.Regex; +using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; + +namespace Blazing.Identity.Repository +{ + + #region UserInfraIdentityRepository + + public class UserInfrastructureRepository( + IMemoryCache memoryCache, + DependencyInjection dependencyInjection, + UserManager userManager, + SignInManager signInManager, + BlazingIdentityMapper mapper, + Ecommerce.Interface.IUserInfrastructureRepository userInfrastructureRepository) : Identity.Interface.IUserInfrastructureRepository + { + private readonly IMemoryCache _memoryCache = memoryCache; + private readonly DependencyInjection _dependencyInjection = dependencyInjection; + private readonly UserManager _userManager = userManager; + private readonly SignInManager _signInManager = signInManager; + private readonly BlazingIdentityMapper _mapper = mapper; + private readonly Ecommerce.Interface.IUserInfrastructureRepository _userInfrastructureRepository = userInfrastructureRepository; + + /// + /// Asynchronously adds a collection of users to the repository. + /// + /// An enumerable collection of UserDto objects representing the users to be added. + /// A cancellation token that can be used to cancel the operation. + /// + /// A task that represents the asynchronous operation. The task result contains a UserCreationResult object + /// which contains a list of successful users and a list of failed users. + /// + /// Thrown if the userDto parameter is null. + /// Thrown if any of the users already exist in the repository. + public async Task AddUsersAsync(IEnumerable userDto, + CancellationToken cancellationToken) + { + if (userDto == null) + throw DomainException.NotFoundException.FoundException(); + + var result = (await _mapper.UserMapperApplicationUser(userDto, cancellationToken)) + .Where(u => true) + .ToList(); + + await ExistsAsync(result, cancellationToken); + + var userCreationResult = new UserCreationResult + { + SuccessfulUsers = [], + FailedUsers = [] + }; + + + foreach (var item in result) + { + item.CreationDate = DateTime.Now; + item.EmailConfirmed = true; + item.LockoutEnabled = false; + + var identityResult = await _userManager.CreateAsync(item, item.PasswordHash!); + if (identityResult.Succeeded) + userCreationResult.SuccessfulUsers.Add(item); + else + userCreationResult.FailedUsers = identityResult.Errors.ToArray(); + } + + userDto = await _mapper.UserMapperAddedDto(userCreationResult.SuccessfulUsers!, userDto, cancellationToken); + + await _userInfrastructureRepository.AddUsers(userDto, cancellationToken); + + return userCreationResult; + } + + + /// + /// Updates users in the repository asynchronously. + /// + /// An enumerable collection of UserDto objects representing the users to be updated. + /// A cancellation token that can be used to cancel the operation. + /// + /// A task that represents the asynchronous operation. The task result contains a UserCreationResult object + /// which contains a list of successful users and a list of failed users. + /// + /// Thrown if the userDto parameter is null. + /// Thrown if any of the users do not exist in the repository. + public async Task UpdateUsersAsync(IEnumerable userDto, + CancellationToken cancellationToken) + { + if (userDto == null) + throw DomainException.NotFoundException.FoundException(); + + var userCreationResult = new UserCreationResult + { + SuccessfulUsers = [], + FailedUsers = [] + }; + + var userDtoUpdate = await _userInfrastructureRepository.UpdateUsers(userDto.Select(u => u.Id).ToList(), + userDto, cancellationToken); + + foreach (var item in userDtoUpdate) + { + var user = await _userManager.FindByIdAsync(item.Id.ToString()); + if (user == null) + continue; + + var result = await UpdateUserDetailsAsync(user, item, cancellationToken); + if (result.Succeeded) + userCreationResult.SuccessfulUsers.Add(user); + else + userCreationResult.FailedUsers = result.Errors.ToArray(); + } + + return userCreationResult; + } + + /// + /// Asynchronously updates the details of an application user based on the provided user DTO. + /// + /// The application user to update. + /// The user DTO containing the updated details. + /// The cancellation token. + /// A task representing the asynchronous operation. The task result contains the result of the update operation. + /// + /// Thrown if the users name or email already exists and is different from the existing user. + /// + private async Task UpdateUserDetailsAsync(ApplicationUser user, UserDto userDto, + CancellationToken cancellationToken) + { + var userNameExists = await IsUserNameExistsAsync(userDto.UserName, cancellationToken); + var emailExists = await IsEmailExistsAsync(userDto.Email, cancellationToken); + + if (userNameExists) + { + if (user.UserName == userDto.UserName) + { + } + else + { + throw UserException.UserAlreadyExistsException.FromNameExistingUser(userDto.UserName.ToString()); + } + } + + if (emailExists) + { + if (user.Email == userDto.Email) + { + } + else + { + throw UserException.UserAlreadyExistsException.FromEmailExistingUser(userDto.Email.ToString()); + } + } + + user.FirstName = userDto.FirstName; + user.UserName = userDto.UserName; + user.LastName = userDto.LastName; + user.Email = userDto.Email; + user.UserName = userDto.UserName; + user.LastUpdate = DateTime.Now; + + return await _userManager.UpdateAsync(user); + } + + /// + /// Deletes users by their IDs asynchronously. + /// + /// A collection of user IDs to be deleted. + /// A cancellation token to cancel the operation. + /// + /// A task representing the asynchronous operation, with a result of + /// containing the list of successfully deleted users and the list of users that failed to be deleted. + /// + /// Thrown when the provided ID collection is null or empty. + public async Task DeleteUsersAsync(IEnumerable id, + CancellationToken cancellationToken) + { + if (id == null || !id.Any()) + throw DomainException.NotFoundException.FoundException(); + + var userCreationResult = new UserCreationResult + { + SuccessfulUsers = [], + FailedUsers = [] + }; + + var idGuid = id.Select(Guid.Parse).ToList(); + await _userInfrastructureRepository.DeleteUsers(idGuid, cancellationToken); + + foreach (var item in id) + { + cancellationToken.ThrowIfCancellationRequested(); + + var user = await _userManager.FindByIdAsync(item); + if (user == null) continue; + var resultIdentity = await _userManager.DeleteAsync(user); + if (resultIdentity.Succeeded) + userCreationResult.SuccessfulUsers.Add(user); + else + userCreationResult.FailedUsers = resultIdentity.Errors.ToArray(); + } + + return userCreationResult; + } + + /// + /// Retrieves a collection of UserDto objects based on their IDs. + /// + /// A collection of IDs of the UserDto objects to retrieve. + /// A cancellation token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. The task result contains a collection of UserDto objects. + public async Task> GetUsersByIdAsync(IEnumerable id, + CancellationToken cancellationToken) + { + var result = await _userInfrastructureRepository.GetUsersById(id, cancellationToken); + + return result; + } + + /// + /// Retrieves all UserDto objects from the repository asynchronously. + /// + /// The cancellation token to cancel the operation. + /// A task that represents the asynchronous operation. The task result contains a collection of UserDto objects. + /// Thrown when no UserDto objects are found in the repository. + public async Task> GetAllUsersAsync(int page, int pageSize, + CancellationToken cancellationToken) + { + var resultDto = await _userInfrastructureRepository.GetAllUsers(page, pageSize, cancellationToken); + + return resultDto; + } + + /// + /// Asynchronously logs in a user with the provided email and password. + /// + /// The email of the user to log in. + /// The password of the user to log in. + /// A boolean indicating whether to remember the user's login. + /// A cancellation token that can be used to cancel the operation. + /// A Task that represents the asynchronous operation. The task result contains the result of the login attempt. + public async Task LoginAsync(Login login, CancellationToken cancellationToken) + { + const string emailPattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"; + + var isEmail = IsMatch(login.LoginIdentifier, emailPattern); + + + if (isEmail) + { + return await LoginWithEmailAsync(login); + } + else + { + return await LoginWithUsernameAsync(login); + } + } + + /// + /// Asynchronously logs in a user with the provided email and password. + /// + /// The login details of the user to log in. + /// A Task that represents the asynchronous operation. The task result contains the result of the login attempt. + private async Task LoginWithEmailAsync(Login login) + { + var user = await _userManager.FindByEmailAsync(login.LoginIdentifier); + + if (user == null) + { + return SignInResult.Failed; + } + + var result = await _signInManager.CheckPasswordSignInAsync(user, login.Password, true); + + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, login.RememberMe); + } + + if (result.IsLockedOut) + { + throw UserException.UserLockedOutException.FromLockedOutExceptionEmail(user.Email); + } + + return result; + } + + /// + /// Asynchronously logs in a user with the provided username and password. + /// + /// The login details of the user to log in. + /// A Task that represents the asynchronous operation. The task result contains the result of the login attempt. + private async Task LoginWithUsernameAsync(Login login) + { + var result = + await _signInManager.PasswordSignInAsync(login.LoginIdentifier, login.Password, login.RememberMe, true); + + if (result.IsLockedOut) + { + throw UserException.UserLockedOutException.FromLockedOutExceptionUserName(login.LoginIdentifier); + } + + return result; + } + + /// + /// Generates a password reset token for the user with the specified email. + /// + /// The email address of the user. + /// A cancellation token that can be used to cancel the operation. + /// The generated password reset token. + /// Thrown if the user with the specified email is not found. + public async Task GeneratePasswordResetTokenAsync(string email, CancellationToken cancellationToken) + { + var user = await _userManager.FindByEmailAsync(email) ?? + throw UserException.UserNotFoundException.UserNotFoundEmail(email); + + + var token = await _userManager.GeneratePasswordResetTokenAsync(user); + + await Task.CompletedTask; + + return token; + } + + /// + /// Resets the password for a user with the specified email using the provided token and new password. + /// + /// The email of the user whose password is to be reset. + /// The token used to reset the password. + /// The new password to set for the user. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the result of the password reset operation. + /// Thrown when the user with the specified email is not found. + public async Task ResetPasswordAsync(string email, string token, string newPassword, + CancellationToken cancellation) + { + var user = await _userManager.FindByEmailAsync(email) ?? + throw UserException.UserNotFoundException.UserNotFoundEmail(email); + + + var result = await _userManager.ResetPasswordAsync(user, token, newPassword); + + await Task.CompletedTask; + + return result; + } + + /// + /// Checks if the specified userDto exist in the repository. + /// + /// A collection of objects to check for existence. + /// + /// + /// A task representing the asynchronous operation, with a result indicating whether the userDto exist ( + /// true if they exist, false otherwise). + /// + public async Task ExistsAsync(IEnumerable userIdentity, + CancellationToken cancellationToken) + { + var userDto = (await _mapper.UserMapperDto(userIdentity, cancellationToken)) + .ToList(); + + foreach (var item in userDto) + { + if (await IsUserIdExistsAsync(item.Id.ToString(), cancellationToken)) + throw UserException.UserAlreadyExistsException.FromExistingId(item.Id.ToString()); + + if (await IsUserNameExistsAsync(item.UserName, cancellationToken)) + throw UserException.UserAlreadyExistsException.FromNameExistingUser(item.UserName.ToString()); + + if (await IsEmailExistsAsync(item.Email, cancellationToken)) + throw UserException.UserAlreadyExistsException.FromEmailExistingUser(item.Email.ToString()); + } + + return false; + } + + /// + /// Checks if a user with the specified ID exists in the database. + /// + /// The ID of the user to check. + /// A cancellation token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the user exists. + private async Task IsUserIdExistsAsync(string userId, CancellationToken cancellationToken) + { + var id = Guid.Parse(userId); + return await _dependencyInjection._appContext.Users.AnyAsync(u => u.Id == id, cancellationToken); + } + + /// + /// Checks if a user with the specified username exists in the database. + /// + /// The username of the user to check. + /// A cancellation token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the user exists. + private async Task IsUserNameExistsAsync(string? userName, CancellationToken cancellationToken) + { + return await _dependencyInjection._appContext.Users.AnyAsync(u => u.UserName == userName, + cancellationToken); + } + + /// + /// Checks if a user with the specified email exists in the database. + /// + /// The email of the user to check. + /// A cancellation token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the user exists. + private async Task IsEmailExistsAsync(string? email, CancellationToken cancellationToken) + { + return await _dependencyInjection._appContext.Users.AnyAsync(u => u.Email == email, cancellationToken); + } + } +} + +#endregion \ No newline at end of file diff --git a/Blazing.infrastructure/Blazing.Identity/Service/UserInfrastructureRepository.cs b/Blazing.infrastructure/Blazing.Identity/Service/UserInfrastructureRepository.cs deleted file mode 100644 index 0b7de88..0000000 --- a/Blazing.infrastructure/Blazing.Identity/Service/UserInfrastructureRepository.cs +++ /dev/null @@ -1,388 +0,0 @@ -using Blazing.Application.Dto; -using Blazing.Domain.Entities; -using Blazing.Domain.Exceptions; -using Blazing.Domain.Exceptions.User; -using Blazing.Ecommerce.Repository; -using Blazing.Identity.Dependency; -using Blazing.Identity.Entities; -using Blazing.Identity.Mappings; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; - -namespace Blazing.Identity.Service; - -#region UserInfraIdentityRepository - -public class UserInfrastructureRepository( - DependencyInjection dependencyInjection, - UserManager userManager, - SignInManager signInManager, - BlazingIdentityMapper mapper, - IUserInfrastructureRepository userInfrastructureRepository) : Repository.IUserInfrastructureRepository -{ - private readonly DependencyInjection _dependencyInjection = dependencyInjection; - private readonly UserManager _userManager = userManager; - private readonly SignInManager _signInManager = signInManager; - private readonly BlazingIdentityMapper _mapper = mapper; - private readonly IUserInfrastructureRepository _userInfrastructureRepository = userInfrastructureRepository; - - /// - /// Asynchronously adds a collection of users to the repository. - /// - /// An enumerable collection of UserDto objects representing the users to be added. - /// A cancellation token that can be used to cancel the operation. - /// - /// A task that represents the asynchronous operation. The task result contains a UserCreationResult object - /// which contains a list of successful users and a list of failed users. - /// - /// Thrown if the userDto parameter is null. - /// Thrown if any of the users already exist in the repository. - public async Task AddUsersAsync(IEnumerable userDto, - CancellationToken cancellationToken) - { - if (userDto == null) - throw DomainException.NotFoundException.FoundException(); - - var result = (await _mapper.UserMapperApplicationUser(userDto, cancellationToken)) - .Where(u => true) - .ToList(); - - await ExistsAsync(result, cancellationToken); - - var userCreationResult = new UserCreationResult - { - SuccessfulUsers = [], - FailedUsers = [] - }; - - - foreach (var item in result) - { - item.CreationDate = DateTime.Now; - item.EmailConfirmed = true; - item.LockoutEnabled = false; - - var identityResult = await _userManager.CreateAsync(item, item.PasswordHash!); - if (identityResult.Succeeded) - userCreationResult.SuccessfulUsers.Add(item); - else - userCreationResult.FailedUsers = identityResult.Errors.ToArray(); - } - - userDto = await _mapper.UserMapperAddedDto(userCreationResult.SuccessfulUsers!, userDto, cancellationToken); - - await _userInfrastructureRepository.AddUsers(userDto, cancellationToken); - - return userCreationResult; - } - - - /// - /// Updates users in the repository asynchronously. - /// - /// An enumerable collection of UserDto objects representing the users to be updated. - /// A cancellation token that can be used to cancel the operation. - /// - /// A task that represents the asynchronous operation. The task result contains a UserCreationResult object - /// which contains a list of successful users and a list of failed users. - /// - /// Thrown if the userDto parameter is null. - /// Thrown if any of the users do not exist in the repository. - public async Task UpdateUsersAsync(IEnumerable userDto, - CancellationToken cancellationToken) - { - if(userDto == null) - throw DomainException.NotFoundException.FoundException(); - - var userCreationResult = new UserCreationResult - { - SuccessfulUsers = [], - FailedUsers = [] - }; - - var userDtoUpdate = await _userInfrastructureRepository.UpdateUsers(userDto.Select(u => u.Id).ToList(), - userDto, cancellationToken); - - foreach(var item in userDtoUpdate) - { - var user = await _userManager.FindByIdAsync(item.Id.ToString()); - if (user == null) - continue; - - var result = await UpdateUserDetailsAsync(user, item, cancellationToken); - if (result.Succeeded) - userCreationResult.SuccessfulUsers.Add(user); - else - userCreationResult.FailedUsers = result.Errors.ToArray(); - } - - return userCreationResult; - } - - /// - /// Asynchronously updates the details of an application user based on the provided user DTO. - /// - /// The application user to update. - /// The user DTO containing the updated details. - /// The cancellation token. - /// A task representing the asynchronous operation. The task result contains the result of the update operation. - /// - /// Thrown if the users name or email already exists and is different from the existing user. - /// - private async Task UpdateUserDetailsAsync(ApplicationUser user, UserDto userDto, - CancellationToken cancellationToken) - { - var userNameExists = await IsUserNameExistsAsync(userDto.UserName, cancellationToken); - var emailExists = await IsEmailExistsAsync(userDto.Email, cancellationToken); - - if (userNameExists) - { - if (user.UserName == userDto.UserName) - { - } - else - { - throw UserException.UserAlreadyExistsException.FromNameExistingUser(userDto.UserName.ToString()); - } - } - - if (emailExists) - { - if (user.Email == userDto.Email) - { - } - else - { - throw UserException.UserAlreadyExistsException.FromEmailExistingUser(userDto.Email.ToString()); - } - } - - user.FirstName = userDto.FirstName; - user.UserName = userDto.UserName; - user.LastName = userDto.LastName; - user.Email = userDto.Email; - user.UserName = userDto.UserName; - user.LastUpdate = DateTime.Now; - - return await _userManager.UpdateAsync(user); - } - - /// - /// Deletes users by their IDs asynchronously. - /// - /// A collection of user IDs to be deleted. - /// A cancellation token to cancel the operation. - /// - /// A task representing the asynchronous operation, with a result of - /// containing the list of successfully deleted users and the list of users that failed to be deleted. - /// - /// Thrown when the provided ID collection is null or empty. - public async Task DeleteUsersAsync(IEnumerable id, CancellationToken cancellationToken) - { - if (id == null || !id.Any()) - throw DomainException.NotFoundException.FoundException(); - - var userCreationResult = new UserCreationResult - { - SuccessfulUsers = [], - FailedUsers = [] - }; - - var idGuid = id.Select(Guid.Parse).ToList(); - await _userInfrastructureRepository.DeleteUsers(idGuid, cancellationToken); - - foreach (var item in id) - { - cancellationToken.ThrowIfCancellationRequested(); - - var user = await _userManager.FindByIdAsync(item); - if (user == null) continue; - var resultIdentity = await _userManager.DeleteAsync(user); - if (resultIdentity.Succeeded) - userCreationResult.SuccessfulUsers.Add(user); - else - userCreationResult.FailedUsers = resultIdentity.Errors.ToArray(); - } - - return userCreationResult; - } - - /// - /// Retrieves a collection of UserDto objects based on their IDs. - /// - /// A collection of IDs of the UserDto objects to retrieve. - /// A cancellation token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. The task result contains a collection of UserDto objects. - public async Task> GetUsersByIdAsync(IEnumerable id, - CancellationToken cancellationToken) - { - var result = await _userInfrastructureRepository.GetUsersById(id, cancellationToken); - - return result; - } - - /// - /// Retrieves all UserDto objects from the repository asynchronously. - /// - /// The cancellation token to cancel the operation. - /// A task that represents the asynchronous operation. The task result contains a collection of UserDto objects. - /// Thrown when no UserDto objects are found in the repository. - public async Task> GetAllUsersAsync(CancellationToken cancellationToken) - { - var resultDto = await _userInfrastructureRepository.GetAllUsers(cancellationToken); - - return resultDto; - } - - /// - /// Asynchronously logs in a user with the provided email and password. - /// - /// The email of the user to log in. - /// The password of the user to log in. - /// A boolean indicating whether to remember the user's login. - /// A cancellation token that can be used to cancel the operation. - /// A Task that represents the asynchronous operation. The task result contains the result of the login attempt. - public async Task LoginAsync(Login login, - CancellationToken cancellationToken) - { - if (!string.IsNullOrEmpty(login.Email) && login.Email.Contains($"@")) - { - var user = await _userManager.FindByEmailAsync(login.Email); - - if (user == null) return SignInResult.Failed; - - var result = await _signInManager.CheckPasswordSignInAsync(user, login.Password, true); - - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, login.RememberMe); - } - else if (result.IsLockedOut == true) - { - throw UserException.UserLockedOutException.FromLockedOutExceptionEmail(user.Email); - } - - return result; - } - else - { - var result = await _signInManager.PasswordSignInAsync(login.Email, login.Password, login.RememberMe, true); - - if (result.IsLockedOut == true) - { - //Login.Email user name - throw UserException.UserLockedOutException.FromLockedOutExceptionUserName(login.Email); - } - return result; - } - - } - - /// - /// Generates a password reset token for the user with the specified email. - /// - /// The email address of the user. - /// A cancellation token that can be used to cancel the operation. - /// The generated password reset token. - /// Thrown if the user with the specified email is not found. - public async Task GeneratePasswordResetTokenAsync(string email, CancellationToken cancellationToken) - { - var user = await _userManager.FindByEmailAsync(email) ?? - throw UserException.UserNotFoundException.UserNotFoundEmail(email); - - - var token = await _userManager.GeneratePasswordResetTokenAsync(user); - - await Task.CompletedTask; - - return token; - } - - /// - /// Resets the password for a user with the specified email using the provided token and new password. - /// - /// The email of the user whose password is to be reset. - /// The token used to reset the password. - /// The new password to set for the user. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the result of the password reset operation. - /// Thrown when the user with the specified email is not found. - public async Task ResetPasswordAsync(string email, string token, string newPassword, - CancellationToken cancellation) - { - var user = await _userManager.FindByEmailAsync(email) ?? - throw UserException.UserNotFoundException.UserNotFoundEmail(email); - - - var result = await _userManager.ResetPasswordAsync(user, token, newPassword); - - await Task.CompletedTask; - - return result; - } - - /// - /// Checks if the specified userDto exist in the repository. - /// - /// A collection of objects to check for existence. - /// - /// - /// A task representing the asynchronous operation, with a result indicating whether the userDto exist ( - /// true if they exist, false otherwise). - /// - public async Task ExistsAsync(IEnumerable userIdentity, CancellationToken cancellationToken) - { - var userDto = (await _mapper.UserMapperDto(userIdentity, cancellationToken)) - .ToList(); - - foreach (var item in userDto) - { - if (await IsUserIdExistsAsync(item.Id.ToString(), cancellationToken)) - throw UserException.UserAlreadyExistsException.FromExistingId(item.Id.ToString()); - - if (await IsUserNameExistsAsync(item.UserName, cancellationToken)) - throw UserException.UserAlreadyExistsException.FromNameExistingUser(item.UserName.ToString()); - - if (await IsEmailExistsAsync(item.Email, cancellationToken)) - throw UserException.UserAlreadyExistsException.FromEmailExistingUser(item.Email.ToString()); - } - - return false; - } - - /// - /// Checks if a user with the specified ID exists in the database. - /// - /// The ID of the user to check. - /// A cancellation token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the user exists. - private async Task IsUserIdExistsAsync(string userId, CancellationToken cancellationToken) - { - var id = Guid.Parse(userId); - return await _dependencyInjection._appContext.Users.AnyAsync(u => u.Id == id, cancellationToken); - } - - /// - /// Checks if a user with the specified username exists in the database. - /// - /// The username of the user to check. - /// A cancellation token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the user exists. - private async Task IsUserNameExistsAsync(string? userName, CancellationToken cancellationToken) - { - return await _dependencyInjection._appContext.Users.AnyAsync(u => u.UserName == userName, cancellationToken); - } - - /// - /// Checks if a user with the specified email exists in the database. - /// - /// The email of the user to check. - /// A cancellation token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the user exists. - private async Task IsEmailExistsAsync(string? email, CancellationToken cancellationToken) - { - return await _dependencyInjection._appContext.Users.AnyAsync(u => u.Email == email, cancellationToken); - } -} -#endregion \ No newline at end of file