From 85bac2b0a445c8b594ac851fbea506bca0f5a0f3 Mon Sep 17 00:00:00 2001 From: prtsie Date: Thu, 22 Aug 2024 00:23:02 +0300 Subject: [PATCH] user service with editing, removing and reading accounts methods, controller actions for this service --- .../ApplicationLayer/DependencyInjection.cs | 4 +- .../ApprovingAuthorities/IUsersService.cs | 24 ++++++++ .../ApprovingAuthorities/UsersService.cs | 34 +++++++++++ .../NeededServices/IUsersRepository.cs | 6 ++ .../Users/Repositories/UsersRepository.cs | 5 ++ .../Controllers/UsersController.cs | 58 +++++++++++++++++-- .../Controllers/VisaApiControllerBase.cs | 12 ++++ .../Controllers/VisaApplicationController.cs | 6 +- 8 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/IUsersService.cs create mode 100644 SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/UsersService.cs create mode 100644 SchengenVisaApi/SchengenVisaApi/Controllers/VisaApiControllerBase.cs diff --git a/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs b/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs index 63b38d8..14e9ffe 100644 --- a/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs +++ b/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs @@ -1,4 +1,5 @@ -using ApplicationLayer.Services.AuthServices.LoginService; +using ApplicationLayer.Services.ApprovingAuthorities; +using ApplicationLayer.Services.AuthServices.LoginService; using ApplicationLayer.Services.AuthServices.RegisterService; using ApplicationLayer.Services.VisaApplications.Handlers; using Microsoft.Extensions.DependencyInjection; @@ -14,6 +15,7 @@ public static class DependencyInjection services.AddScoped(); services.AddScoped(); + services.AddScoped(); if (isDevelopment) { diff --git a/SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/IUsersService.cs b/SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/IUsersService.cs new file mode 100644 index 0000000..500f9c2 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/IUsersService.cs @@ -0,0 +1,24 @@ +using ApplicationLayer.Services.AuthServices.Requests; +using Domains.Users; + +namespace ApplicationLayer.Services.ApprovingAuthorities +{ + /// user accounts service + public interface IUsersService + { + /// Returns all user accounts with role of approving authority + /// Cancellation token + Task> GetAuthoritiesAccountsAsync(CancellationToken cancellationToken); + + /// Changes authentication data for an account + /// identifier of account + /// request data with new email and password + /// Cancellation token + Task ChangeAccountAuthDataAsync(Guid userId, RegisterRequest data, CancellationToken cancellationToken); + + /// Removes user account + /// Identifier of account + /// Cancellation token + Task RemoveUserAccount(Guid userId, CancellationToken cancellationToken); + } +} diff --git a/SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/UsersService.cs b/SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/UsersService.cs new file mode 100644 index 0000000..ab53755 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/Services/ApprovingAuthorities/UsersService.cs @@ -0,0 +1,34 @@ +using ApplicationLayer.InfrastructureServicesInterfaces; +using ApplicationLayer.Services.AuthServices.NeededServices; +using ApplicationLayer.Services.AuthServices.Requests; +using Domains.Users; + +namespace ApplicationLayer.Services.ApprovingAuthorities +{ + public class UsersService(IUsersRepository users, IUnitOfWork unitOfWork) : IUsersService + { + async Task> IUsersService.GetAuthoritiesAccountsAsync(CancellationToken cancellationToken) + { + return await users.GetAllOfRoleAsync(Role.ApprovingAuthority, cancellationToken); + } + + async Task IUsersService.ChangeAccountAuthDataAsync(Guid userId, RegisterRequest data, CancellationToken cancellationToken) + { + var user = await users.GetByIdAsync(userId, cancellationToken); + + user.Email = data.Email; + user.Password = data.Password; + await users.UpdateAsync(user, cancellationToken); + + await unitOfWork.SaveAsync(cancellationToken); + } + + async Task IUsersService.RemoveUserAccount(Guid userId, CancellationToken cancellationToken) + { + var user = await users.GetByIdAsync(userId, cancellationToken); + users.Remove(user); + + await unitOfWork.SaveAsync(cancellationToken); + } + } +} diff --git a/SchengenVisaApi/ApplicationLayer/Services/AuthServices/NeededServices/IUsersRepository.cs b/SchengenVisaApi/ApplicationLayer/Services/AuthServices/NeededServices/IUsersRepository.cs index ef82a20..a77ff96 100644 --- a/SchengenVisaApi/ApplicationLayer/Services/AuthServices/NeededServices/IUsersRepository.cs +++ b/SchengenVisaApi/ApplicationLayer/Services/AuthServices/NeededServices/IUsersRepository.cs @@ -11,5 +11,11 @@ namespace ApplicationLayer.Services.AuthServices.NeededServices /// Cancellation token /// User or null if not found Task FindByEmailAsync(string email, CancellationToken cancellationToken); + + /// Returns all accounts with specific role + /// role + /// cancellation token + /// list of accounts + Task> GetAllOfRoleAsync(Role role, CancellationToken cancellationToken); } } diff --git a/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs b/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs index ff35e52..8c75cd9 100644 --- a/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs @@ -13,5 +13,10 @@ namespace Infrastructure.Database.Users.Repositories { return await LoadDomain().SingleOrDefaultAsync(u => u.Email == email, cancellationToken); } + + async Task> IUsersRepository.GetAllOfRoleAsync(Role role, CancellationToken cancellationToken) + { + return await LoadDomain().Where(u => u.Role == role).ToListAsync(cancellationToken); + } } } diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs index 9c59b6d..454c67d 100644 --- a/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs @@ -1,6 +1,8 @@ -using ApplicationLayer.Services.AuthServices.LoginService; +using ApplicationLayer.Services.ApprovingAuthorities; +using ApplicationLayer.Services.AuthServices.LoginService; using ApplicationLayer.Services.AuthServices.RegisterService; using ApplicationLayer.Services.AuthServices.Requests; +using Domains.Users; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SchengenVisaApi.Common; @@ -9,14 +11,17 @@ namespace SchengenVisaApi.Controllers { /// Controller for user-auth and registration [ApiController] - [Route("auth")] - public class UsersController(IRegisterService registerService, ILoginService loginService) : ControllerBase + [Route("users")] + public class UsersController( + IRegisterService registerService, + ILoginService loginService, + IUsersService authorityService) : VisaApiControllerBase { /// Adds applicant with user account to DB [HttpPost] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status409Conflict)] - [Route("applicant")] + [Route("register")] public async Task Register(RegisterApplicantRequest request, CancellationToken cancellationToken) { await registerService.Register(request, cancellationToken); @@ -42,10 +47,55 @@ namespace SchengenVisaApi.Controllers [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] + [Route("login")] public async Task Login(string email, string password, CancellationToken cancellationToken) { var result = await loginService.LoginAsync(new UserLoginRequest(email, password), cancellationToken); return Ok(result); } + + /// Returns list of authority accounts + /// Accessible only for admins + [HttpGet] + [ProducesResponseType>(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [Route("authority")] + [Authorize(policy: PolicyConstants.AdminPolicy)] + public async Task GetAuthorityAccounts(CancellationToken cancellationToken) + { + var result = await authorityService.GetAuthoritiesAccountsAsync(cancellationToken); + return Ok(result); + } + + /// Changes authority's account authentication data + /// Accessible only for admins + [HttpPut] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [Route("authority/{authorityAccountId:guid}")] + [Authorize(policy: PolicyConstants.AdminPolicy)] + public async Task ChangeAuthorityAuthData(Guid authorityAccountId, RegisterRequest authData, CancellationToken cancellationToken) + { + await authorityService.ChangeAccountAuthDataAsync(authorityAccountId, authData, cancellationToken); + return Ok(); + } + + /// Removes authority's account authentication data + /// Accessible only for admins + [HttpDelete] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [Route("authority/{authorityAccountId:guid}")] + [Authorize(policy: PolicyConstants.AdminPolicy)] + public async Task RemoveAuthorityAccount(Guid authorityAccountId, CancellationToken cancellationToken) + { + await authorityService.RemoveUserAccount(authorityAccountId, cancellationToken); + return Ok(); + } } } diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApiControllerBase.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApiControllerBase.cs new file mode 100644 index 0000000..6e90a82 --- /dev/null +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApiControllerBase.cs @@ -0,0 +1,12 @@ +using System.Security.Claims; +using Microsoft.AspNetCore.Mvc; + +namespace SchengenVisaApi.Controllers +{ + /// Base controller class for api controllers in project + public abstract class VisaApiControllerBase : ControllerBase + { + /// Returns identifier of authenticated user + protected Guid GetUserId() => Guid.Parse(HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value); + } +} diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs index 8918252..9aa3837 100644 --- a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs @@ -11,8 +11,8 @@ namespace SchengenVisaApi.Controllers; /// Controller for [ApiController] -[Route("[controller]")] -public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : ControllerBase +[Route("visaApplication")] +public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : VisaApiControllerBase { //todo should return only pending applications //todo should return model @@ -59,6 +59,4 @@ public class VisaApplicationController(IVisaApplicationRequestsHandler visaAppli await visaApplicationRequestsHandler.HandleCreateRequest(userId, request, cancellationToken); return Ok(); } - - private Guid GetUserId() => Guid.Parse(HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value); }