Вытащил солюшен на уровень выше, чтобы прощё было дотнетить
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using Domains;
|
||||
using Domains.ApplicantDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Configuration;
|
||||
|
||||
public static class AddressConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, Address> entity)
|
||||
{
|
||||
entity.Property(a => a.Country)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CountryNameLength);
|
||||
|
||||
entity.Property(a => a.City)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CityNameLength);
|
||||
|
||||
entity.Property(a => a.Street)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.StreetNameLength);
|
||||
|
||||
entity.Property(a => a.Building)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.BuildingNumberLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Domains;
|
||||
using Domains.ApplicantDomain;
|
||||
using Domains.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Configuration;
|
||||
|
||||
public class ApplicantConfiguration : IEntityTypeConfiguration<Applicant>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Applicant> entity)
|
||||
{
|
||||
entity.OwnsOne(a => a.Name, NameConfiguration<Applicant>.Configure);
|
||||
entity.OwnsOne(a => a.FatherName, NameConfiguration<Applicant>.Configure);
|
||||
entity.OwnsOne(a => a.MotherName, NameConfiguration<Applicant>.Configure);
|
||||
entity.OwnsOne(a => a.Passport, PassportConfiguration<Applicant>.Configure);
|
||||
|
||||
entity.HasOne<User>().WithOne().HasForeignKey<Applicant>(a => a.UserId);
|
||||
|
||||
entity.Property(a => a.Citizenship)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CitizenshipLength);
|
||||
|
||||
entity.Property(a => a.CitizenshipByBirth)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CitizenshipLength);
|
||||
|
||||
entity.Property(a => a.CountryOfBirth)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CountryNameLength);
|
||||
|
||||
entity.Property(a => a.CityOfBirth)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CityNameLength);
|
||||
|
||||
entity.Property(a => a.JobTitle)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.JobTitleLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Domains;
|
||||
using Domains.ApplicantDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Configuration;
|
||||
|
||||
public static class NameConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, Name> entity)
|
||||
{
|
||||
entity.Property(p => p.FirstName)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.NameLength);
|
||||
|
||||
entity.Property(p => p.Surname)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.NameLength);
|
||||
|
||||
entity.Property(p => p.Patronymic)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.NameLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Domains;
|
||||
using Domains.ApplicantDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Configuration;
|
||||
|
||||
public static class PassportConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, Passport> entity)
|
||||
{
|
||||
entity.Property(p => p.Number)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.PassportNumberLength);
|
||||
|
||||
entity.Property(p => p.Issuer)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.IssuerNameLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Domains;
|
||||
using Domains.ApplicantDomain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Configuration;
|
||||
|
||||
public class PlaceOfWorkConfiguration : IEntityTypeConfiguration<PlaceOfWork>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<PlaceOfWork> entity)
|
||||
{
|
||||
entity.OwnsOne(p => p.Address, AddressConfiguration<PlaceOfWork>.Configure);
|
||||
|
||||
entity.Property(p => p.Name)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.PlaceOfWorkNameLength);
|
||||
|
||||
entity.Property(p => p.PhoneNum)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.PhoneNumberLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using ApplicationLayer.Services.Applicants.NeededServices;
|
||||
using Domains.ApplicantDomain;
|
||||
using Infrastructure.Database.Applicants.Repositories.Exceptions;
|
||||
using Infrastructure.Database.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Repositories;
|
||||
|
||||
/// Repository pattern for <see cref="Applicant"/>
|
||||
/// <param name="reader"><inheritdoc cref="IGenericReader"/></param>
|
||||
/// <param name="writer"><inheritdoc cref="IGenericWriter"/></param>
|
||||
public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter writer)
|
||||
: GenericRepository<Applicant>(reader, writer), IApplicantsRepository
|
||||
{
|
||||
protected override IQueryable<Applicant> LoadDomain()
|
||||
{
|
||||
return base.LoadDomain()
|
||||
.Include(a => a.PlaceOfWork);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IApplicantsRepository.FindByUserIdAsync"/>
|
||||
public async Task<Applicant> FindByUserIdAsync(Guid userId, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken);
|
||||
return result ?? throw new ApplicantNotFoundByUserIdException();
|
||||
}
|
||||
|
||||
async Task<Guid> IApplicantsRepository.GetApplicantIdByUserId(Guid userId, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await base.LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken);
|
||||
return result?.Id ?? throw new ApplicantNotFoundByUserIdException();
|
||||
}
|
||||
|
||||
async Task<bool> IApplicantsRepository.IsApplicantNonResidentByUserId(Guid userId, CancellationToken cancellationToken)
|
||||
{
|
||||
var applicant = await FindByUserIdAsync(userId, cancellationToken);
|
||||
return applicant.IsNonResident;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using ApplicationLayer.GeneralExceptions;
|
||||
|
||||
namespace Infrastructure.Database.Applicants.Repositories.Exceptions;
|
||||
|
||||
public class ApplicantNotFoundByUserIdException() : EntityNotFoundException("Applicant not found.");
|
||||
39
Infrastructure/Database/DatabaseContext.cs
Normal file
39
Infrastructure/Database/DatabaseContext.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Reflection;
|
||||
using ApplicationLayer.InfrastructureServicesInterfaces;
|
||||
using Infrastructure.Database.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Infrastructure.Database;
|
||||
|
||||
public class DatabaseContext(DbContextOptions<DatabaseContext> opts) : DbContext(opts), IGenericWriter, IGenericReader, IUnitOfWork
|
||||
{
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
|
||||
}
|
||||
|
||||
async Task IGenericWriter.AddAsync<T>(T entity, CancellationToken cancellationToken)
|
||||
{
|
||||
await AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
void IGenericWriter.Update<T>(T entity)
|
||||
{
|
||||
Update(entity);
|
||||
}
|
||||
|
||||
void IGenericWriter.Remove<T>(T entity)
|
||||
{
|
||||
Remove(entity);
|
||||
}
|
||||
|
||||
IQueryable<T> IGenericReader.GetAll<T>()
|
||||
{
|
||||
return Set<T>();
|
||||
}
|
||||
|
||||
async Task IUnitOfWork.SaveAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
48
Infrastructure/Database/Generic/GenericRepository.cs
Normal file
48
Infrastructure/Database/Generic/GenericRepository.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using ApplicationLayer.GeneralExceptions;
|
||||
using ApplicationLayer.InfrastructureServicesInterfaces;
|
||||
using Domains;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Infrastructure.Database.Generic;
|
||||
|
||||
/// Generic repository pattern
|
||||
/// <param name="writer"><inheritdoc cref="IGenericWriter"/></param>
|
||||
/// <typeparam name="T">Type of entity</typeparam>
|
||||
/// <remarks>Should be inherited to create typed repositories</remarks>
|
||||
public abstract class GenericRepository<T>(IGenericReader reader, IGenericWriter writer) : IGenericRepository<T>
|
||||
where T : class, IEntity
|
||||
{
|
||||
/// <inheritdoc cref="IGenericRepository{T}.GetAllAsync"/>
|
||||
public async Task<List<T>> GetAllAsync(CancellationToken cancellationToken)
|
||||
=> await LoadDomain().ToListAsync(cancellationToken);
|
||||
|
||||
/// <inheritdoc cref="IGenericRepository{T}.GetByIdAsync"/>
|
||||
public async Task<T> GetByIdAsync(Guid id, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await LoadDomain().SingleOrDefaultAsync(a => a.Id == id, cancellationToken);
|
||||
return result ?? throw new EntityNotFoundByIdException<T>(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IGenericRepository{T}.AddAsync"/>
|
||||
public async Task AddAsync(T entity, CancellationToken cancellationToken)
|
||||
=> await writer.AddAsync(entity, cancellationToken);
|
||||
|
||||
/// <inheritdoc cref="IGenericRepository{T}.UpdateAsync"/>
|
||||
public async Task UpdateAsync(T entity, CancellationToken cancellationToken)
|
||||
{
|
||||
await GetByIdAsync(entity.Id, cancellationToken);
|
||||
writer.Update(entity);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IGenericRepository{T}.Remove"/>
|
||||
public void Remove(T entity)
|
||||
{
|
||||
writer.Remove(entity);
|
||||
}
|
||||
|
||||
/// Should be overriden to load navigation properties of entity
|
||||
protected virtual IQueryable<T> LoadDomain()
|
||||
{
|
||||
return reader.GetAll<T>();
|
||||
}
|
||||
}
|
||||
11
Infrastructure/Database/Generic/IGenericReader.cs
Normal file
11
Infrastructure/Database/Generic/IGenericReader.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Domains;
|
||||
|
||||
namespace Infrastructure.Database.Generic;
|
||||
|
||||
/// Reads from data storage
|
||||
public interface IGenericReader
|
||||
{
|
||||
/// Get all entities of type T stored in storage
|
||||
/// <typeparam name="T">Entity type to seek in storage</typeparam>
|
||||
IQueryable<T> GetAll<T>() where T : class, IEntity;
|
||||
}
|
||||
25
Infrastructure/Database/Generic/IGenericWriter.cs
Normal file
25
Infrastructure/Database/Generic/IGenericWriter.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ApplicationLayer.InfrastructureServicesInterfaces;
|
||||
using Domains;
|
||||
|
||||
namespace Infrastructure.Database.Generic;
|
||||
|
||||
/// Writes data to data storage
|
||||
/// <remarks><see cref="IUnitOfWork"/> should be used to save changes</remarks>
|
||||
public interface IGenericWriter
|
||||
{
|
||||
/// Add entity to data storage
|
||||
/// <param name="entity">Entity to add</param>
|
||||
/// <param name="cancellationToken">Cancellation Token</param>
|
||||
/// <typeparam name="T">Entity type</typeparam>
|
||||
Task AddAsync<T>(T entity, CancellationToken cancellationToken) where T : class, IEntity;
|
||||
|
||||
/// Update entity in data storage
|
||||
/// <param name="entity">Entity to update</param>
|
||||
/// <typeparam name="T">Entity type</typeparam>
|
||||
void Update<T>(T entity) where T : class, IEntity;
|
||||
|
||||
/// Remove entity from data storage
|
||||
/// <param name="entity">Entity to remove</param>
|
||||
/// <typeparam name="T">Entity type</typeparam>
|
||||
void Remove<T>(T entity) where T : class, IEntity;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Domains;
|
||||
using Domains.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.Users.Configuration;
|
||||
|
||||
public class UserConfiguration : IEntityTypeConfiguration<User>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<User> entity)
|
||||
{
|
||||
entity.Property(u => u.Email)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.EmailLength);
|
||||
|
||||
entity.HasIndex(u => u.Email).IsUnique();
|
||||
|
||||
entity.Property(u => u.Password)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.PasswordLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using ApplicationLayer.Services.AuthServices.NeededServices;
|
||||
using Domains.Users;
|
||||
using Infrastructure.Database.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Infrastructure.Database.Users.Repositories;
|
||||
|
||||
/// <inheritdoc cref="IUsersRepository"/>
|
||||
public class UsersRepository(IGenericReader reader, IGenericWriter writer)
|
||||
: GenericRepository<User>(reader, writer), IUsersRepository
|
||||
{
|
||||
async Task<User?> IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken)
|
||||
{
|
||||
return await LoadDomain().SingleOrDefaultAsync(u => u.Email == email, cancellationToken);
|
||||
}
|
||||
|
||||
async Task<List<User>> IUsersRepository.GetAllOfRoleAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
return await LoadDomain().Where(u => u.Role == role).ToListAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Domains;
|
||||
using Domains.VisaApplicationDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Configuration;
|
||||
|
||||
public static class PastVisaConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, PastVisa> entity)
|
||||
{
|
||||
entity.Property(p => p.Name)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.VisaNameLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Domains;
|
||||
using Domains.VisaApplicationDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Configuration;
|
||||
|
||||
public static class PastVisitConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, PastVisit> entity)
|
||||
{
|
||||
entity.Property(pv => pv.DestinationCountry)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CountryNameLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Domains;
|
||||
using Domains.VisaApplicationDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Configuration;
|
||||
|
||||
public static class PermissionToDestCountryConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, PermissionToDestCountry> entity)
|
||||
{
|
||||
entity.Property(p => p.Issuer)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.IssuerNameLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Domains;
|
||||
using Domains.VisaApplicationDomain;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Configuration;
|
||||
|
||||
public static class ReentryPermitConfiguration<T> where T : class, IEntity
|
||||
{
|
||||
public static void Configure(OwnedNavigationBuilder<T, ReentryPermit> entity)
|
||||
{
|
||||
entity.Property(p => p.Number)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.ReentryPermitNumberLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Domains;
|
||||
using Domains.ApplicantDomain;
|
||||
using Domains.VisaApplicationDomain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Configuration;
|
||||
|
||||
public class VisaApplicationConfiguration : IEntityTypeConfiguration<VisaApplication>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<VisaApplication> entity)
|
||||
{
|
||||
entity.OwnsOne(va => va.ReentryPermit, ReentryPermitConfiguration<VisaApplication>.Configure);
|
||||
entity.OwnsOne(va => va.PermissionToDestCountry, PermissionToDestCountryConfiguration<VisaApplication>.Configure);
|
||||
entity.OwnsMany(va => va.PastVisits, PastVisitConfiguration<VisaApplication>.Configure);
|
||||
entity.OwnsMany(va => va.PastVisas, PastVisaConfiguration<VisaApplication>.Configure);
|
||||
|
||||
entity.Property(va => va.DestinationCountry)
|
||||
.IsUnicode(false)
|
||||
.HasMaxLength(ConfigurationConstraints.CountryNameLength);
|
||||
|
||||
entity.HasOne<Applicant>()
|
||||
.WithMany()
|
||||
.HasForeignKey(va => va.ApplicantId)
|
||||
.IsRequired();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using ApplicationLayer.GeneralExceptions;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Repositories.Exceptions;
|
||||
|
||||
public class ApplicationNotFoundByApplicantAndApplicationIdException(Guid applicationId)
|
||||
: EntityNotFoundException($"Application with id {applicationId} not found for authenticated user");
|
||||
@@ -0,0 +1,36 @@
|
||||
using ApplicationLayer.Services.VisaApplications.NeededServices;
|
||||
using Domains.VisaApplicationDomain;
|
||||
using Infrastructure.Database.Generic;
|
||||
using Infrastructure.Database.VisaApplications.Repositories.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Infrastructure.Database.VisaApplications.Repositories;
|
||||
|
||||
public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWriter writer)
|
||||
: GenericRepository<VisaApplication>(reader, writer), IVisaApplicationsRepository
|
||||
{
|
||||
protected override IQueryable<VisaApplication> LoadDomain()
|
||||
=> base.LoadDomain()
|
||||
.Include(va => va.PastVisas)
|
||||
.Include(va => va.PastVisits);
|
||||
|
||||
|
||||
async Task<List<VisaApplication>> IVisaApplicationsRepository.GetOfApplicantAsync(Guid applicantId, CancellationToken cancellationToken)
|
||||
=> await LoadDomain().Where(va => va.ApplicantId == applicantId).ToListAsync(cancellationToken);
|
||||
|
||||
async Task<VisaApplication> IVisaApplicationsRepository.GetByApplicantAndApplicationIdAsync(
|
||||
Guid applicantId,
|
||||
Guid applicationId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await LoadDomain()
|
||||
.SingleOrDefaultAsync(va => va.Id == applicationId && va.ApplicantId == applicantId, cancellationToken);
|
||||
return result ?? throw new ApplicationNotFoundByApplicantAndApplicationIdException(applicationId);
|
||||
}
|
||||
|
||||
async Task<List<VisaApplication>> IVisaApplicationsRepository.GetPendingApplicationsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var result = LoadDomain().Where(va => va.Status == ApplicationStatus.Pending);
|
||||
return await result.ToListAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user