Added authentication and authorization, updated dependency injections, removed hard-coded connection string

This commit is contained in:
2024-08-17 16:28:35 +03:00
parent 026a104131
commit 7cbe3d9698
44 changed files with 419 additions and 49 deletions

View File

@@ -14,4 +14,8 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0-preview.7.24405.7" />
</ItemGroup>
<ItemGroup>
<Folder Include="DataAccessingServices\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,4 @@
namespace ApplicationLayer.AuthServices.LoginService.Exceptions
{
public class IncorrectLoginDataException() : Exception("Incorrect email or password");
}

View File

@@ -0,0 +1,12 @@
using ApplicationLayer.AuthServices.Requests;
namespace ApplicationLayer.AuthServices.LoginService
{
/// Handles <see cref="UserLoginRequest"/>
public interface ILoginService
{
/// Handle <see cref="UserLoginRequest"/>
/// <returns>JWT-token</returns>
Task<string> LoginAsync(UserLoginRequest request, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,21 @@
using ApplicationLayer.AuthServices.LoginService.Exceptions;
using ApplicationLayer.AuthServices.NeededServices;
using ApplicationLayer.AuthServices.Requests;
namespace ApplicationLayer.AuthServices.LoginService
{
/// <inheritdoc cref="ILoginService"/>
public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService
{
async Task<string> ILoginService.LoginAsync(UserLoginRequest request, CancellationToken cancellationToken)
{
var user = await users.FindByEmailAsync(request.Email, cancellationToken);
if (user is null || user.Password != request.Password)
{
throw new IncorrectLoginDataException();
}
return tokenGenerator.CreateToken(user);
}
}
}

View File

@@ -0,0 +1,9 @@
using Domains.Users;
namespace ApplicationLayer.AuthServices.NeededServices
{
public interface ITokenGenerator
{
string CreateToken(User user);
}
}

View File

@@ -0,0 +1,15 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.Users;
namespace ApplicationLayer.AuthServices.NeededServices
{
/// Repository pattern for <see cref="User"/>
public interface IUsersRepository : IGenericRepository<User>
{
/// Find <see cref="User"/> by email
/// <param name="email"><see cref="User"/>'s email</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>User or null if not found</returns>
Task<User?> FindByEmailAsync(string email, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,6 @@
using ApplicationLayer.AuthServices.Requests;
namespace ApplicationLayer.AuthServices.RegisterService.Exceptions
{
public class UserAlreadyExistsException(RegisterApplicantRequest request) : Exception($"User with email '{request.Email}' already exists");
}

View File

@@ -0,0 +1,11 @@
using ApplicationLayer.AuthServices.Requests;
namespace ApplicationLayer.AuthServices.RegisterService
{
/// Handles <see cref="RegisterApplicantRequest"/>
public interface IRegisterService
{
/// Handle <see cref="RegisterApplicantRequest"/>
Task Register(RegisterApplicantRequest request, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,31 @@
using ApplicationLayer.AuthServices.NeededServices;
using ApplicationLayer.AuthServices.RegisterService.Exceptions;
using ApplicationLayer.AuthServices.Requests;
using Domains.Users;
namespace ApplicationLayer.AuthServices.RegisterService
{
/// <inheritdoc cref="IRegisterService"/>
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);
}
}
}

View File

@@ -0,0 +1,4 @@
namespace ApplicationLayer.AuthServices.Requests
{
public record RegisterApplicantRequest(string Email, string Password);
}

View File

@@ -0,0 +1,4 @@
namespace ApplicationLayer.AuthServices.Requests
{
public record UserLoginRequest(string Email, string Password);
}

View File

@@ -1,7 +1,7 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.ApplicantDomain;
namespace ApplicationLayer.Applicants.NeededServices;
namespace ApplicationLayer.DataAccessingServices.Applicants.NeededServices;
/// Repository pattern for <see cref="Applicant"/>
public interface IApplicantsRepository : IGenericRepository<Applicant> { }
public interface IApplicantsRepository : IGenericRepository<Applicant>;

View File

@@ -0,0 +1,6 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.LocationDomain;
namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices;
public interface ICitiesRepository : IGenericRepository<City>;

View File

@@ -1,6 +1,6 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.LocationDomain;
namespace ApplicationLayer.Locations.NeededServices;
namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices;
public interface ICountriesRepository : IGenericRepository<Country> { }
public interface ICountriesRepository : IGenericRepository<Country>;

View File

@@ -1,7 +1,7 @@
using ApplicationLayer.VisaApplications.Requests;
using ApplicationLayer.DataAccessingServices.VisaApplications.Requests;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.VisaApplications.Handlers;
namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers;
public interface IVisaApplicationsRequestHandler
{

View File

@@ -1,11 +1,11 @@
using ApplicationLayer.Locations.NeededServices;
using ApplicationLayer.VisaApplications.Models;
using ApplicationLayer.VisaApplications.NeededServices;
using ApplicationLayer.VisaApplications.Requests;
using ApplicationLayer.DataAccessingServices.Locations.NeededServices;
using ApplicationLayer.DataAccessingServices.VisaApplications.Models;
using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices;
using ApplicationLayer.DataAccessingServices.VisaApplications.Requests;
using Domains.ApplicantDomain;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.VisaApplications.Handlers;
namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers;
/// Handles visa requests
public class VisaApplicationRequestsHandler(
@@ -64,6 +64,7 @@ public class VisaApplicationRequestsHandler(
};
await applications.AddAsync(visaApplication, cancellationToken);
await applications.SaveAsync(cancellationToken);
}
private async Task<PastVisit> ConvertPastVisitModelToPastVisit(PastVisitModel model, CancellationToken cancellationToken)

View File

@@ -1,4 +1,4 @@
namespace ApplicationLayer.VisaApplications.Models;
namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models;
public class AddressModel
{

View File

@@ -1,4 +1,4 @@
namespace ApplicationLayer.VisaApplications.Models
namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models
{
public class PastVisitModel
{

View File

@@ -1,4 +1,4 @@
namespace ApplicationLayer.VisaApplications.Models;
namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models;
public class PlaceOfWorkModel
{

View File

@@ -1,6 +1,6 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.VisaApplications.NeededServices;
namespace ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices;
public interface IVisaApplicationsRepository : IGenericRepository<VisaApplication> { }
public interface IVisaApplicationsRepository : IGenericRepository<VisaApplication>;

View File

@@ -1,8 +1,8 @@
using ApplicationLayer.VisaApplications.Models;
using ApplicationLayer.DataAccessingServices.VisaApplications.Models;
using Domains.ApplicantDomain;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.VisaApplications.Requests;
namespace ApplicationLayer.DataAccessingServices.VisaApplications.Requests;
/// Model of visa request from user
public record VisaApplicationCreateRequest(

View File

@@ -1,4 +1,6 @@
using ApplicationLayer.VisaApplications.Handlers;
using ApplicationLayer.AuthServices.LoginService;
using ApplicationLayer.AuthServices.RegisterService;
using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers;
using Microsoft.Extensions.DependencyInjection;
namespace ApplicationLayer;
@@ -11,6 +13,9 @@ public static class DependencyInjection
{
services.AddScoped<IVisaApplicationsRequestHandler, VisaApplicationRequestsHandler>();
services.AddScoped<IRegisterService, RegisterService>();
services.AddScoped<ILoginService, LoginService>();
return services;
}
}

View File

@@ -0,0 +1,8 @@
namespace ApplicationLayer.GeneralNeededServices
{
public interface IDateTimeProvider
{
/// Returns current date and time
DateTime Now();
}
}

View File

@@ -1,6 +0,0 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.LocationDomain;
namespace ApplicationLayer.Locations.NeededServices;
public interface ICitiesRepository : IGenericRepository<City> { }