From 3cb2083222360c93b612b1663fcabe4d9afecb55 Mon Sep 17 00:00:00 2001 From: prtsie Date: Sat, 17 Aug 2024 21:30:51 +0300 Subject: [PATCH] Admin controller, Locations controller, requests to add available countries, request to get available countries --- .../Exceptions/IncorrectLoginDataException.cs | 4 -- .../Exceptions/UserAlreadyExistsException.cs | 6 -- .../RegisterService/RegisterService.cs | 31 -------- .../Requests/RegisterApplicantRequest.cs | 4 -- .../AuthServices/Requests/UserLoginRequest.cs | 4 -- .../Models/AddressModel.cs | 2 +- .../Models/PlaceOfWorkModel.cs | 2 +- .../NeededServices/IApplicantsRepository.cs | 6 +- .../LoginService/DevelopmentLoginService.cs | 28 ++++++++ .../Exceptions/IncorrectLoginDataException.cs | 6 ++ .../LoginService/ILoginService.cs | 4 +- .../AuthServices/LoginService/LoginService.cs | 8 +-- .../NeededServices/ITokenGenerator.cs | 2 +- .../NeededServices/IUsersRepository.cs | 2 +- .../Exceptions/UserAlreadyExistsException.cs | 7 ++ .../RegisterService/IRegisterService.cs | 4 +- .../RegisterService/RegisterService.cs | 71 +++++++++++++++++++ .../Requests/RegisterApplicantRequest.cs | 22 ++++++ .../AuthServices/Requests/UserLoginRequest.cs | 4 ++ .../NeededServices/ICountriesRepository.cs | 9 ++- .../EditLocationsRequestsHandler.cs | 36 ++++++++++ .../Exceptions/CountryAlreadyExists.cs | 6 ++ .../MultipleIdenticalCitiesInCountry.cs | 6 ++ .../IEditLocationsRequestsHandler.cs | 11 +++ .../ILocationRequestsHandler.cs | 12 ++++ .../LocationRequestsHandler.cs | 14 ++++ .../Locations/Requests/AddCountryRequest.cs | 4 ++ ....cs => IVisaApplicationRequestsHandler.cs} | 4 +- .../VisaApplicationRequestsHandler.cs | 44 +++--------- .../Requests/VisaApplicationCreateRequest.cs | 14 ---- .../ApplicationLayer/DependencyInjection.cs | 22 ++++-- .../AlreadyExistsException.cs | 4 ++ .../GeneralExceptions/ApiException.cs | 4 ++ .../IGenericRepository.cs | 3 - .../GeneralNeededServices}/IUnitOfWork.cs | 4 +- .../Domains/ApplicantDomain/Applicant.cs | 4 +- .../Domains/LocationDomain/City.cs | 7 +- .../Auth/ServiceCollectionsExtensions.cs | 2 +- .../Infrastructure/Auth/TokenGenerator.cs | 4 +- .../Configuration/ApplicantConfiguration.cs | 2 + .../Repositories/ApplicantsRepository.cs | 12 +++- .../ApplicantNotFoundByUserIdException.cs | 10 +++ .../Infrastructure/Database/DbContext.cs | 1 + .../EntityNotFoundException.cs | 5 +- .../Database/Generic/GenericRepository.cs | 7 +- .../Database/Generic/IGenericWriter.cs | 3 +- .../Configuration/CountryConfiguration.cs | 6 +- .../Repositories/Cities/CitiesRepository.cs | 4 +- .../Countries/CountriesRepository.cs | 12 +++- .../Users/Repositories/UsersRepository.cs | 6 +- .../VisaApplicationsRepository.cs | 6 +- .../Infrastructure/DependencyInjection.cs | 6 +- .../Common/ConfigureSwaggerOptions.cs | 37 ++++++++++ .../SchengenVisaApi/Common/PolicyConstants.cs | 12 ++++ .../Controllers/AdminController.cs | 22 ++++++ .../Controllers/LocationsController.cs | 16 +++++ .../Controllers/UsersController.cs | 9 ++- .../Controllers/VisaApplicationController.cs | 12 +++- .../SchengenVisaApi/DependencyInjection.cs | 25 ++++++- 59 files changed, 477 insertions(+), 167 deletions(-) delete mode 100644 SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs delete mode 100644 SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs delete mode 100644 SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/RegisterService.cs delete mode 100644 SchengenVisaApi/ApplicationLayer/AuthServices/Requests/RegisterApplicantRequest.cs delete mode 100644 SchengenVisaApi/ApplicationLayer/AuthServices/Requests/UserLoginRequest.cs rename SchengenVisaApi/ApplicationLayer/DataAccessingServices/{VisaApplications => Applicants}/Models/AddressModel.cs (77%) rename SchengenVisaApi/ApplicationLayer/DataAccessingServices/{VisaApplications => Applicants}/Models/PlaceOfWorkModel.cs (78%) create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/DevelopmentLoginService.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs rename SchengenVisaApi/ApplicationLayer/{ => DataAccessingServices}/AuthServices/LoginService/ILoginService.cs (66%) rename SchengenVisaApi/ApplicationLayer/{ => DataAccessingServices}/AuthServices/LoginService/LoginService.cs (66%) rename SchengenVisaApi/ApplicationLayer/{ => DataAccessingServices}/AuthServices/NeededServices/ITokenGenerator.cs (60%) rename SchengenVisaApi/ApplicationLayer/{ => DataAccessingServices}/AuthServices/NeededServices/IUsersRepository.cs (87%) create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs rename SchengenVisaApi/ApplicationLayer/{ => DataAccessingServices}/AuthServices/RegisterService/IRegisterService.cs (63%) create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/RegisterService.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/RegisterApplicantRequest.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/UserLoginRequest.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/CountryAlreadyExists.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/IEditLocationsRequestsHandler.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/ILocationRequestsHandler.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/LocationRequestsHandler.cs create mode 100644 SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/Requests/AddCountryRequest.cs rename SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/{IVisaApplicationsRequestHandler.cs => IVisaApplicationRequestsHandler.cs} (61%) create mode 100644 SchengenVisaApi/ApplicationLayer/GeneralExceptions/AlreadyExistsException.cs create mode 100644 SchengenVisaApi/ApplicationLayer/GeneralExceptions/ApiException.cs rename SchengenVisaApi/{Infrastructure/Database => ApplicationLayer/GeneralNeededServices}/IUnitOfWork.cs (77%) create mode 100644 SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/Exceptions/ApplicantNotFoundByUserIdException.cs create mode 100644 SchengenVisaApi/SchengenVisaApi/Common/ConfigureSwaggerOptions.cs create mode 100644 SchengenVisaApi/SchengenVisaApi/Common/PolicyConstants.cs create mode 100644 SchengenVisaApi/SchengenVisaApi/Controllers/AdminController.cs create mode 100644 SchengenVisaApi/SchengenVisaApi/Controllers/LocationsController.cs diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs b/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs deleted file mode 100644 index d5ee16d..0000000 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace ApplicationLayer.AuthServices.LoginService.Exceptions -{ - public class IncorrectLoginDataException() : Exception("Incorrect email or password"); -} diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs b/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs deleted file mode 100644 index bd32eb1..0000000 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs +++ /dev/null @@ -1,6 +0,0 @@ -using ApplicationLayer.AuthServices.Requests; - -namespace ApplicationLayer.AuthServices.RegisterService.Exceptions -{ - public class UserAlreadyExistsException(RegisterApplicantRequest request) : Exception($"User with email '{request.Email}' already exists"); -} diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/RegisterService.cs b/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/RegisterService.cs deleted file mode 100644 index 83ab4cc..0000000 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/RegisterService.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ApplicationLayer.AuthServices.NeededServices; -using ApplicationLayer.AuthServices.RegisterService.Exceptions; -using ApplicationLayer.AuthServices.Requests; -using Domains.Users; - -namespace ApplicationLayer.AuthServices.RegisterService -{ - /// - public class RegisterService(IUsersRepository users) : IRegisterService - { - async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) - { - if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) - { - throw new UserAlreadyExistsException(request); - } - - //TODO mapper - var user = new User - { - Email = request.Email, - Password = request.Password, - Role = Role.Applicant - }; - - await users.AddAsync(user, cancellationToken); - await users.SaveAsync(cancellationToken); - users.GetAllAsync(cancellationToken); - } - } -} diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/Requests/RegisterApplicantRequest.cs b/SchengenVisaApi/ApplicationLayer/AuthServices/Requests/RegisterApplicantRequest.cs deleted file mode 100644 index e919545..0000000 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/Requests/RegisterApplicantRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace ApplicationLayer.AuthServices.Requests -{ - public record RegisterApplicantRequest(string Email, string Password); -} diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/Requests/UserLoginRequest.cs b/SchengenVisaApi/ApplicationLayer/AuthServices/Requests/UserLoginRequest.cs deleted file mode 100644 index a1ed5cf..0000000 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/Requests/UserLoginRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace ApplicationLayer.AuthServices.Requests -{ - public record UserLoginRequest(string Email, string Password); -} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Models/AddressModel.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/Models/AddressModel.cs similarity index 77% rename from SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Models/AddressModel.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/Models/AddressModel.cs index 5e6909b..fb9cfc2 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Models/AddressModel.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/Models/AddressModel.cs @@ -1,4 +1,4 @@ -namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models; +namespace ApplicationLayer.DataAccessingServices.Applicants.Models; public class AddressModel { diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Models/PlaceOfWorkModel.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/Models/PlaceOfWorkModel.cs similarity index 78% rename from SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Models/PlaceOfWorkModel.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/Models/PlaceOfWorkModel.cs index 42b6b1d..a69fc82 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Models/PlaceOfWorkModel.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/Models/PlaceOfWorkModel.cs @@ -1,4 +1,4 @@ -namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models; +namespace ApplicationLayer.DataAccessingServices.Applicants.Models; public class PlaceOfWorkModel { diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/NeededServices/IApplicantsRepository.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/NeededServices/IApplicantsRepository.cs index 1ac3667..a355353 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/NeededServices/IApplicantsRepository.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Applicants/NeededServices/IApplicantsRepository.cs @@ -4,4 +4,8 @@ using Domains.ApplicantDomain; namespace ApplicationLayer.DataAccessingServices.Applicants.NeededServices; /// Repository pattern for -public interface IApplicantsRepository : IGenericRepository; +public interface IApplicantsRepository : IGenericRepository +{ + /// Find by Identifier + Task FindByUserIdAsync(Guid userId, CancellationToken cancellationToken); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/DevelopmentLoginService.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/DevelopmentLoginService.cs new file mode 100644 index 0000000..b7e2fa3 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/DevelopmentLoginService.cs @@ -0,0 +1,28 @@ +using ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; +using Domains.Users; + +namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService +{ + public class DevelopmentLoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService + { + async Task ILoginService.LoginAsync(UserLoginRequest request, CancellationToken cancellationToken) + { + if (request is { Email: "admin@mail.ru", Password: "admin" }) + { + var admin = new User { Role = Role.Admin }; + + return tokenGenerator.CreateToken(admin); + } + + var user = await users.FindByEmailAsync(request.Email, cancellationToken); + if (user is null || user.Password != request.Password) + { + throw new IncorrectLoginDataException(); + } + + return tokenGenerator.CreateToken(user); + } + } +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs new file mode 100644 index 0000000..4c2f887 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/Exceptions/IncorrectLoginDataException.cs @@ -0,0 +1,6 @@ +using ApplicationLayer.GeneralExceptions; + +namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions +{ + public class IncorrectLoginDataException() : ApiException("Incorrect email or password"); +} diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/ILoginService.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/ILoginService.cs similarity index 66% rename from SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/ILoginService.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/ILoginService.cs index b9f26c5..0ca04ea 100644 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/ILoginService.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/ILoginService.cs @@ -1,6 +1,6 @@ -using ApplicationLayer.AuthServices.Requests; +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; -namespace ApplicationLayer.AuthServices.LoginService +namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService { /// Handles public interface ILoginService diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/LoginService.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/LoginService.cs similarity index 66% rename from SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/LoginService.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/LoginService.cs index d0279a9..e662d2e 100644 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/LoginService/LoginService.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/LoginService/LoginService.cs @@ -1,8 +1,8 @@ -using ApplicationLayer.AuthServices.LoginService.Exceptions; -using ApplicationLayer.AuthServices.NeededServices; -using ApplicationLayer.AuthServices.Requests; +using ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; -namespace ApplicationLayer.AuthServices.LoginService +namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService { /// public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/NeededServices/ITokenGenerator.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/NeededServices/ITokenGenerator.cs similarity index 60% rename from SchengenVisaApi/ApplicationLayer/AuthServices/NeededServices/ITokenGenerator.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/NeededServices/ITokenGenerator.cs index 1c9b2fa..bb2525d 100644 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/NeededServices/ITokenGenerator.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/NeededServices/ITokenGenerator.cs @@ -1,6 +1,6 @@ using Domains.Users; -namespace ApplicationLayer.AuthServices.NeededServices +namespace ApplicationLayer.DataAccessingServices.AuthServices.NeededServices { public interface ITokenGenerator { diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/NeededServices/IUsersRepository.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/NeededServices/IUsersRepository.cs similarity index 87% rename from SchengenVisaApi/ApplicationLayer/AuthServices/NeededServices/IUsersRepository.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/NeededServices/IUsersRepository.cs index 3f1f206..4f74f88 100644 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/NeededServices/IUsersRepository.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/NeededServices/IUsersRepository.cs @@ -1,7 +1,7 @@ using ApplicationLayer.GeneralNeededServices; using Domains.Users; -namespace ApplicationLayer.AuthServices.NeededServices +namespace ApplicationLayer.DataAccessingServices.AuthServices.NeededServices { /// Repository pattern for public interface IUsersRepository : IGenericRepository diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs new file mode 100644 index 0000000..9a115be --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/Exceptions/UserAlreadyExistsException.cs @@ -0,0 +1,7 @@ +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; +using ApplicationLayer.GeneralExceptions; + +namespace ApplicationLayer.DataAccessingServices.AuthServices.RegisterService.Exceptions +{ + public class UserAlreadyExistsException(RegisterApplicantRequest request) : AlreadyExistsException($"User with email '{request.Email}' already exists"); +} diff --git a/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/IRegisterService.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/IRegisterService.cs similarity index 63% rename from SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/IRegisterService.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/IRegisterService.cs index 54c0e0c..be331be 100644 --- a/SchengenVisaApi/ApplicationLayer/AuthServices/RegisterService/IRegisterService.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/IRegisterService.cs @@ -1,6 +1,6 @@ -using ApplicationLayer.AuthServices.Requests; +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; -namespace ApplicationLayer.AuthServices.RegisterService +namespace ApplicationLayer.DataAccessingServices.AuthServices.RegisterService { /// Handles public interface IRegisterService diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/RegisterService.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/RegisterService.cs new file mode 100644 index 0000000..9611916 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/RegisterService/RegisterService.cs @@ -0,0 +1,71 @@ +using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.RegisterService.Exceptions; +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; +using ApplicationLayer.DataAccessingServices.Locations.NeededServices; +using ApplicationLayer.GeneralNeededServices; +using Domains.ApplicantDomain; +using Domains.Users; + +namespace ApplicationLayer.DataAccessingServices.AuthServices.RegisterService +{ + /// + public class RegisterService( + IUsersRepository users, + IApplicantsRepository applicants, + ICitiesRepository cities, + IUnitOfWork unitOfWork) : IRegisterService + { + async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) + { + if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) + { + throw new UserAlreadyExistsException(request); + } + + //TODO mapper + var user = new User { Email = request.Email, Password = request.Password, Role = Role.Applicant }; + + var applicantCity = await cities.GetByIdAsync(request.CityOfBirthId, cancellationToken); + var placeOfWorkCity = await cities.GetByIdAsync(request.PlaceOfWork.Address.CityId, cancellationToken); + var placeOfWorkAddress = new Address + { + Country = placeOfWorkCity.Country, + City = placeOfWorkCity, + Building = request.PlaceOfWork.Address.Building, + Street = request.PlaceOfWork.Address.Street + }; + + var placeOfWork = new PlaceOfWork + { + Name = request.PlaceOfWork.Name, + Address = placeOfWorkAddress, + PhoneNum = request.PlaceOfWork.PhoneNum + }; + + var applicant = new Applicant + { + Citizenship = request.Citizenship, + CitizenshipByBirth = request.CitizenshipByBirth, + Gender = request.Gender, + Name = request.ApplicantName, + Passport = request.Passport, + BirthDate = request.BirthDate, + FatherName = request.FatherName, + JobTitle = request.JobTitle, + MaritalStatus = request.MaritalStatus, + MotherName = request.MotherName, + UserId = user.Id, + CityOfBirth = applicantCity, + CountryOfBirth = applicantCity.Country, + IsNonResident = request.IsNonResident, + PlaceOfWork = placeOfWork + }; + + await users.AddAsync(user, cancellationToken); + await applicants.AddAsync(applicant, cancellationToken); + + await unitOfWork.SaveAsync(cancellationToken); + } + } +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/RegisterApplicantRequest.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/RegisterApplicantRequest.cs new file mode 100644 index 0000000..bbaa0da --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/RegisterApplicantRequest.cs @@ -0,0 +1,22 @@ +using ApplicationLayer.DataAccessingServices.Applicants.Models; +using Domains.ApplicantDomain; + +namespace ApplicationLayer.DataAccessingServices.AuthServices.Requests +{ + public record RegisterApplicantRequest( + string Email, + string Password, + Name ApplicantName, + Passport Passport, + DateTime BirthDate, + Guid CityOfBirthId, + string Citizenship, + string CitizenshipByBirth, + Gender Gender, + MaritalStatus MaritalStatus, + Name FatherName, + Name MotherName, + string JobTitle, + PlaceOfWorkModel PlaceOfWork, + bool IsNonResident); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/UserLoginRequest.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/UserLoginRequest.cs new file mode 100644 index 0000000..1cf039b --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/AuthServices/Requests/UserLoginRequest.cs @@ -0,0 +1,4 @@ +namespace ApplicationLayer.DataAccessingServices.AuthServices.Requests +{ + public record UserLoginRequest(string Email, string Password); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/NeededServices/ICountriesRepository.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/NeededServices/ICountriesRepository.cs index ca86c9e..3de0b05 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/NeededServices/ICountriesRepository.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/NeededServices/ICountriesRepository.cs @@ -3,4 +3,11 @@ using Domains.LocationDomain; namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices; -public interface ICountriesRepository : IGenericRepository; +public interface ICountriesRepository : IGenericRepository +{ + /// Gets country by name + /// Name of country to seek + /// Cancellation Token + /// Country or null if not found + Task FindByName(string countryName, CancellationToken cancellationToken); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs new file mode 100644 index 0000000..e84e975 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs @@ -0,0 +1,36 @@ +using ApplicationLayer.DataAccessingServices.Locations.NeededServices; +using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions; +using ApplicationLayer.DataAccessingServices.Locations.Requests; +using ApplicationLayer.GeneralNeededServices; +using Domains.LocationDomain; + +namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests +{ + /// + public class EditLocationsRequestsHandler(ICountriesRepository countries, IUnitOfWork unitOfWork) : IEditLocationsRequestsHandler + { + async Task IEditLocationsRequestsHandler.AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken) + { + if (await countries.FindByName(request.CountryName, cancellationToken) is not null) + { + throw new CountryAlreadyExists(request.CountryName); + } + + if (request.Cities.Distinct().Count() < request.Cities.Length) + { + throw new MultipleIdenticalCitiesInCountry(); + } + + var country = new Country + { + Name = request.CountryName, + IsSchengen = request.IsSchengen, + Cities = request.Cities.Select(cityName => new City { Name = cityName }).ToList() + }; + + await countries.AddAsync(country, cancellationToken); + + await unitOfWork.SaveAsync(cancellationToken); + } + } +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/CountryAlreadyExists.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/CountryAlreadyExists.cs new file mode 100644 index 0000000..b7e6d36 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/CountryAlreadyExists.cs @@ -0,0 +1,6 @@ +using ApplicationLayer.GeneralExceptions; + +namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions +{ + public class CountryAlreadyExists(string countryName) : AlreadyExistsException($"{countryName} already exists."); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs new file mode 100644 index 0000000..a32da0a --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs @@ -0,0 +1,6 @@ +using ApplicationLayer.GeneralExceptions; + +namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions +{ + public class MultipleIdenticalCitiesInCountry() : ApiException("There are multiple cities with one name in the country."); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/IEditLocationsRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/IEditLocationsRequestsHandler.cs new file mode 100644 index 0000000..d8c36a9 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/IEditLocationsRequestsHandler.cs @@ -0,0 +1,11 @@ +using ApplicationLayer.DataAccessingServices.Locations.Requests; + +namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests +{ + /// Handles edit requests of locations from admins + public interface IEditLocationsRequestsHandler + { + /// Handles add country requests + Task AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken); + } +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/ILocationRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/ILocationRequestsHandler.cs new file mode 100644 index 0000000..7299308 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/ILocationRequestsHandler.cs @@ -0,0 +1,12 @@ +using Domains.LocationDomain; + +namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests +{ + /// Handles location requests + public interface ILocationRequestsHandler + { + /// Handle get request + /// List of available countries + Task> HandleGetRequestAsync(CancellationToken cancellationToken); + } +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/LocationRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/LocationRequestsHandler.cs new file mode 100644 index 0000000..f69951c --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/ApplicantRequests/LocationRequestsHandler.cs @@ -0,0 +1,14 @@ +using ApplicationLayer.DataAccessingServices.Locations.NeededServices; +using Domains.LocationDomain; + +namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests +{ + /// + public class LocationRequestsHandler(ICountriesRepository countries) : ILocationRequestsHandler + { + async Task> ILocationRequestsHandler.HandleGetRequestAsync(CancellationToken cancellationToken) + { + return await countries.GetAllAsync(cancellationToken); + } + } +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/Requests/AddCountryRequest.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/Requests/AddCountryRequest.cs new file mode 100644 index 0000000..902e6e1 --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/Requests/AddCountryRequest.cs @@ -0,0 +1,4 @@ +namespace ApplicationLayer.DataAccessingServices.Locations.Requests +{ + public record AddCountryRequest(string CountryName, bool IsSchengen, string[] Cities); +} diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/IVisaApplicationsRequestHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/IVisaApplicationRequestsHandler.cs similarity index 61% rename from SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/IVisaApplicationsRequestHandler.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/IVisaApplicationRequestsHandler.cs index 7ef57b2..d5b52c5 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/IVisaApplicationsRequestHandler.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/IVisaApplicationRequestsHandler.cs @@ -3,9 +3,9 @@ using Domains.VisaApplicationDomain; namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; -public interface IVisaApplicationsRequestHandler +public interface IVisaApplicationRequestsHandler { Task> Get(CancellationToken cancellationToken); - void HandleCreateRequest(VisaApplicationCreateRequest request, CancellationToken cancellationToken); + void HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken); } diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs index dc25a53..4c99f20 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs @@ -1,8 +1,9 @@ -using ApplicationLayer.DataAccessingServices.Locations.NeededServices; +using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; +using ApplicationLayer.DataAccessingServices.Locations.NeededServices; using ApplicationLayer.DataAccessingServices.VisaApplications.Models; using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; -using Domains.ApplicantDomain; +using ApplicationLayer.GeneralNeededServices; using Domains.VisaApplicationDomain; namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; @@ -10,42 +11,18 @@ namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; /// Handles visa requests public class VisaApplicationRequestsHandler( IVisaApplicationsRepository applications, - ICitiesRepository cities, - ICountriesRepository countries) : IVisaApplicationsRequestHandler + IApplicantsRepository applicants, + ICountriesRepository countries, + IUnitOfWork unitOfWork) : IVisaApplicationRequestsHandler { public async Task> Get(CancellationToken cancellationToken) => await applications.GetAllAsync(cancellationToken); - public async void HandleCreateRequest(VisaApplicationCreateRequest request, CancellationToken cancellationToken) + public async void HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken) { + //TODO fix //TODO mapper - var cityOfBirth = await cities.GetByIdAsync(request.BirthCityId, cancellationToken); - var cityOfWork = await cities.GetByIdAsync(request.PlaceOfWork.Address.CityId, cancellationToken); - var addressOfWork = new Address - { - City = cityOfWork, - Country = cityOfWork.Country, - Building = request.PlaceOfWork.Address.Building, - Street = request.PlaceOfWork.Address.Street - }; - - var applicant = new Applicant - { - MaritalStatus = request.MaritalStatus, - Name = request.FullName, - Passport = request.Passport, - Gender = request.Gender, - Citizenship = request.CitizenShip, - BirthDate = request.BirthDate, - FatherName = request.FatherName, - JobTitle = request.JobTitle, - MotherName = request.MotherName, - CitizenshipByBirth = request.CitizenshipByBirth, - CityOfBirth = cityOfBirth, - CountryOfBirth = cityOfBirth.Country, - IsNonResident = request.IsNonResident, - PlaceOfWork = new PlaceOfWork { Address = addressOfWork, Name = request.PlaceOfWork.Name, PhoneNum = request.PlaceOfWork.PhoneNum } - }; + var applicant = await applicants.FindByUserIdAsync(userId, cancellationToken); var pastVisits = request.PastVisits.Select(m => ConvertPastVisitModelToPastVisit(m, cancellationToken).Result).ToList(); var visaApplication = new VisaApplication @@ -64,7 +41,8 @@ public class VisaApplicationRequestsHandler( }; await applications.AddAsync(visaApplication, cancellationToken); - await applications.SaveAsync(cancellationToken); + + await unitOfWork.SaveAsync(cancellationToken); } private async Task ConvertPastVisitModelToPastVisit(PastVisitModel model, CancellationToken cancellationToken) diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Requests/VisaApplicationCreateRequest.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Requests/VisaApplicationCreateRequest.cs index 4a5bf1a..2127cc3 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Requests/VisaApplicationCreateRequest.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/VisaApplications/Requests/VisaApplicationCreateRequest.cs @@ -1,25 +1,11 @@ using ApplicationLayer.DataAccessingServices.VisaApplications.Models; -using Domains.ApplicantDomain; using Domains.VisaApplicationDomain; namespace ApplicationLayer.DataAccessingServices.VisaApplications.Requests; /// Model of visa request from user public record VisaApplicationCreateRequest( - Name FullName, - Passport Passport, - DateTime BirthDate, - Guid BirthCityId, - string CitizenShip, - string CitizenshipByBirth, - Gender Gender, - MaritalStatus MaritalStatus, - Name FatherName, - Name MotherName, - bool IsNonResident, ReentryPermit ReentryPermit, - string JobTitle, - PlaceOfWorkModel PlaceOfWork, Guid DestinationCountryId, VisaCategory VisaCategory, bool IsForGroup, diff --git a/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs b/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs index 8fa5014..00977ec 100644 --- a/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs +++ b/SchengenVisaApi/ApplicationLayer/DependencyInjection.cs @@ -1,5 +1,7 @@ -using ApplicationLayer.AuthServices.LoginService; -using ApplicationLayer.AuthServices.RegisterService; +using ApplicationLayer.DataAccessingServices.AuthServices.LoginService; +using ApplicationLayer.DataAccessingServices.AuthServices.RegisterService; +using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests; +using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests; using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; using Microsoft.Extensions.DependencyInjection; @@ -9,12 +11,22 @@ namespace ApplicationLayer; public static class DependencyInjection { /// Add services for Application layer - public static IServiceCollection AddApplicationLayer(this IServiceCollection services) + public static IServiceCollection AddApplicationLayer(this IServiceCollection services, bool isDevelopment = false) { - services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); - services.AddScoped(); + + if (isDevelopment) + { + services.AddScoped(); + } + else + { + services.AddScoped(); + } return services; } diff --git a/SchengenVisaApi/ApplicationLayer/GeneralExceptions/AlreadyExistsException.cs b/SchengenVisaApi/ApplicationLayer/GeneralExceptions/AlreadyExistsException.cs new file mode 100644 index 0000000..51daa4e --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/GeneralExceptions/AlreadyExistsException.cs @@ -0,0 +1,4 @@ +namespace ApplicationLayer.GeneralExceptions +{ + public class AlreadyExistsException(string message) : ApiException(message); +} diff --git a/SchengenVisaApi/ApplicationLayer/GeneralExceptions/ApiException.cs b/SchengenVisaApi/ApplicationLayer/GeneralExceptions/ApiException.cs new file mode 100644 index 0000000..8f7ed6a --- /dev/null +++ b/SchengenVisaApi/ApplicationLayer/GeneralExceptions/ApiException.cs @@ -0,0 +1,4 @@ +namespace ApplicationLayer.GeneralExceptions +{ + public class ApiException(string message) : Exception(message); +} diff --git a/SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IGenericRepository.cs b/SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IGenericRepository.cs index d8474f7..e0d84ca 100644 --- a/SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IGenericRepository.cs +++ b/SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IGenericRepository.cs @@ -34,7 +34,4 @@ public interface IGenericRepository where T : class, IEntity /// /// Entity to remove void Remove(T entity); - - /// Save changes in storage - Task SaveAsync(CancellationToken cancellationToken); } diff --git a/SchengenVisaApi/Infrastructure/Database/IUnitOfWork.cs b/SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IUnitOfWork.cs similarity index 77% rename from SchengenVisaApi/Infrastructure/Database/IUnitOfWork.cs rename to SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IUnitOfWork.cs index 821c4f1..cf7fef7 100644 --- a/SchengenVisaApi/Infrastructure/Database/IUnitOfWork.cs +++ b/SchengenVisaApi/ApplicationLayer/GeneralNeededServices/IUnitOfWork.cs @@ -1,8 +1,8 @@ -namespace Infrastructure.Database; +namespace ApplicationLayer.GeneralNeededServices; public interface IUnitOfWork { /// Saves changes in data storage /// Cancellation Token Task SaveAsync(CancellationToken cancellationToken); -} \ No newline at end of file +} diff --git a/SchengenVisaApi/Domains/ApplicantDomain/Applicant.cs b/SchengenVisaApi/Domains/ApplicantDomain/Applicant.cs index dc2efa4..91404c2 100644 --- a/SchengenVisaApi/Domains/ApplicantDomain/Applicant.cs +++ b/SchengenVisaApi/Domains/ApplicantDomain/Applicant.cs @@ -6,7 +6,9 @@ namespace Domains.ApplicantDomain; public class Applicant : IEntity { /// Unique identifier of the - public Guid Id { get; set; } + public Guid Id { get; private set; } = Guid.NewGuid(); + + public Guid UserId { get; set; } /// Full name of the public Name Name { get; set; } = null!; diff --git a/SchengenVisaApi/Domains/LocationDomain/City.cs b/SchengenVisaApi/Domains/LocationDomain/City.cs index ebc0e31..1a646f6 100644 --- a/SchengenVisaApi/Domains/LocationDomain/City.cs +++ b/SchengenVisaApi/Domains/LocationDomain/City.cs @@ -1,4 +1,6 @@ -namespace Domains.LocationDomain; +using System.Text.Json.Serialization; + +namespace Domains.LocationDomain; /// Model of a city public class City : IEntity @@ -10,5 +12,6 @@ public class City : IEntity public string Name { get; set; } = null!; /// in which the city is located + [JsonIgnore] public Country Country { get; set; } = null!; -} \ No newline at end of file +} diff --git a/SchengenVisaApi/Infrastructure/Auth/ServiceCollectionsExtensions.cs b/SchengenVisaApi/Infrastructure/Auth/ServiceCollectionsExtensions.cs index 1138163..f72fc22 100644 --- a/SchengenVisaApi/Infrastructure/Auth/ServiceCollectionsExtensions.cs +++ b/SchengenVisaApi/Infrastructure/Auth/ServiceCollectionsExtensions.cs @@ -1,5 +1,5 @@ using System.IdentityModel.Tokens.Jwt; -using ApplicationLayer.AuthServices.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; using ApplicationLayer.GeneralNeededServices; using Microsoft.Extensions.DependencyInjection; diff --git a/SchengenVisaApi/Infrastructure/Auth/TokenGenerator.cs b/SchengenVisaApi/Infrastructure/Auth/TokenGenerator.cs index 54363b4..a7e5627 100644 --- a/SchengenVisaApi/Infrastructure/Auth/TokenGenerator.cs +++ b/SchengenVisaApi/Infrastructure/Auth/TokenGenerator.cs @@ -1,6 +1,6 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; -using ApplicationLayer.AuthServices.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; using ApplicationLayer.GeneralNeededServices; using Domains.Users; @@ -14,7 +14,7 @@ namespace Infrastructure.Auth var claims = new List { new(ClaimTypes.Role, user.Role.ToString()), - new(ClaimTypes.Email, user.Email) + new(ClaimTypes.NameIdentifier, user.Id.ToString()) }; var token = new JwtSecurityToken( diff --git a/SchengenVisaApi/Infrastructure/Database/Applicants/Configuration/ApplicantConfiguration.cs b/SchengenVisaApi/Infrastructure/Database/Applicants/Configuration/ApplicantConfiguration.cs index cadf620..96f6fe7 100644 --- a/SchengenVisaApi/Infrastructure/Database/Applicants/Configuration/ApplicantConfiguration.cs +++ b/SchengenVisaApi/Infrastructure/Database/Applicants/Configuration/ApplicantConfiguration.cs @@ -1,4 +1,5 @@ using Domains.ApplicantDomain; +using Domains.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -16,6 +17,7 @@ public class ApplicantConfiguration : IEntityTypeConfiguration entity.HasOne(a => a.CityOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); entity.HasOne(a => a.CountryOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); + entity.HasOne().WithOne().HasForeignKey(a => a.UserId); entity.Property(p => p.Citizenship) .IsUnicode(false) diff --git a/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/ApplicantsRepository.cs b/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/ApplicantsRepository.cs index aaf0ece..1d47955 100644 --- a/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/ApplicantsRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/ApplicantsRepository.cs @@ -1,5 +1,6 @@ using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; using Domains.ApplicantDomain; +using Infrastructure.Database.Applicants.Repositories.Exceptions; using Infrastructure.Database.Generic; using Microsoft.EntityFrameworkCore; @@ -8,9 +9,8 @@ namespace Infrastructure.Database.Applicants.Repositories; /// Repository pattern for /// /// -/// -public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) - : GenericRepository(reader, writer, unitOfWork), IApplicantsRepository +public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter writer) + : GenericRepository(reader, writer), IApplicantsRepository { protected override IQueryable LoadDomain() { @@ -19,4 +19,10 @@ public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter w .Include(a => a.CityOfBirth) .Include(a => a.PlaceOfWork); } + + async Task IApplicantsRepository.FindByUserIdAsync(Guid userId, CancellationToken cancellationToken) + { + var result = await LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken); + return result ?? throw new ApplicantNotFoundByUserIdException(userId); + } } diff --git a/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/Exceptions/ApplicantNotFoundByUserIdException.cs b/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/Exceptions/ApplicantNotFoundByUserIdException.cs new file mode 100644 index 0000000..9e8d6a1 --- /dev/null +++ b/SchengenVisaApi/Infrastructure/Database/Applicants/Repositories/Exceptions/ApplicantNotFoundByUserIdException.cs @@ -0,0 +1,10 @@ +using Domains.ApplicantDomain; +using Infrastructure.Database.GeneralExceptions; + +namespace Infrastructure.Database.Applicants.Repositories.Exceptions +{ + public class ApplicantNotFoundByUserIdException(Guid id) : EntityNotFoundException("Applicant not found.") + { + public Guid UserId { get; private set; } = id; + } +} diff --git a/SchengenVisaApi/Infrastructure/Database/DbContext.cs b/SchengenVisaApi/Infrastructure/Database/DbContext.cs index 021bc66..f4fa8fb 100644 --- a/SchengenVisaApi/Infrastructure/Database/DbContext.cs +++ b/SchengenVisaApi/Infrastructure/Database/DbContext.cs @@ -1,4 +1,5 @@ using System.Reflection; +using ApplicationLayer.GeneralNeededServices; using Infrastructure.Database.Generic; using Microsoft.EntityFrameworkCore; diff --git a/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundException.cs b/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundException.cs index 3d6ce3d..37de24f 100644 --- a/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundException.cs +++ b/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundException.cs @@ -1,8 +1,9 @@ -using Domains; +using ApplicationLayer.GeneralExceptions; +using Domains; namespace Infrastructure.Database.GeneralExceptions; /// Exception to throw when entity not found /// Not found entity type -public class EntityNotFoundException(string message) : Exception(message) +public class EntityNotFoundException(string message) : ApiException(message) where T : class, IEntity; diff --git a/SchengenVisaApi/Infrastructure/Database/Generic/GenericRepository.cs b/SchengenVisaApi/Infrastructure/Database/Generic/GenericRepository.cs index 48d716d..0a9fc3a 100644 --- a/SchengenVisaApi/Infrastructure/Database/Generic/GenericRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/Generic/GenericRepository.cs @@ -7,10 +7,9 @@ namespace Infrastructure.Database.Generic; /// Generic repository pattern /// -/// /// Type of entity /// Should be inherited to create typed repositories -public abstract class GenericRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) : IGenericRepository +public abstract class GenericRepository(IGenericReader reader, IGenericWriter writer) : IGenericRepository where T : class, IEntity { /// @@ -41,10 +40,6 @@ public abstract class GenericRepository(IGenericReader reader, IGenericWriter writer.Remove(entity); } - /// - public async Task SaveAsync(CancellationToken cancellationToken) - => await unitOfWork.SaveAsync(cancellationToken); - /// Should be overriden to load navigation properties of entity protected virtual IQueryable LoadDomain() { diff --git a/SchengenVisaApi/Infrastructure/Database/Generic/IGenericWriter.cs b/SchengenVisaApi/Infrastructure/Database/Generic/IGenericWriter.cs index 77db3c2..d84a68e 100644 --- a/SchengenVisaApi/Infrastructure/Database/Generic/IGenericWriter.cs +++ b/SchengenVisaApi/Infrastructure/Database/Generic/IGenericWriter.cs @@ -1,4 +1,5 @@ -using Domains; +using ApplicationLayer.GeneralNeededServices; +using Domains; namespace Infrastructure.Database.Generic; diff --git a/SchengenVisaApi/Infrastructure/Database/Locations/Configuration/CountryConfiguration.cs b/SchengenVisaApi/Infrastructure/Database/Locations/Configuration/CountryConfiguration.cs index 5f0459e..6ef5bf2 100644 --- a/SchengenVisaApi/Infrastructure/Database/Locations/Configuration/CountryConfiguration.cs +++ b/SchengenVisaApi/Infrastructure/Database/Locations/Configuration/CountryConfiguration.cs @@ -8,8 +8,10 @@ public class CountryConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder entity) { - entity.Property(p => p.Name) + entity.Property(c => c.Name) .IsUnicode(false) .HasMaxLength(70); + + entity.HasIndex(c => c.Name).IsUnique(); } -} \ No newline at end of file +} diff --git a/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Cities/CitiesRepository.cs b/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Cities/CitiesRepository.cs index 953a0d6..5c52bb6 100644 --- a/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Cities/CitiesRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Cities/CitiesRepository.cs @@ -5,8 +5,8 @@ using Microsoft.EntityFrameworkCore; namespace Infrastructure.Database.Locations.Repositories.Cities; -public sealed class CitiesRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) - : GenericRepository(reader, writer, unitOfWork), ICitiesRepository +public sealed class CitiesRepository(IGenericReader reader, IGenericWriter writer) + : GenericRepository(reader, writer), ICitiesRepository { protected override IQueryable LoadDomain() { diff --git a/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Countries/CountriesRepository.cs b/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Countries/CountriesRepository.cs index e17f5d8..e291da7 100644 --- a/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Countries/CountriesRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/Locations/Repositories/Countries/CountriesRepository.cs @@ -5,11 +5,17 @@ using Microsoft.EntityFrameworkCore; namespace Infrastructure.Database.Locations.Repositories.Countries; -public sealed class CountriesRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) - : GenericRepository(reader, writer, unitOfWork), ICountriesRepository +public sealed class CountriesRepository(IGenericReader reader, IGenericWriter writer) + : GenericRepository(reader, writer), ICountriesRepository { protected override IQueryable LoadDomain() { return base.LoadDomain().Include(c => c.Cities); } -} \ No newline at end of file + + async Task ICountriesRepository.FindByName(string countryName, CancellationToken cancellationToken) + { + var result = await LoadDomain().SingleOrDefaultAsync(c => c.Name == countryName, cancellationToken); + return result; + } +} diff --git a/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs b/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs index 665fbc7..6ca9c1a 100644 --- a/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/Users/Repositories/UsersRepository.cs @@ -1,4 +1,4 @@ -using ApplicationLayer.AuthServices.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; using Domains.Users; using Infrastructure.Database.Generic; using Microsoft.EntityFrameworkCore; @@ -6,8 +6,8 @@ using Microsoft.EntityFrameworkCore; namespace Infrastructure.Database.Users.Repositories { /// - public class UsersRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) - : GenericRepository(reader, writer, unitOfWork), IUsersRepository + public class UsersRepository(IGenericReader reader, IGenericWriter writer) + : GenericRepository(reader, writer), IUsersRepository { async Task IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken) { diff --git a/SchengenVisaApi/Infrastructure/Database/VisaApplications/Repositories/VisaApplicationsRepository.cs b/SchengenVisaApi/Infrastructure/Database/VisaApplications/Repositories/VisaApplicationsRepository.cs index a287b82..9363762 100644 --- a/SchengenVisaApi/Infrastructure/Database/VisaApplications/Repositories/VisaApplicationsRepository.cs +++ b/SchengenVisaApi/Infrastructure/Database/VisaApplications/Repositories/VisaApplicationsRepository.cs @@ -5,8 +5,8 @@ using Microsoft.EntityFrameworkCore; namespace Infrastructure.Database.VisaApplications.Repositories; -public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) - : GenericRepository(reader, writer, unitOfWork), IVisaApplicationsRepository +public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWriter writer) + : GenericRepository(reader, writer), IVisaApplicationsRepository { protected override IQueryable LoadDomain() { @@ -15,4 +15,4 @@ public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWr .Include(a => a.PastVisas) .Include(a => a.PastVisits); } -} \ No newline at end of file +} diff --git a/SchengenVisaApi/Infrastructure/DependencyInjection.cs b/SchengenVisaApi/Infrastructure/DependencyInjection.cs index ac1e261..dc53b94 100644 --- a/SchengenVisaApi/Infrastructure/DependencyInjection.cs +++ b/SchengenVisaApi/Infrastructure/DependencyInjection.cs @@ -1,11 +1,9 @@ -using ApplicationLayer.AuthServices.NeededServices; -using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; +using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; +using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; using ApplicationLayer.DataAccessingServices.Locations.NeededServices; using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; using ApplicationLayer.GeneralNeededServices; -using Infrastructure.Auth; using Infrastructure.Common; -using Infrastructure.Database; using Infrastructure.Database.Applicants.Repositories; using Infrastructure.Database.Generic; using Infrastructure.Database.Locations.Repositories.Cities; diff --git a/SchengenVisaApi/SchengenVisaApi/Common/ConfigureSwaggerOptions.cs b/SchengenVisaApi/SchengenVisaApi/Common/ConfigureSwaggerOptions.cs new file mode 100644 index 0000000..51aa125 --- /dev/null +++ b/SchengenVisaApi/SchengenVisaApi/Common/ConfigureSwaggerOptions.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace SchengenVisaApi.Common +{ + public class ConfigureSwaggerOptions : IConfigureOptions + { + void IConfigureOptions.Configure(SwaggerGenOptions options) + { + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Provide a JWT-token.", + Name = "Authorization", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT", + Scheme = "Bearer" + }); + + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + Array.Empty() + } + }); + } + } +} diff --git a/SchengenVisaApi/SchengenVisaApi/Common/PolicyConstants.cs b/SchengenVisaApi/SchengenVisaApi/Common/PolicyConstants.cs new file mode 100644 index 0000000..111b5bc --- /dev/null +++ b/SchengenVisaApi/SchengenVisaApi/Common/PolicyConstants.cs @@ -0,0 +1,12 @@ +namespace SchengenVisaApi.Common +{ +#pragma warning disable CS1591 + public static class PolicyConstants + { + public const string AdminPolicy = "AdminPolicy"; + public const string ApplicantPolicy = "ApplicantPolicy"; + public const string ApprovingAuthorityPolicy = "ApprovingAuthorityPolicy"; + } +#pragma warning enable CS1591 + +} diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/AdminController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/AdminController.cs new file mode 100644 index 0000000..09b1bd4 --- /dev/null +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/AdminController.cs @@ -0,0 +1,22 @@ +using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests; +using ApplicationLayer.DataAccessingServices.Locations.Requests; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SchengenVisaApi.Common; + +namespace SchengenVisaApi.Controllers +{ + [ApiController] + [Route("admin")] + [Authorize(policy: PolicyConstants.AdminPolicy)] + public class AdminController(IEditLocationsRequestsHandler requestsHandler) : ControllerBase + { + [HttpPost] + [Route("country")] + public async Task AddCountry(AddCountryRequest request, CancellationToken cancellationToken) + { + await requestsHandler.AddCountryAsync(request, cancellationToken); + return Ok(); + } + } +} diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/LocationsController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/LocationsController.cs new file mode 100644 index 0000000..f2fbde6 --- /dev/null +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/LocationsController.cs @@ -0,0 +1,16 @@ +using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests; +using Microsoft.AspNetCore.Mvc; + +namespace SchengenVisaApi.Controllers +{ + [ApiController] + [Route("countries")] + public class LocationsController(ILocationRequestsHandler requestsHandler) : ControllerBase + { + [HttpGet] + public async Task GetAvailableLocations(CancellationToken cancellationToken) + { + return Ok(await requestsHandler.HandleGetRequestAsync(cancellationToken)); + } + } +} diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs index 237b64c..4bc546d 100644 --- a/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs @@ -1,14 +1,13 @@ -using ApplicationLayer.AuthServices.LoginService; -using ApplicationLayer.AuthServices.RegisterService; -using ApplicationLayer.AuthServices.Requests; -using Microsoft.AspNetCore.Identity.Data; +using ApplicationLayer.DataAccessingServices.AuthServices.LoginService; +using ApplicationLayer.DataAccessingServices.AuthServices.RegisterService; +using ApplicationLayer.DataAccessingServices.AuthServices.Requests; using Microsoft.AspNetCore.Mvc; namespace SchengenVisaApi.Controllers { [ApiController] [Route("auth")] - public class UsersController(IRegisterService registerService, ILoginService loginService) : Controller + public class UsersController(IRegisterService registerService, ILoginService loginService) : ControllerBase { [HttpPost] public async Task Register(RegisterApplicantRequest request, CancellationToken cancellationToken) diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs index 80cb645..c85664b 100644 --- a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs @@ -1,23 +1,29 @@ +using System.Security.Claims; using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using SchengenVisaApi.Common; namespace SchengenVisaApi.Controllers; [ApiController] [Route("[controller]")] -public class VisaApplicationController(IVisaApplicationsRequestHandler visaApplicationsRequestHandler) : ControllerBase +[Authorize(policy: PolicyConstants.ApplicantPolicy)] +public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : ControllerBase { + //TODO remove [HttpGet] public async Task Get(CancellationToken cancellationToken) { - var result = await visaApplicationsRequestHandler.Get(cancellationToken); + var result = await visaApplicationRequestsHandler.Get(cancellationToken); return Ok(result); } [HttpPost] public void Create(VisaApplicationCreateRequest request, CancellationToken cancellationToken) { - visaApplicationsRequestHandler.HandleCreateRequest(request, cancellationToken); + var userId = Guid.Parse(HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value); + visaApplicationRequestsHandler.HandleCreateRequest(userId, request, cancellationToken); } } diff --git a/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs b/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs index 1c27bbc..f1e759b 100644 --- a/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs +++ b/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs @@ -1,10 +1,16 @@ using System.Reflection; +using System.Security.Claims; using System.Text; using ApplicationLayer; +using Domains.Users; using Infrastructure; using Infrastructure.Auth; using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using SchengenVisaApi.Common; +using Swashbuckle.AspNetCore.SwaggerGen; namespace SchengenVisaApi; @@ -19,7 +25,7 @@ public static class DependencyInjection builder.Services .AddInfrastructure(config, environment.IsDevelopment()) - .AddApplicationLayer() + .AddApplicationLayer(environment.IsDevelopment()) .AddAuth(config) .AddPresentation(environment); } @@ -52,7 +58,7 @@ public static class DependencyInjection services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(opts => opts.TokenValidationParameters = parameters); - services.AddAuthorization(); + services.AddAuthorizationBuilder().ConfigureAuthorizationPolicies(); services.AddTokenGenerator(new TokenGeneratorOptions( Issuer: parameters.ValidIssuer!, @@ -64,9 +70,24 @@ public static class DependencyInjection return services; } + /// Configure roles + private static void ConfigureAuthorizationPolicies(this AuthorizationBuilder builder) + { + builder.AddPolicy( + PolicyConstants.AdminPolicy, + p => p.RequireClaim(ClaimTypes.Role, Role.Admin.ToString())) + .AddPolicy( + PolicyConstants.ApprovingAuthorityPolicy, + p => p.RequireClaim(ClaimTypes.Role, Role.ApprovingAuthority.ToString())) + .AddPolicy( + PolicyConstants.ApplicantPolicy, + p => p.RequireClaim(ClaimTypes.Role, Role.Applicant.ToString())); + } + /// Add swagger private static void AddSwagger(this IServiceCollection services) { + services.AddTransient, ConfigureSwaggerOptions>(); services.AddSwaggerGen(options => { var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";