From 2acdbaac9a6e7c280756963bcc00b33398412040 Mon Sep 17 00:00:00 2001 From: Vanderlan Gomes Date: Fri, 29 Dec 2023 11:41:08 -0300 Subject: [PATCH] Improvements on application architecture and code design (#30) --- docker-compose.yaml | 11 ++++ scripts/init-sqlserver.sh | 1 + scripts/initial-script.sql | 2 + .../Configuration/HealthCheckConfiguration.cs | 34 +++++----- .../Controllers/Base/ApiController.cs | 8 +-- .../Controllers/V1/AuthController.cs | 11 +--- .../Controllers/V1/UsersController.cs | 7 +- src/Orion.Api/Middleware/OrionMiddleware.cs | 21 ++---- src/Orion.Api/Orion.Api.csproj | 8 +-- src/Orion.Api/appsettings.Development.json | 2 +- src/Orion.Api/appsettings.Production.json | 2 +- .../LoginWithCredentialsRequestHandler.cs | 11 +--- .../LoginWithRefreshTokenRequestHandler.cs | 12 +--- .../UserUpdatePasswordRequestHandler.cs | 21 ++---- .../UserCreate/UserCreateRequestHandler.cs | 16 ++--- .../Commands/UserDelete/UserDeleteRequest.cs | 9 +-- .../UserDelete/UserDeleteRequestHandler.cs | 11 +--- .../UserUpdate/UserUpdateRequestHandler.cs | 11 +--- .../UserCreated/UserCreatedNotification.cs | 9 +-- .../UserCreatedNotificationHandler.cs | 18 ++--- .../UserPasswordChangedNotificationHandler.cs | 18 ++--- .../Orion.Application.Core.csproj | 2 +- .../Queries/UserGetById/UserGetByIdRequest.cs | 9 +-- .../UserGetById/UserGetByIdRequestHandler.cs | 11 +--- .../UserGetPaginatedRequestHandler.cs | 12 +--- .../OrionResources.cs | 9 +-- .../Extensions/EnumExtensions.cs | 3 +- src/Orion.Domain.Core/Services/UserService.cs | 66 ++++++++----------- .../ValueObjects/Pagination/PagedList.cs | 12 +--- src/Orion.Infra.Data/Context/DataContext.cs | 7 +- .../Generic/BaseEntityRepository.cs | 10 +-- .../Implementations/RefreshTokenRepository.cs | 8 +-- .../Implementations/UserRepository.cs | 6 +- src/Orion.Infra.Data/UnitOfWork/UnitOfWork.cs | 9 +-- .../Domain/Services/UserServiceTest.cs | 7 +- .../Setup/IntegrationTestsBootstrapper.cs | 22 ++----- tests/Orion.Test/Orion.Test.csproj | 8 +-- 37 files changed, 149 insertions(+), 295 deletions(-) create mode 100644 scripts/init-sqlserver.sh create mode 100644 scripts/initial-script.sql diff --git a/docker-compose.yaml b/docker-compose.yaml index b8816bb..371bc7d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -24,6 +24,17 @@ services: container_name: sqlserver networks: - backend-network + + mssqltools: + image: mcr.microsoft.com/mssql-tools + depends_on: + - sqlserver + volumes: + - ./scripts/initial-script.sql:/tmp/initial-script.sql + - ./scripts/init-sqlserver.sh:/tmp/init-sqlserver.sh + command: /bin/bash ./tmp/init-sqlserver.sh + networks: + - backend-network elasticsearch: container_name: elasticsearch diff --git a/scripts/init-sqlserver.sh b/scripts/init-sqlserver.sh new file mode 100644 index 0000000..5f6699c --- /dev/null +++ b/scripts/init-sqlserver.sh @@ -0,0 +1 @@ +/opt/mssql-tools/bin/sqlcmd -S sqlserver -U sa -P SqlServer2019! -d master -i /tmp/initial-script.sql \ No newline at end of file diff --git a/scripts/initial-script.sql b/scripts/initial-script.sql new file mode 100644 index 0000000..721a1de --- /dev/null +++ b/scripts/initial-script.sql @@ -0,0 +1,2 @@ +--script used to create the database used in integration tests, if the database name changes, it is necessary to update appsettings.Test.json +CREATE DATABASE OrionTests; \ No newline at end of file diff --git a/src/Orion.Api/Configuration/HealthCheckConfiguration.cs b/src/Orion.Api/Configuration/HealthCheckConfiguration.cs index ba52c0b..960ca19 100644 --- a/src/Orion.Api/Configuration/HealthCheckConfiguration.cs +++ b/src/Orion.Api/Configuration/HealthCheckConfiguration.cs @@ -5,6 +5,25 @@ namespace Orion.Api.Configuration; public static class HealthCheckConfiguration { + private static readonly string[] DatabaseTags = + [ + "database" + ]; + private static readonly string[] ElasticSearchTags = + [ + "elasticsearch", + "kibana" + ]; + + public static void AddApplicationHealthChecks(this IServiceCollection services, IConfiguration configuration) + { + services.AddHealthChecks().AddSqlServer(configuration["ConnectionStrings:OrionDatabase"], + tags: DatabaseTags); + + services.AddHealthChecks().AddElasticsearch(configuration["ElasticConfiguration:Uri"], + tags: ElasticSearchTags); + } + public static void ConfigureHealthCheck(this IApplicationBuilder app) { app.UseHealthChecks("/health", new HealthCheckOptions @@ -13,19 +32,4 @@ public static void ConfigureHealthCheck(this IApplicationBuilder app) }); } - public static void AddApplicationHealthChecks(this IServiceCollection services, IConfiguration configuration) - { - services.AddHealthChecks().AddSqlServer(configuration["ConnectionStrings:OrionDatabase"], - tags: new[] - { - "database" - }); - - services.AddHealthChecks().AddElasticsearch(configuration["ElasticConfiguration:Uri"], - tags: new[] - { - "elasticsearch", - "kibana" - }); - } } diff --git a/src/Orion.Api/Controllers/Base/ApiController.cs b/src/Orion.Api/Controllers/Base/ApiController.cs index cb67840..1902989 100644 --- a/src/Orion.Api/Controllers/Base/ApiController.cs +++ b/src/Orion.Api/Controllers/Base/ApiController.cs @@ -4,13 +4,9 @@ namespace Orion.Api.Controllers.Base; [ApiController] -public abstract class ApiController : ControllerBase +public abstract class ApiController(IMediator mediator) : ControllerBase { - protected readonly IMediator Mediator; - protected ApiController(IMediator mediator) - { - Mediator = mediator; - } + protected readonly IMediator Mediator = mediator; protected CreatedResult Created(object entity) { diff --git a/src/Orion.Api/Controllers/V1/AuthController.cs b/src/Orion.Api/Controllers/V1/AuthController.cs index 96b495e..8f8f890 100644 --- a/src/Orion.Api/Controllers/V1/AuthController.cs +++ b/src/Orion.Api/Controllers/V1/AuthController.cs @@ -16,15 +16,8 @@ namespace Orion.Api.Controllers.V1; [ApiVersion(1.0)] [Route("api/[controller]")] [AllowAnonymous] -public class AuthController : ApiController +public class AuthController(IMediator mediator, IConfiguration configuration) : ApiController(mediator) { - private readonly IConfiguration _configuration; - - public AuthController(IMediator mediator, IConfiguration configuration) : base(mediator) - { - _configuration = configuration; - } - [HttpPost("Login")] [SwaggerResponse((int)HttpStatusCode.OK,"A success reponse with a Token, Refresh Token and expiration date" ,typeof(LoginWithCredentialsResponse))] [SwaggerResponse((int)HttpStatusCode.BadRequest,"A error response with the error description", typeof(ExceptionResponse))] @@ -51,7 +44,7 @@ private IActionResult AuthorizeUser(LoginWithCredentialsResponse loginWithCreden { if (loginWithCredentialsResponse != null) { - var (token, validTo) = AuthenticationConfiguration.CreateToken(loginWithCredentialsResponse, _configuration); + var (token, validTo) = AuthenticationConfiguration.CreateToken(loginWithCredentialsResponse, configuration); return Ok( new UserApiTokenModel diff --git a/src/Orion.Api/Controllers/V1/UsersController.cs b/src/Orion.Api/Controllers/V1/UsersController.cs index 8a5fdb5..41a9dab 100644 --- a/src/Orion.Api/Controllers/V1/UsersController.cs +++ b/src/Orion.Api/Controllers/V1/UsersController.cs @@ -20,13 +20,8 @@ namespace Orion.Api.Controllers.V1; [ApiVersion(1.0)] [Route("api/[controller]")] [AuthorizeFor(Roles.Admin)] -public class UsersController : ApiController +public class UsersController(IMediator mediator) : ApiController(mediator) { - public UsersController(IMediator mediator) : base(mediator) - { - - } - [HttpGet] [SwaggerResponse((int)HttpStatusCode.OK,"A success response with a list of Users paginated", typeof(PagedList))] [SwaggerResponse((int)HttpStatusCode.Unauthorized)] diff --git a/src/Orion.Api/Middleware/OrionMiddleware.cs b/src/Orion.Api/Middleware/OrionMiddleware.cs index d861c39..52ebe58 100644 --- a/src/Orion.Api/Middleware/OrionMiddleware.cs +++ b/src/Orion.Api/Middleware/OrionMiddleware.cs @@ -4,26 +4,15 @@ namespace Orion.Api.Middleware; -public class OrionMiddleware +public class OrionMiddleware(RequestDelegate next, ILogger logger, IHostEnvironment env) { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private readonly IHostEnvironment _env; - - public OrionMiddleware(RequestDelegate next, ILogger logger, IHostEnvironment env) - { - _env = env; - _next = next; - _logger = logger; - } - public async Task Invoke(HttpContext context) { try { - if (_next != null) + if (next != null) { - await _next(context); + await next(context); } } catch (Exception ex) @@ -38,7 +27,7 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception var errorResponse = new ExceptionResponse(exception.Message, NotificationType.Error); - if (exception is not BusinessException && _env.IsDevelopment()) + if (exception is not BusinessException && env.IsDevelopment()) { errorResponse = new ExceptionResponse(exception.Message, NotificationType.Error); } @@ -73,7 +62,7 @@ private async Task ProccessResponseAsync(HttpContext context, HttpStatusCode sta if (statusCode == HttpStatusCode.InternalServerError) foreach (var error in errorResponse.Errors) - _logger.LogError(exception, "Internal Server Error: {message}", error); + logger.LogError(exception, "Internal Server Error: {message}", error); context.Response.StatusCode = (int)statusCode; context.Response.ContentType = "application/json"; diff --git a/src/Orion.Api/Orion.Api.csproj b/src/Orion.Api/Orion.Api.csproj index be7efec..7e89b6f 100644 --- a/src/Orion.Api/Orion.Api.csproj +++ b/src/Orion.Api/Orion.Api.csproj @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/src/Orion.Api/appsettings.Development.json b/src/Orion.Api/appsettings.Development.json index 33908bd..fa4bbea 100644 --- a/src/Orion.Api/appsettings.Development.json +++ b/src/Orion.Api/appsettings.Development.json @@ -7,7 +7,7 @@ } }, "ConnectionStrings": { - "OrionDatabase": "Data Source=localhost,1433;Initial Catalog=Orion;User ID=Orion;Password=123;TrustServerCertificate=True" + "OrionDatabase": "Data Source=localhost,1434;Initial Catalog=OrionDev;User ID=sa;Password=SqlServer2019!;TrustServerCertificate=True" }, "JwtOptions": { "SymmetricSecurityKey": "5cCI6IkpXVCJ9.eyJlbWFpbCI6InZhbmRlcmxhbi5nc0BnbWFpbC5jb20iLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJhZG1p", diff --git a/src/Orion.Api/appsettings.Production.json b/src/Orion.Api/appsettings.Production.json index 2354382..e8c657d 100644 --- a/src/Orion.Api/appsettings.Production.json +++ b/src/Orion.Api/appsettings.Production.json @@ -7,7 +7,7 @@ } }, "ConnectionStrings": { - "OrionDatabase": "Data Source=10.0.0.90,1433;Initial Catalog=Orion;User ID=Orion;Password=123;TrustServerCertificate=True" + "OrionDatabase": "Data Source=sqlserver;Initial Catalog=OrionDev;User ID=sa;Password=SqlServer2019!;TrustServerCertificate=True" }, "JwtOptions": { "SymmetricSecurityKey": "5cCI6IkpXVCJ9.eyJlbWFpbCI6InZhbmRlcmxhbi5nc0BnbWFpbC5jb20iLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJhZG1p", diff --git a/src/Orion.Application.Core/Commands/LoginWithCredentials/LoginWithCredentialsRequestHandler.cs b/src/Orion.Application.Core/Commands/LoginWithCredentials/LoginWithCredentialsRequestHandler.cs index 1857843..3adc26f 100644 --- a/src/Orion.Application.Core/Commands/LoginWithCredentials/LoginWithCredentialsRequestHandler.cs +++ b/src/Orion.Application.Core/Commands/LoginWithCredentials/LoginWithCredentialsRequestHandler.cs @@ -3,18 +3,11 @@ namespace Orion.Application.Core.Commands.LoginWithCredentials; -public class LoginWithCredentialsRequestHandler : IRequestHandler +public class LoginWithCredentialsRequestHandler(IUserService userService) : IRequestHandler { - private readonly IUserService _userService; - - public LoginWithCredentialsRequestHandler(IUserService userService) - { - _userService = userService; - } - public async Task Handle(LoginWithCredentialsRequest request, CancellationToken cancellationToken) { - var (user, refreshToken) = await _userService.SignInWithCredentialsAsync(request.Email, request.Password); + var (user, refreshToken) = await userService.SignInWithCredentialsAsync(request.Email, request.Password); return new LoginWithCredentialsResponse { diff --git a/src/Orion.Application.Core/Commands/LoginWithRefreshToken/LoginWithRefreshTokenRequestHandler.cs b/src/Orion.Application.Core/Commands/LoginWithRefreshToken/LoginWithRefreshTokenRequestHandler.cs index 77f1dba..635695f 100644 --- a/src/Orion.Application.Core/Commands/LoginWithRefreshToken/LoginWithRefreshTokenRequestHandler.cs +++ b/src/Orion.Application.Core/Commands/LoginWithRefreshToken/LoginWithRefreshTokenRequestHandler.cs @@ -3,18 +3,12 @@ namespace Orion.Application.Core.Commands.LoginWithRefreshToken; -public class LoginWithRefreshTokenRequestHandler : IRequestHandler +public class LoginWithRefreshTokenRequestHandler(IUserService userService) + : IRequestHandler { - private readonly IUserService _userService; - - public LoginWithRefreshTokenRequestHandler(IUserService userService) - { - _userService = userService; - } - public async Task Handle(LoginWithRefreshTokenRequest request, CancellationToken cancellationToken) { - var (user, refreshToken) = await _userService.SignInWithRefreshTokenAsync(request.RefreshToken, request.Token); + var (user, refreshToken) = await userService.SignInWithRefreshTokenAsync(request.RefreshToken, request.Token); return new LoginWithRefreshTokenResponse { diff --git a/src/Orion.Application.Core/Commands/UserChangePassword/UserUpdatePasswordRequestHandler.cs b/src/Orion.Application.Core/Commands/UserChangePassword/UserUpdatePasswordRequestHandler.cs index 9545182..72be78c 100644 --- a/src/Orion.Application.Core/Commands/UserChangePassword/UserUpdatePasswordRequestHandler.cs +++ b/src/Orion.Application.Core/Commands/UserChangePassword/UserUpdatePasswordRequestHandler.cs @@ -5,24 +5,17 @@ namespace Orion.Application.Core.Commands.UserChangePassword { - public class UserUpdatePasswordRequestHandler : IRequestHandler + public class UserUpdatePasswordRequestHandler( + IUserService userService, + ICurrentUser currentUser, + IMediator mediator) + : IRequestHandler { - private readonly IUserService _userService; - private readonly ICurrentUser _currentUser; - private readonly IMediator _mediator; - - public UserUpdatePasswordRequestHandler(IUserService userService, ICurrentUser currentUser, IMediator mediator) - { - _userService = userService; - _currentUser = currentUser; - _mediator = mediator; - } - public async Task Handle(UserChangePasswordRequest request, CancellationToken cancellationToken) { - await _userService.ChangePasswordAsync(_currentUser.Id, request.CurrentPassword, request.NewPassword); + await userService.ChangePasswordAsync(currentUser.Id, request.CurrentPassword, request.NewPassword); - await _mediator.Publish(new UserPasswordChangedNotification(), cancellationToken); + await mediator.Publish(new UserPasswordChangedNotification(), cancellationToken); return Unit.Value; } diff --git a/src/Orion.Application.Core/Commands/UserCreate/UserCreateRequestHandler.cs b/src/Orion.Application.Core/Commands/UserCreate/UserCreateRequestHandler.cs index 5c2b7df..5d7feb7 100644 --- a/src/Orion.Application.Core/Commands/UserCreate/UserCreateRequestHandler.cs +++ b/src/Orion.Application.Core/Commands/UserCreate/UserCreateRequestHandler.cs @@ -4,22 +4,14 @@ namespace Orion.Application.Core.Commands.UserCreate; -public class UserCreateRequestHandler : IRequestHandler +public class UserCreateRequestHandler(IUserService userService, IMediator mediator) + : IRequestHandler { - private readonly IUserService _userService; - private readonly IMediator _mediator; - - public UserCreateRequestHandler(IUserService userService, IMediator mediator) - { - _userService = userService; - _mediator = mediator; - } - public async Task Handle(UserCreateRequest request, CancellationToken cancellationToken) { - var userCreated = await _userService.AddAsync(request); + var userCreated = await userService.AddAsync(request); - await _mediator.Publish(new UserCreatedNotification(userCreated), cancellationToken); + await mediator.Publish(new UserCreatedNotification(userCreated), cancellationToken); return (UserCreateResponse)userCreated; } diff --git a/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequest.cs b/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequest.cs index 1a3ab41..c9134fe 100644 --- a/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequest.cs +++ b/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequest.cs @@ -2,13 +2,8 @@ namespace Orion.Application.Core.Commands.UserDelete; -public class UserDeleteRequest : IRequest +public class UserDeleteRequest(string publicId) : IRequest { - public UserDeleteRequest(string publicId) - { - PublicId = publicId; - } - - public string PublicId { get; private set; } + public string PublicId { get; private set; } = publicId; } diff --git a/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequestHandler.cs b/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequestHandler.cs index 1b38cea..dab31bc 100644 --- a/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequestHandler.cs +++ b/src/Orion.Application.Core/Commands/UserDelete/UserDeleteRequestHandler.cs @@ -3,18 +3,11 @@ namespace Orion.Application.Core.Commands.UserDelete; -public class UserDeleteRequestHandler : IRequestHandler +public class UserDeleteRequestHandler(IUserService userService) : IRequestHandler { - private readonly IUserService _userService; - - public UserDeleteRequestHandler(IUserService userService) - { - _userService = userService; - } - public async Task Handle(UserDeleteRequest request, CancellationToken cancellationToken) { - await _userService.DeleteAsync(request.PublicId); + await userService.DeleteAsync(request.PublicId); return Unit.Value; } diff --git a/src/Orion.Application.Core/Commands/UserUpdate/UserUpdateRequestHandler.cs b/src/Orion.Application.Core/Commands/UserUpdate/UserUpdateRequestHandler.cs index e0e3fb9..63b634b 100644 --- a/src/Orion.Application.Core/Commands/UserUpdate/UserUpdateRequestHandler.cs +++ b/src/Orion.Application.Core/Commands/UserUpdate/UserUpdateRequestHandler.cs @@ -3,18 +3,11 @@ namespace Orion.Application.Core.Commands.UserUpdate; -public class UserUpdateRequestHandler : IRequestHandler +public class UserUpdateRequestHandler(IUserService userService) : IRequestHandler { - private readonly IUserService _userService; - - public UserUpdateRequestHandler(IUserService userService) - { - _userService = userService; - } - public async Task Handle(UserUpdateRequest request, CancellationToken cancellationToken) { - await _userService.UpdateAsync(request); + await userService.UpdateAsync(request); return Unit.Value; } diff --git a/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotification.cs b/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotification.cs index 48891db..a550f48 100644 --- a/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotification.cs +++ b/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotification.cs @@ -3,13 +3,8 @@ namespace Orion.Application.Core.Notifications.UserCreated { - public class UserCreatedNotification : INotification + public class UserCreatedNotification(User user) : INotification { - public UserCreatedNotification(User user) - { - Entity = user; - } - - public User Entity { get; set; } + public User Entity { get; set; } = user; } } diff --git a/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotificationHandler.cs b/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotificationHandler.cs index 43daf21..1f3ceb5 100644 --- a/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotificationHandler.cs +++ b/src/Orion.Application.Core/Notifications/UserCreated/UserCreatedNotificationHandler.cs @@ -5,23 +5,17 @@ namespace Orion.Application.Core.Notifications.UserCreated { - public class UserCreatedNotificationHandler : INotificationHandler + public class UserCreatedNotificationHandler( + ILogger logger, + ICurrentUser currentUser) + : INotificationHandler { - private readonly ILogger _logger; - private readonly ICurrentUser _currentUser; - - public UserCreatedNotificationHandler(ILogger logger, ICurrentUser currentUser) - { - _logger = logger; - _currentUser = currentUser; - } - public async Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken) { - _logger.LogInformation("A notification {notificationType} has been received. Notification details: {notification}. Action performed by: {currentUserName}", + logger.LogInformation("A notification {notificationType} has been received. Notification details: {notification}. Action performed by: {currentUserName}", nameof(UserCreatedNotification), JsonConvert.SerializeObject(notification, Formatting.Indented), - _currentUser.ToString()); + currentUser.ToString()); await Task.CompletedTask; } diff --git a/src/Orion.Application.Core/Notifications/UserPasswordChanged/UserPasswordChangedNotificationHandler.cs b/src/Orion.Application.Core/Notifications/UserPasswordChanged/UserPasswordChangedNotificationHandler.cs index 1df9f79..6630246 100644 --- a/src/Orion.Application.Core/Notifications/UserPasswordChanged/UserPasswordChangedNotificationHandler.cs +++ b/src/Orion.Application.Core/Notifications/UserPasswordChanged/UserPasswordChangedNotificationHandler.cs @@ -5,23 +5,17 @@ namespace Orion.Application.Core.Notifications.UserPasswordChanged { - public class UserPasswordChangedNotificationHandler : INotificationHandler + public class UserPasswordChangedNotificationHandler( + ILogger logger, + ICurrentUser currentUser) + : INotificationHandler { - private readonly ILogger _logger; - private readonly ICurrentUser _currentUser; - - public UserPasswordChangedNotificationHandler(ILogger logger, ICurrentUser currentUser) - { - _logger = logger; - _currentUser = currentUser; - } - public async Task Handle(UserPasswordChangedNotification notification, CancellationToken cancellationToken) { - _logger.LogInformation("A notification {notificationType} has been received. Notification details: {notification}. Action performed by: {currentUserName}", + logger.LogInformation("A notification {notificationType} has been received. Notification details: {notification}. Action performed by: {currentUserName}", nameof(UserPasswordChangedNotification), JsonConvert.SerializeObject(notification, Formatting.Indented), - _currentUser.ToString()); + currentUser.ToString()); await Task.CompletedTask; } diff --git a/src/Orion.Application.Core/Orion.Application.Core.csproj b/src/Orion.Application.Core/Orion.Application.Core.csproj index 608c639..e8abc0d 100644 --- a/src/Orion.Application.Core/Orion.Application.Core.csproj +++ b/src/Orion.Application.Core/Orion.Application.Core.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequest.cs b/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequest.cs index 2a7e8ec..ea18d4f 100644 --- a/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequest.cs +++ b/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequest.cs @@ -2,12 +2,7 @@ namespace Orion.Application.Core.Queries.UserGetById; -public class UserGetByIdRequest : IRequest +public class UserGetByIdRequest(string publicId) : IRequest { - public UserGetByIdRequest(string publicId) - { - PublicId = publicId; - } - - public string PublicId { get; private set; } + public string PublicId { get; private set; } = publicId; } diff --git a/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequestHandler.cs b/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequestHandler.cs index 58fd220..b8adcfe 100644 --- a/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequestHandler.cs +++ b/src/Orion.Application.Core/Queries/UserGetById/UserGetByIdRequestHandler.cs @@ -3,17 +3,10 @@ namespace Orion.Application.Core.Queries.UserGetById; -public class UserGetByIdHandler : IRequestHandler +public class UserGetByIdHandler(IUserService userService) : IRequestHandler { - private readonly IUserService _userService; - - public UserGetByIdHandler(IUserService userService) - { - _userService = userService; - } - public async Task Handle(UserGetByIdRequest request, CancellationToken cancellationToken) { - return (UserGetByIdResponse) await _userService.FindByIdAsync(request.PublicId); + return (UserGetByIdResponse) await userService.FindByIdAsync(request.PublicId); } } \ No newline at end of file diff --git a/src/Orion.Application.Core/Queries/UserGetPaginated/UserGetPaginatedRequestHandler.cs b/src/Orion.Application.Core/Queries/UserGetPaginated/UserGetPaginatedRequestHandler.cs index f497243..559b86c 100644 --- a/src/Orion.Application.Core/Queries/UserGetPaginated/UserGetPaginatedRequestHandler.cs +++ b/src/Orion.Application.Core/Queries/UserGetPaginated/UserGetPaginatedRequestHandler.cs @@ -4,18 +4,12 @@ namespace Orion.Application.Core.Queries.UserGetPaginated; -public class UserGetPaginatedRequestHandler : IRequestHandler> +public class UserGetPaginatedRequestHandler(IUserService userService) + : IRequestHandler> { - private readonly IUserService _userService; - - public UserGetPaginatedRequestHandler(IUserService userService) - { - _userService = userService; - } - public async Task> Handle(UserGetPaginatedRequest request, CancellationToken cancellationToken) { - var users = await _userService.ListPaginateAsync(request); + var users = await userService.ListPaginateAsync(request); var usersPaginated = users.Items.Select(user => (UserGetPaginatedResponse)user).ToList(); diff --git a/src/Orion.Croscutting.Resources/OrionResources.cs b/src/Orion.Croscutting.Resources/OrionResources.cs index 63698ce..e908296 100644 --- a/src/Orion.Croscutting.Resources/OrionResources.cs +++ b/src/Orion.Croscutting.Resources/OrionResources.cs @@ -2,14 +2,9 @@ namespace Orion.Croscutting.Resources; -public class OrionResources : ISharedResource +public class OrionResources(IStringLocalizer localizer) : ISharedResource { - private readonly IStringLocalizer _localizer; - - public OrionResources(IStringLocalizer localizer) - { - _localizer = localizer; - } + private readonly IStringLocalizer _localizer = localizer; public string this[string index] => _localizer[index]; } diff --git a/src/Orion.Domain.Core/Extensions/EnumExtensions.cs b/src/Orion.Domain.Core/Extensions/EnumExtensions.cs index b852055..a74a9d6 100644 --- a/src/Orion.Domain.Core/Extensions/EnumExtensions.cs +++ b/src/Orion.Domain.Core/Extensions/EnumExtensions.cs @@ -1,5 +1,4 @@ using System.ComponentModel; -using System.Linq; namespace Orion.Domain.Core.Extensions { @@ -11,7 +10,7 @@ public static string Description(this T source) var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); - if (attributes.Any()) + if (attributes.Length != 0) return attributes[0].Description; return string.Empty; diff --git a/src/Orion.Domain.Core/Services/UserService.cs b/src/Orion.Domain.Core/Services/UserService.cs index 94dead1..ca58dc4 100644 --- a/src/Orion.Domain.Core/Services/UserService.cs +++ b/src/Orion.Domain.Core/Services/UserService.cs @@ -16,25 +16,17 @@ namespace Orion.Domain.Core.Services; -public class UserService : IUserService +public class UserService(IUnitOfWork unitOfWork, IStringLocalizer resourceMessages) + : IUserService { - private readonly IUnitOfWork _unitOfWork; - private readonly IStringLocalizer _messages; - - public UserService(IUnitOfWork unitOfWork, IStringLocalizer resourceMessages) - { - _unitOfWork = unitOfWork; - _messages = resourceMessages; - } - public async Task AddAsync(User user) { await ValidateUser(user); user.Password = user.Password.ToSha512(); - var added = await _unitOfWork.UserRepository.AddAsync(user); - await _unitOfWork.CommitAsync(); + var added = await unitOfWork.UserRepository.AddAsync(user); + await unitOfWork.CommitAsync(); return added; } @@ -46,18 +38,18 @@ public async Task DeleteAsync(string publicId) if (user == null) throw new NotFoundException(publicId); - await _unitOfWork.UserRepository.DeleteAsync(publicId); - await _unitOfWork.CommitAsync(); + await unitOfWork.UserRepository.DeleteAsync(publicId); + await unitOfWork.CommitAsync(); } public async Task FindByIdAsync(string publicId) { - return await _unitOfWork.UserRepository.GetByIdAsync(publicId); + return await unitOfWork.UserRepository.GetByIdAsync(publicId); } public async Task<(User User, RefreshToken RefreshToken)> SignInWithCredentialsAsync(string email, string password) { - var user = await _unitOfWork.UserRepository.LoginAsync(email, password.ToSha512()); + var user = await unitOfWork.UserRepository.LoginAsync(email, password.ToSha512()); if (user is not null) { @@ -65,7 +57,7 @@ public async Task FindByIdAsync(string publicId) return (user, refreshToken); } - throw new UnauthorizedUserException(_messages[UserMessages.InvalidCredentials], _messages[ExceptionsTitles.AuthenticationError]); + throw new UnauthorizedUserException(resourceMessages[UserMessages.InvalidCredentials], resourceMessages[ExceptionsTitles.AuthenticationError]); } public async Task UpdateAsync(User user) @@ -78,17 +70,17 @@ public async Task UpdateAsync(User user) entitySaved.Name = user.Name; entitySaved.Profile = user.Profile; - _unitOfWork.UserRepository.Update(entitySaved); + unitOfWork.UserRepository.Update(entitySaved); - await _unitOfWork.CommitAsync(); + await unitOfWork.CommitAsync(); } private async Task AddRefreshTokenAsync(string userEmail) { - var existantRefreshToken = (await _unitOfWork.RefreshTokenRepository.SearchByAsync(x => x.Email == userEmail)).FirstOrDefault(); + var existentRefreshToken = (await unitOfWork.RefreshTokenRepository.SearchByAsync(x => x.Email == userEmail)).FirstOrDefault(); - if (existantRefreshToken is not null) - return existantRefreshToken; + if (existentRefreshToken is not null) + return existentRefreshToken; var refreshToken = new RefreshToken { @@ -96,8 +88,8 @@ private async Task AddRefreshTokenAsync(string userEmail) Refreshtoken = Guid.NewGuid().ToString().ToSha512() }; - var addedRefreshToken = await _unitOfWork.RefreshTokenRepository.AddAsync(refreshToken); - await _unitOfWork.CommitAsync(); + var addedRefreshToken = await unitOfWork.RefreshTokenRepository.AddAsync(refreshToken); + await unitOfWork.CommitAsync(); return addedRefreshToken; } @@ -107,29 +99,29 @@ private async Task AddRefreshTokenAsync(string userEmail) if (string.IsNullOrEmpty(refreshToken)) { throw new UnauthorizedUserException( - _messages[UserMessages.InvalidRefreshToken], - _messages[ExceptionsTitles.AuthenticationError] + resourceMessages[UserMessages.InvalidRefreshToken], + resourceMessages[ExceptionsTitles.AuthenticationError] ); } var email = GetClaimFromJwtToken(expiredToken, ClaimTypes.Email); - var userRefreshToken = (await _unitOfWork.RefreshTokenRepository.SearchByAsync(x => x.Refreshtoken.Equals(refreshToken) && x.Email == email)).FirstOrDefault(); + var userRefreshToken = (await unitOfWork.RefreshTokenRepository.SearchByAsync(x => x.Refreshtoken.Equals(refreshToken) && x.Email == email)).FirstOrDefault(); if (userRefreshToken is not null) { - var user = (await _unitOfWork.UserRepository.SearchByAsync(x => x.Email == userRefreshToken.Email)).FirstOrDefault(); + var user = (await unitOfWork.UserRepository.SearchByAsync(x => x.Email == userRefreshToken.Email)).FirstOrDefault(); if (user is not null) { - await _unitOfWork.RefreshTokenRepository.DeleteAsync(userRefreshToken.PublicId); + await unitOfWork.RefreshTokenRepository.DeleteAsync(userRefreshToken.PublicId); var newRefreshToken = await AddRefreshTokenAsync(user.Email); return (user, newRefreshToken); } } - throw new UnauthorizedUserException(_messages[UserMessages.InvalidRefreshToken], _messages[ExceptionsTitles.AuthenticationError]); + throw new UnauthorizedUserException(resourceMessages[UserMessages.InvalidRefreshToken], resourceMessages[ExceptionsTitles.AuthenticationError]); } private string GetClaimFromJwtToken(string jtwToken, string claimName) @@ -144,21 +136,21 @@ private string GetClaimFromJwtToken(string jtwToken, string claimName) } catch (Exception) { - throw new UnauthorizedUserException(_messages[UserMessages.InvalidRefreshToken], _messages[ExceptionsTitles.AuthenticationError]); + throw new UnauthorizedUserException(resourceMessages[UserMessages.InvalidRefreshToken], resourceMessages[ExceptionsTitles.AuthenticationError]); } } private async Task ValidateUser(User user) { - var userFound = await _unitOfWork.UserRepository.FindByEmailAsync(user.Email); + var userFound = await unitOfWork.UserRepository.FindByEmailAsync(user.Email); if (userFound != null && userFound.PublicId != user.PublicId) - throw new ConflictException(_messages[UserMessages.EmailExists], _messages[ExceptionsTitles.ValidationError]); + throw new ConflictException(resourceMessages[UserMessages.EmailExists], resourceMessages[ExceptionsTitles.ValidationError]); } public async Task> ListPaginateAsync(UserFilter filter) { - return await _unitOfWork.UserRepository.ListPaginateAsync(filter); + return await unitOfWork.UserRepository.ListPaginateAsync(filter); } public async Task ChangePasswordAsync(string userId, string currentPassword, string newPassword) @@ -169,12 +161,12 @@ public async Task ChangePasswordAsync(string userId, string currentPassword, str throw new NotFoundException(userId); if(user.Password != currentPassword.ToSha512()) - throw new BusinessException(_messages[UserMessages.InvalidPassword]); + throw new BusinessException(resourceMessages[UserMessages.InvalidPassword]); user.Password = newPassword.ToSha512(); - _unitOfWork.UserRepository.Update(user); + unitOfWork.UserRepository.Update(user); - await _unitOfWork.CommitAsync(); + await unitOfWork.CommitAsync(); } } diff --git a/src/Orion.Domain.Core/ValueObjects/Pagination/PagedList.cs b/src/Orion.Domain.Core/ValueObjects/Pagination/PagedList.cs index 83eda9d..c811f33 100644 --- a/src/Orion.Domain.Core/ValueObjects/Pagination/PagedList.cs +++ b/src/Orion.Domain.Core/ValueObjects/Pagination/PagedList.cs @@ -2,14 +2,8 @@ namespace Orion.Domain.Core.ValueObjects.Pagination; -public class PagedList +public class PagedList(IList items, int count = 0) { - public PagedList(IList items, int count = 0) - { - Items = items; - Count = count; - } - - public IList Items { get; set; } - public int Count { get; set; } + public IList Items { get; set; } = items; + public int Count { get; set; } = count; } diff --git a/src/Orion.Infra.Data/Context/DataContext.cs b/src/Orion.Infra.Data/Context/DataContext.cs index 5c36227..d88f3ce 100644 --- a/src/Orion.Infra.Data/Context/DataContext.cs +++ b/src/Orion.Infra.Data/Context/DataContext.cs @@ -8,15 +8,10 @@ namespace Orion.Infra.Data.Context; -public class DataContext : DbContext +public class DataContext(IConfiguration configuration) : DbContext(GetDefaultOptions(configuration)) { public ModelBuilder ModelBuilder { get; private set; } - public DataContext(IConfiguration configuration) : base(GetDefaultOptions(configuration)) - { - - } - #region DBSet public DbSet Users { get; set; } public DbSet RefreshTokens { get; set; } diff --git a/src/Orion.Infra.Data/Repository/Generic/BaseEntityRepository.cs b/src/Orion.Infra.Data/Repository/Generic/BaseEntityRepository.cs index d45c5ff..ada1b88 100644 --- a/src/Orion.Infra.Data/Repository/Generic/BaseEntityRepository.cs +++ b/src/Orion.Infra.Data/Repository/Generic/BaseEntityRepository.cs @@ -9,14 +9,10 @@ namespace Orion.Infra.Data.Repository.Generic; -internal abstract class BaseEntityRepository : IBaseEntityRepository where T : BaseEntity +internal abstract class BaseEntityRepository(DataContext dataContext) : IBaseEntityRepository + where T : BaseEntity { - protected DataContext DataContext { get; } - - protected BaseEntityRepository(DataContext dataContext) - { - DataContext = dataContext; - } + protected DataContext DataContext { get; } = dataContext; public virtual async Task AddAsync(T entity) { diff --git a/src/Orion.Infra.Data/Repository/Implementations/RefreshTokenRepository.cs b/src/Orion.Infra.Data/Repository/Implementations/RefreshTokenRepository.cs index 089dce4..32b02cd 100644 --- a/src/Orion.Infra.Data/Repository/Implementations/RefreshTokenRepository.cs +++ b/src/Orion.Infra.Data/Repository/Implementations/RefreshTokenRepository.cs @@ -5,9 +5,5 @@ namespace Orion.Infra.Data.Repository.Implementations; -internal class RefreshTokenRepository : BaseEntityRepository, IRefreshTokenRepository -{ - public RefreshTokenRepository(DataContext context) : base(context) - { - } -} +internal class RefreshTokenRepository(DataContext context) + : BaseEntityRepository(context), IRefreshTokenRepository; diff --git a/src/Orion.Infra.Data/Repository/Implementations/UserRepository.cs b/src/Orion.Infra.Data/Repository/Implementations/UserRepository.cs index 069da00..55e826d 100644 --- a/src/Orion.Infra.Data/Repository/Implementations/UserRepository.cs +++ b/src/Orion.Infra.Data/Repository/Implementations/UserRepository.cs @@ -10,12 +10,8 @@ namespace Orion.Infra.Data.Repository.Implementations; -internal class UserRepository : BaseEntityRepository, IUserRepository +internal class UserRepository(DataContext context) : BaseEntityRepository(context), IUserRepository { - public UserRepository(DataContext context) : base(context) - { - } - public async Task LoginAsync(string email, string password) { var user = await DataContext.Users.AsNoTracking() diff --git a/src/Orion.Infra.Data/UnitOfWork/UnitOfWork.cs b/src/Orion.Infra.Data/UnitOfWork/UnitOfWork.cs index f531b41..5526f02 100644 --- a/src/Orion.Infra.Data/UnitOfWork/UnitOfWork.cs +++ b/src/Orion.Infra.Data/UnitOfWork/UnitOfWork.cs @@ -10,14 +10,9 @@ namespace Orion.Infra.Data.UnitOfWork; -public class UnitOfWork : IUnitOfWork +public class UnitOfWork(IConfiguration configuration) : IUnitOfWork { - private DataContext DbContext { get; } - - public UnitOfWork(IConfiguration configuration) - { - DbContext = new DataContext(configuration); - } + private DataContext DbContext { get; } = new(configuration); private IUserRepository _userRepository; public IUserRepository UserRepository => _userRepository ??= new UserRepository(DbContext); diff --git a/tests/Orion.Test/Integration/Domain/Services/UserServiceTest.cs b/tests/Orion.Test/Integration/Domain/Services/UserServiceTest.cs index dd3f5b5..5892a78 100644 --- a/tests/Orion.Test/Integration/Domain/Services/UserServiceTest.cs +++ b/tests/Orion.Test/Integration/Domain/Services/UserServiceTest.cs @@ -15,13 +15,8 @@ namespace Orion.Test.Integration.Domain.Services; -public class UserServiceTest : IntegrationTestsBootstrapper +public class UserServiceTest(IntegrationTestsFixture fixture) : IntegrationTestsBootstrapper(fixture) { - public UserServiceTest(IntegrationTestsFixture fixture) : base(fixture) - { - - } - #region User CRUD tests [Fact] public async Task AddAsync_WithValidData_AddUserAsSuccess() diff --git a/tests/Orion.Test/Integration/Setup/IntegrationTestsBootstrapper.cs b/tests/Orion.Test/Integration/Setup/IntegrationTestsBootstrapper.cs index 8df22e6..7eabbb8 100644 --- a/tests/Orion.Test/Integration/Setup/IntegrationTestsBootstrapper.cs +++ b/tests/Orion.Test/Integration/Setup/IntegrationTestsBootstrapper.cs @@ -11,23 +11,15 @@ namespace Orion.Test.Integration.Setup; -public abstract class IntegrationTestsBootstrapper : IClassFixture, IDisposable +public abstract class IntegrationTestsBootstrapper(IntegrationTestsFixture fixture) + : IClassFixture, IDisposable { - protected readonly HttpClient HttpClient; - protected readonly HttpClient AuthenticatedHttpClient; - protected readonly User DefaultSystemUser; - protected readonly IntegrationTestsFixture IntegrationTestsFixture; + protected readonly HttpClient HttpClient = fixture.HttpClient; + protected readonly HttpClient AuthenticatedHttpClient = fixture.AuthenticatedHttpClient; + protected readonly User DefaultSystemUser = fixture.DefaultSystemUser; + protected readonly IntegrationTestsFixture IntegrationTestsFixture = fixture; - protected IServiceProvider ServiceProvider { get; private set; } - - protected IntegrationTestsBootstrapper(IntegrationTestsFixture fixture) - { - HttpClient = fixture.HttpClient; - AuthenticatedHttpClient = fixture.AuthenticatedHttpClient; - DefaultSystemUser = fixture.DefaultSystemUser; - ServiceProvider = fixture.ServiceProvider; - IntegrationTestsFixture = fixture; - } + protected IServiceProvider ServiceProvider { get; private set; } = fixture.ServiceProvider; protected void LoginWithDefaultUser() { diff --git a/tests/Orion.Test/Orion.Test.csproj b/tests/Orion.Test/Orion.Test.csproj index 27edf57..f51a504 100644 --- a/tests/Orion.Test/Orion.Test.csproj +++ b/tests/Orion.Test/Orion.Test.csproj @@ -6,7 +6,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -14,9 +14,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive