Renamed folder

This commit is contained in:
2024-08-19 22:25:08 +03:00
parent bd43611edf
commit 0afe775d85
45 changed files with 103 additions and 95 deletions

View File

@@ -0,0 +1,13 @@
namespace ApplicationLayer.Services.Applicants.Models;
public class AddressModel
{
/// City part of address
public Guid CityId { get; set; }
/// Street part of address
public string Street { get; set; } = null!;
/// Building part of address
public string Building { get; set; } = null!;
}

View File

@@ -0,0 +1,13 @@
namespace ApplicationLayer.Services.Applicants.Models;
public class PlaceOfWorkModel
{
/// Name of hirer
public string Name { get; set; } = null!;
/// <see cref="AddressModel"/> of hirer
public AddressModel Address { get; set; } = null!;
/// Phone number of hirer
public string PhoneNum { get; set; } = null!;
}

View File

@@ -0,0 +1,11 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.ApplicantDomain;
namespace ApplicationLayer.Services.Applicants.NeededServices;
/// Repository pattern for <see cref="Applicant"/>
public interface IApplicantsRepository : IGenericRepository<Applicant>
{
/// Find <see cref="Applicant"/> by Identifier
Task<Applicant> FindByUserIdAsync(Guid userId, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,28 @@
using ApplicationLayer.Services.AuthServices.LoginService.Exceptions;
using ApplicationLayer.Services.AuthServices.NeededServices;
using ApplicationLayer.Services.AuthServices.Requests;
using Domains.Users;
namespace ApplicationLayer.Services.AuthServices.LoginService
{
public class DevelopmentLoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService
{
async Task<string> 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);
}
}
}

View File

@@ -0,0 +1,6 @@
using ApplicationLayer.GeneralExceptions;
namespace ApplicationLayer.Services.AuthServices.LoginService.Exceptions
{
public class IncorrectLoginDataException() : ApiException("Incorrect email or password");
}

View File

@@ -0,0 +1,12 @@
using ApplicationLayer.Services.AuthServices.Requests;
namespace ApplicationLayer.Services.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.Services.AuthServices.LoginService.Exceptions;
using ApplicationLayer.Services.AuthServices.NeededServices;
using ApplicationLayer.Services.AuthServices.Requests;
namespace ApplicationLayer.Services.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.Services.AuthServices.NeededServices
{
public interface ITokenGenerator
{
string CreateToken(User user);
}
}

View File

@@ -0,0 +1,15 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.Users;
namespace ApplicationLayer.Services.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,7 @@
using ApplicationLayer.GeneralExceptions;
using ApplicationLayer.Services.AuthServices.Requests;
namespace ApplicationLayer.Services.AuthServices.RegisterService.Exceptions
{
public class UserAlreadyExistsException(RegisterApplicantRequest request) : AlreadyExistsException($"User with email '{request.Email}' already exists");
}

View File

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

View File

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

View File

@@ -0,0 +1,22 @@
using ApplicationLayer.Services.Applicants.Models;
using Domains.ApplicantDomain;
namespace ApplicationLayer.Services.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);
}

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
using ApplicationLayer.GeneralNeededServices;
using Domains.LocationDomain;
namespace ApplicationLayer.Services.Locations.NeededServices;
public interface ICountriesRepository : IGenericRepository<Country>
{
/// Gets country by name
/// <param name="countryName">Name of country to seek</param>
/// <param name="cancellationToken">Cancellation Token</param>
/// <returns>Country or null if not found</returns>
Task<Country?> FindByName(string countryName, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,36 @@
using ApplicationLayer.GeneralNeededServices;
using ApplicationLayer.Services.Locations.NeededServices;
using ApplicationLayer.Services.Locations.RequestHandlers.AdminRequests.Exceptions;
using ApplicationLayer.Services.Locations.Requests;
using Domains.LocationDomain;
namespace ApplicationLayer.Services.Locations.RequestHandlers.AdminRequests
{
/// <inheritdoc cref="IEditLocationsRequestsHandler"/>
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 MultipleIdenticalCitiesInCountryException();
}
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);
}
}
}

View File

@@ -0,0 +1,6 @@
using ApplicationLayer.GeneralExceptions;
namespace ApplicationLayer.Services.Locations.RequestHandlers.AdminRequests.Exceptions
{
public class CountryAlreadyExists(string countryName) : AlreadyExistsException($"{countryName} already exists.");
}

View File

@@ -0,0 +1,6 @@
using ApplicationLayer.GeneralExceptions;
namespace ApplicationLayer.Services.Locations.RequestHandlers.AdminRequests.Exceptions
{
public class MultipleIdenticalCitiesInCountryException() : ApiException("There are multiple cities with one name in the country.");
}

View File

@@ -0,0 +1,11 @@
using ApplicationLayer.Services.Locations.Requests;
namespace ApplicationLayer.Services.Locations.RequestHandlers.AdminRequests
{
/// Handles edit requests of locations from admins
public interface IEditLocationsRequestsHandler
{
/// Handles add country requests
Task AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,12 @@
using Domains.LocationDomain;
namespace ApplicationLayer.Services.Locations.RequestHandlers.ApplicantRequests
{
/// Handles location requests
public interface ILocationRequestsHandler
{
/// Handle get request
/// <returns>List of available countries</returns>
Task<List<Country>> HandleGetRequestAsync(CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,14 @@
using ApplicationLayer.Services.Locations.NeededServices;
using Domains.LocationDomain;
namespace ApplicationLayer.Services.Locations.RequestHandlers.ApplicantRequests
{
/// <inheritdoc cref="ILocationRequestsHandler"/>
public class LocationRequestsHandler(ICountriesRepository countries) : ILocationRequestsHandler
{
async Task<List<Country>> ILocationRequestsHandler.HandleGetRequestAsync(CancellationToken cancellationToken)
{
return await countries.GetAllAsync(cancellationToken);
}
}
}

View File

@@ -0,0 +1,4 @@
namespace ApplicationLayer.Services.Locations.Requests
{
public record AddCountryRequest(string CountryName, bool IsSchengen, string[] Cities);
}

View File

@@ -0,0 +1,11 @@
using ApplicationLayer.Services.VisaApplications.Requests;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.Services.VisaApplications.Handlers;
public interface IVisaApplicationRequestsHandler
{
Task<List<VisaApplication>> Get(CancellationToken cancellationToken);
void HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,57 @@
using ApplicationLayer.GeneralNeededServices;
using ApplicationLayer.Services.Applicants.NeededServices;
using ApplicationLayer.Services.Locations.NeededServices;
using ApplicationLayer.Services.VisaApplications.Models;
using ApplicationLayer.Services.VisaApplications.NeededServices;
using ApplicationLayer.Services.VisaApplications.Requests;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.Services.VisaApplications.Handlers;
/// Handles visa requests
public class VisaApplicationRequestsHandler(
IVisaApplicationsRepository applications,
IApplicantsRepository applicants,
ICountriesRepository countries,
IUnitOfWork unitOfWork) : IVisaApplicationRequestsHandler
{
public async Task<List<VisaApplication>> Get(CancellationToken cancellationToken) => await applications.GetAllAsync(cancellationToken);
public async void HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken)
{
//TODO fix
//TODO mapper
var applicant = await applicants.FindByUserIdAsync(userId, cancellationToken);
var pastVisits = request.PastVisits.Select(m => ConvertPastVisitModelToPastVisit(m, cancellationToken).Result).ToList();
var visaApplication = new VisaApplication
{
Applicant = applicant,
RequestedNumberOfEntries = request.RequestedNumberOfEntries,
ValidDaysRequested = request.ValidDaysRequested,
ReentryPermit = request.ReentryPermit,
VisaCategory = request.VisaCategory,
PermissionToDestCountry = request.PermissionToDestCountry,
DestinationCountry = await countries.GetByIdAsync(request.DestinationCountryId, cancellationToken),
PastVisas = request.PastVisas.ToList(),
PastVisits = pastVisits,
ForGroup = request.IsForGroup,
RequestDate = DateTime.Today
};
await applications.AddAsync(visaApplication, cancellationToken);
await unitOfWork.SaveAsync(cancellationToken);
}
private async Task<PastVisit> ConvertPastVisitModelToPastVisit(PastVisitModel model, CancellationToken cancellationToken)
{
return new PastVisit
{
DestinationCountry = await countries.GetByIdAsync(model.DestinationCountryId, cancellationToken),
StartDate = model.StartDate,
EndDate = model.EndDate
};
}
}

View File

@@ -0,0 +1,14 @@
namespace ApplicationLayer.Services.VisaApplications.Models
{
public class PastVisitModel
{
/// First day of <see cref="PastVisitModel"/>
public DateTime StartDate { get; set; }
/// Last day of <see cref="PastVisitModel"/>
public DateTime EndDate { get; set; }
/// Identifier of destination country of <see cref="PastVisitModel"/>
public Guid DestinationCountryId { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,17 @@
using ApplicationLayer.Services.VisaApplications.Models;
using Domains.VisaApplicationDomain;
namespace ApplicationLayer.Services.VisaApplications.Requests;
/// Model of visa request from user
public record VisaApplicationCreateRequest(
ReentryPermit ReentryPermit,
Guid DestinationCountryId,
VisaCategory VisaCategory,
bool IsForGroup,
RequestedNumberOfEntries RequestedNumberOfEntries,
int ValidDaysRequested,
PastVisa[] PastVisas,
PermissionToDestCountry? PermissionToDestCountry,
PastVisitModel[] PastVisits
);