Вытащил солюшен на уровень выше, чтобы прощё было дотнетить
	
		
			
	
		
	
	
		
	
		
			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,5 @@ | ||||
| using ApplicationLayer.GeneralExceptions; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Exceptions; | ||||
|  | ||||
| public class ApplicationAlreadyProcessedException() : ApiException("This application already processed or closed by applicant."); | ||||
| @@ -0,0 +1,31 @@ | ||||
| using ApplicationLayer.Services.VisaApplications.Models; | ||||
| using ApplicationLayer.Services.VisaApplications.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Handlers; | ||||
|  | ||||
| public interface IVisaApplicationRequestsHandler | ||||
| { | ||||
|     /// Returns all applications for approving authorities | ||||
|     Task<List<VisaApplicationPreview>> GetPendingAsync(CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Returns all applications of one applicant | ||||
|     Task<List<VisaApplicationPreview>> GetForApplicantAsync(CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Returns one application with specific id | ||||
|     Task<VisaApplicationModel> GetApplicationForApplicantAsync(Guid id, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Returns one application with specific id | ||||
|     Task<VisaApplicationModel> GetApplicationForAuthorityAsync(Guid id, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Creates application for applicant with specific user identifier | ||||
|     Task HandleCreateRequestAsync(VisaApplicationCreateRequest request, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Sets application status to closed | ||||
|     Task HandleCloseRequestAsync(Guid applicationId, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Sets application status to approved or rejected | ||||
|     Task SetApplicationStatusFromAuthorityAsync(Guid applicationId, AuthorityRequestStatuses status, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Returns stream with file with formatted application data to download | ||||
|     Task<Stream> ApplicationToStreamAsync(Guid applicationId, CancellationToken cancellationToken); | ||||
| } | ||||
| @@ -0,0 +1,115 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using ApplicationLayer.Services.Applicants.Models; | ||||
| using ApplicationLayer.Services.Applicants.NeededServices; | ||||
| using ApplicationLayer.Services.VisaApplications.Exceptions; | ||||
| using ApplicationLayer.Services.VisaApplications.Models; | ||||
| using ApplicationLayer.Services.VisaApplications.NeededServices; | ||||
| using ApplicationLayer.Services.VisaApplications.Requests; | ||||
| using AutoMapper; | ||||
| using Domains.VisaApplicationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Handlers; | ||||
|  | ||||
| /// Handles visa requests | ||||
| public class VisaApplicationRequestsHandler( | ||||
|     IVisaApplicationsRepository applications, | ||||
|     IApplicantsRepository applicants, | ||||
|     IUnitOfWork unitOfWork, | ||||
|     IMapper mapper, | ||||
|     IDateTimeProvider dateTimeProvider, | ||||
|     IUserIdProvider userIdProvider, | ||||
|     IEntityWriter entityWriter) : IVisaApplicationRequestsHandler | ||||
| { | ||||
|     async Task<List<VisaApplicationPreview>> IVisaApplicationRequestsHandler.GetPendingAsync(CancellationToken cancellationToken) | ||||
|     { | ||||
|         var applicationsList = await applications.GetPendingApplicationsAsync(cancellationToken); | ||||
|  | ||||
|         var applicationModels = mapper.Map<List<VisaApplicationPreview>>(applicationsList); | ||||
|         return applicationModels; | ||||
|     } | ||||
|  | ||||
|     async Task<List<VisaApplicationPreview>> IVisaApplicationRequestsHandler.GetForApplicantAsync(CancellationToken cancellationToken) | ||||
|     { | ||||
|         var applicantId = await applicants.GetApplicantIdByUserId(userIdProvider.GetUserId(), cancellationToken); | ||||
|         var visaApplications = await applications.GetOfApplicantAsync(applicantId, cancellationToken); | ||||
|         return mapper.Map<List<VisaApplicationPreview>>(visaApplications); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc cref="IVisaApplicationRequestsHandler.GetApplicationForApplicantAsync"/> | ||||
|     public async Task<VisaApplicationModel> GetApplicationForApplicantAsync(Guid id, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var applicant = await applicants.FindByUserIdAsync(userIdProvider.GetUserId(), cancellationToken); | ||||
|         var application = await applications.GetByApplicantAndApplicationIdAsync(applicant.Id, id, cancellationToken); | ||||
|         var mapped = mapper.Map<VisaApplicationModel>(application); | ||||
|         mapped.Applicant = mapper.Map<ApplicantModel>(applicant); | ||||
|         return mapped; | ||||
|     } | ||||
|  | ||||
|     async Task<VisaApplicationModel> IVisaApplicationRequestsHandler.GetApplicationForAuthorityAsync(Guid id, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var pending = await applications.GetPendingApplicationsAsync(cancellationToken); | ||||
|         var application = pending.SingleOrDefault(a => a.Id == id) ?? throw new ApplicationAlreadyProcessedException(); | ||||
|         var mapped = mapper.Map<VisaApplicationModel>(application); | ||||
|         var applicant = await applicants.GetByIdAsync(application.ApplicantId, cancellationToken); | ||||
|         mapped.Applicant = mapper.Map<ApplicantModel>(applicant); | ||||
|         return mapped; | ||||
|     } | ||||
|  | ||||
|     async Task IVisaApplicationRequestsHandler.HandleCreateRequestAsync(VisaApplicationCreateRequest request, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var applicant = await applicants.FindByUserIdAsync(userIdProvider.GetUserId(), cancellationToken); | ||||
|  | ||||
|         var visaApplication = mapper.Map<VisaApplication>(request); | ||||
|         visaApplication.RequestDate = dateTimeProvider.Now(); | ||||
|         visaApplication.ApplicantId = applicant.Id; | ||||
|  | ||||
|         await applications.AddAsync(visaApplication, cancellationToken); | ||||
|  | ||||
|         await unitOfWork.SaveAsync(cancellationToken); | ||||
|     } | ||||
|  | ||||
|     async Task IVisaApplicationRequestsHandler.HandleCloseRequestAsync(Guid applicationId, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var applicantId = await applicants.GetApplicantIdByUserId(userIdProvider.GetUserId(), cancellationToken); | ||||
|         var application = await applications.GetByApplicantAndApplicationIdAsync(applicantId, applicationId, cancellationToken); | ||||
|         if (application.Status is ApplicationStatus.Approved or ApplicationStatus.Rejected) | ||||
|         { | ||||
|             throw new ApplicationAlreadyProcessedException(); | ||||
|         } | ||||
|  | ||||
|         application.Status = ApplicationStatus.Closed; | ||||
|         await applications.UpdateAsync(application, cancellationToken); | ||||
|  | ||||
|         await unitOfWork.SaveAsync(cancellationToken); | ||||
|     } | ||||
|  | ||||
|     async Task IVisaApplicationRequestsHandler.SetApplicationStatusFromAuthorityAsync( | ||||
|         Guid applicationId, | ||||
|         AuthorityRequestStatuses status, | ||||
|         CancellationToken cancellationToken) | ||||
|     { | ||||
|         var application = await applications.GetByIdAsync(applicationId, cancellationToken); | ||||
|         if (application.Status != ApplicationStatus.Pending) | ||||
|         { | ||||
|             throw new ApplicationAlreadyProcessedException(); | ||||
|         } | ||||
|  | ||||
|         var statusToSet = status switch | ||||
|         { | ||||
|             AuthorityRequestStatuses.Approved => ApplicationStatus.Approved, | ||||
|             AuthorityRequestStatuses.Rejected => ApplicationStatus.Rejected, | ||||
|             _ => throw new ArgumentOutOfRangeException(nameof(status), status, null) | ||||
|         }; | ||||
|  | ||||
|         application.Status = statusToSet; | ||||
|         await applications.UpdateAsync(application, cancellationToken); | ||||
|  | ||||
|         await unitOfWork.SaveAsync(cancellationToken); | ||||
|     } | ||||
|  | ||||
|     async Task<Stream> IVisaApplicationRequestsHandler.ApplicationToStreamAsync(Guid applicationId, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var application = await GetApplicationForApplicantAsync(applicationId, cancellationToken); | ||||
|         return await entityWriter.WriteEntityToStream(application, cancellationToken); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,7 @@ | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| public enum AuthorityRequestStatuses | ||||
| { | ||||
|     Approved, | ||||
|     Rejected | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using Domains; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| /// Model of past visa for presentation layer | ||||
| public class PastVisaModel | ||||
| { | ||||
|     // Date of issue | ||||
|     [Required] | ||||
|     public DateTime IssueDate { get; set; } | ||||
|  | ||||
|     /// Name of visa | ||||
|     [MaxLength(ConfigurationConstraints.VisaNameLength)] | ||||
|     [Required] | ||||
|     public string Name { get; set; } = null!; | ||||
|  | ||||
|     /// Date when visa expires | ||||
|     [Required] | ||||
|     public DateTime ExpirationDate { get; set; } | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using Domains; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| /// Model of past visit for presentation layer | ||||
| public class PastVisitModel | ||||
| { | ||||
|     /// First day of past visit | ||||
|     [Required] | ||||
|     public DateTime StartDate { get; set; } | ||||
|  | ||||
|     /// Last day of past visit | ||||
|     [Required] | ||||
|     public DateTime EndDate { get; set; } | ||||
|  | ||||
|     /// Destination country of past visit | ||||
|     [MaxLength(ConfigurationConstraints.CountryNameLength)] | ||||
|     [Required] | ||||
|     public string DestinationCountry { get; set; } = null!; | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using Domains; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| /// Model of permission to destination country for presentation layer | ||||
| public class PermissionToDestCountryModel | ||||
| { | ||||
|     /// Date when permission to destination country expires | ||||
|     [Required] | ||||
|     public DateTime ExpirationDate { get; set; } | ||||
|  | ||||
|     /// Issuing authority | ||||
|     [MaxLength(ConfigurationConstraints.IssuerNameLength)] | ||||
|     [Required] | ||||
|     public string Issuer { get; set; } = null!; | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using Domains; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| /// Model of re-entry permit for presentation layer | ||||
| public class ReentryPermitModel | ||||
| { | ||||
|     /// Number of re-entry permit | ||||
|     [MaxLength(ConfigurationConstraints.ReentryPermitNumberLength)] | ||||
|     [Required] | ||||
|     public string Number { get; set; } = null!; | ||||
|  | ||||
|     /// Date when re-entry permit expires | ||||
|     [Required] | ||||
|     public DateTime ExpirationDate { get; set; } | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using Domains; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models.Validation; | ||||
|  | ||||
| public class PastVisaModelValidator : AbstractValidator<PastVisaModel> | ||||
| { | ||||
|     public PastVisaModelValidator(IDateTimeProvider dateTimeProvider) | ||||
|     { | ||||
|         RuleFor(v => v.ExpirationDate) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Expiration date of past visa can not be empty") | ||||
|             .GreaterThan(v => v.IssueDate) | ||||
|             .WithMessage("Past visa expiration date can not be earlier than issue date"); | ||||
|  | ||||
|         RuleFor(v => v.IssueDate) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Issue date of past visa can not be empty") | ||||
|             .LessThan(dateTimeProvider.Now()) | ||||
|             .WithMessage("Issue date of past visa must be in past"); | ||||
|  | ||||
|         RuleFor(v => v.Name) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Name of past visa can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Name of past visa can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.VisaNameLength) | ||||
|             .WithMessage($"Past visa name length must be less than {ConfigurationConstraints.VisaNameLength}"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using Domains; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models.Validation; | ||||
|  | ||||
| public class PastVisitModelValidator : AbstractValidator<PastVisitModel> | ||||
| { | ||||
|     public PastVisitModelValidator(IDateTimeProvider dateTimeProvider) | ||||
|     { | ||||
|         RuleFor(v => v.StartDate) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Start date of past visit can not be empty") | ||||
|             .LessThan(v => v.EndDate) | ||||
|             .WithMessage("Start date of past visit must be earlier than end date") | ||||
|             .LessThan(dateTimeProvider.Now()) | ||||
|             .WithMessage("Start date of past visit must be in past"); | ||||
|  | ||||
|         RuleFor(v => v.EndDate) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("End date of past visit can not be empty"); | ||||
|  | ||||
|         RuleFor(v => v.DestinationCountry) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Destination Country of past visit can not be null") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Destination Country of past visit can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|             .WithMessage($"Destination Country of past visit length must be less than {ConfigurationConstraints.CountryNameLength}"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using Domains; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models.Validation; | ||||
|  | ||||
| public class PermissionToDestCountryModelValidator : AbstractValidator<PermissionToDestCountryModel?> | ||||
| { | ||||
|     public PermissionToDestCountryModelValidator(IDateTimeProvider dateTimeProvider) | ||||
|     { | ||||
|         RuleFor(p => p!.ExpirationDate) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Expiration date of permission to destination Country can not be empty") | ||||
|             .GreaterThan(dateTimeProvider.Now()) | ||||
|             .WithMessage("Permission to destination Country must not be expired"); | ||||
|  | ||||
|         RuleFor(p => p!.Issuer) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Issuer of permission for destination Country can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Issuer of permission for destination Country can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.IssuerNameLength) | ||||
|             .WithMessage($"Issuer of permission to destination Country length must be less than {ConfigurationConstraints.IssuerNameLength}"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using Domains; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models.Validation; | ||||
|  | ||||
| public class ReentryPermitModelValidator : AbstractValidator<ReentryPermitModel?> | ||||
| { | ||||
|     public ReentryPermitModelValidator(IDateTimeProvider dateTimeProvider) | ||||
|     { | ||||
|         RuleFor(p => p!.Number) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Re-entry permit number can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Re-entry permit number can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.ReentryPermitNumberLength) | ||||
|             .WithMessage($"Re-entry permit number length must be less than {ConfigurationConstraints.ReentryPermitNumberLength}"); | ||||
|  | ||||
|         RuleFor(p => p!.ExpirationDate) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Re-entry permit expiration date can not be empty") | ||||
|             .GreaterThan(dateTimeProvider.Now()) | ||||
|             .WithMessage("Re-entry permit must not be expired"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,89 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using System.Text; | ||||
| using ApplicationLayer.Services.Applicants.Models; | ||||
| using Domains.VisaApplicationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| /// Model of <see cref="VisaApplication" /> with applicant property | ||||
| public class VisaApplicationModel | ||||
| { | ||||
|     /// <inheritdoc cref="VisaApplication.Id" /> | ||||
|     [Required] | ||||
|     public Guid Id { get; set; } | ||||
|  | ||||
|     /// Applicant of application | ||||
|     [Required] | ||||
|     public ApplicantModel Applicant { get; set; } = null!; | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.Status" /> | ||||
|     [Required] | ||||
|     public ApplicationStatus Status { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.ReentryPermit" /> | ||||
|     public ReentryPermitModel? ReentryPermit { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.DestinationCountry" /> | ||||
|     [Required] | ||||
|     public string DestinationCountry { get; set; } = null!; | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.PastVisas" /> | ||||
|     [Required] | ||||
|     public List<PastVisaModel> PastVisas { get; set; } = null!; | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.PermissionToDestCountry" /> | ||||
|     public PermissionToDestCountryModel? PermissionToDestCountry { get; set; } | ||||
|  | ||||
|     [Required] public List<PastVisitModel> PastVisits { get; set; } = null!; | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.VisaCategory" /> | ||||
|     [Required] | ||||
|     public VisaCategory VisaCategory { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.ForGroup" /> | ||||
|     [Required] | ||||
|     public bool ForGroup { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.RequestedNumberOfEntries" /> | ||||
|     [Required] | ||||
|     public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.RequestDate" /> | ||||
|     [Required] | ||||
|     public DateTime RequestDate { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.ValidDaysRequested" /> | ||||
|     [Required] | ||||
|     public int ValidDaysRequested { get; set; } | ||||
|  | ||||
|     public string ForGroupToString() => ForGroup ? "For group" : "Individual"; | ||||
|  | ||||
|     public string PastVisasToString() | ||||
|     { | ||||
|         var stringBuilder = new StringBuilder(); | ||||
|         foreach (var visa in PastVisas) | ||||
|         { | ||||
|             stringBuilder.AppendLine($"{visa.Name} issued at {visa.IssueDate.ToShortDateString()} and valid for {visa.ExpirationDate.ToShortDateString()}"); | ||||
|         } | ||||
|  | ||||
|         return stringBuilder.ToString(); | ||||
|     } | ||||
|  | ||||
|     public string PastVisitsToString() | ||||
|     { | ||||
|         var stringBuilder = new StringBuilder(); | ||||
|         foreach (var visit in PastVisits) | ||||
|         { | ||||
|             stringBuilder.AppendLine($"Visit to {visit.DestinationCountry} started at {visit.StartDate.ToShortDateString()} and ends {visit.EndDate.ToShortDateString()}"); | ||||
|         } | ||||
|  | ||||
|         return stringBuilder.ToString(); | ||||
|     } | ||||
|  | ||||
|     public string PermissionToDestCountryToString() | ||||
|     { | ||||
|         return VisaCategory is VisaCategory.Transit | ||||
|             ? $"Issued by{PermissionToDestCountry!.Issuer}, expires at {PermissionToDestCountry.ExpirationDate.ToShortDateString()}" | ||||
|             : "Non-transit"; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using Domains.VisaApplicationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Models; | ||||
|  | ||||
| /// Model of <see cref="VisaApplication" /> | ||||
| public class VisaApplicationPreview | ||||
| { | ||||
|     /// <inheritdoc cref="VisaApplication.Id" /> | ||||
|     [Required] | ||||
|     public Guid Id { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.Status" /> | ||||
|     [Required] | ||||
|     public ApplicationStatus Status { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.DestinationCountry" /> | ||||
|     [Required] | ||||
|     public string DestinationCountry { get; set; } = null!; | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.VisaCategory" /> | ||||
|     [Required] | ||||
|     public VisaCategory VisaCategory { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.RequestDate" /> | ||||
|     [Required] | ||||
|     public DateTime RequestDate { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VisaApplication.ValidDaysRequested" /> | ||||
|     [Required] | ||||
|     public int ValidDaysRequested { get; set; } | ||||
| } | ||||
| @@ -0,0 +1,7 @@ | ||||
| namespace ApplicationLayer.Services.VisaApplications.NeededServices | ||||
| { | ||||
|     public interface IEntityWriter | ||||
|     { | ||||
|         Task<Stream> WriteEntityToStream(object entity, CancellationToken cancellationToken); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,16 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using Domains.VisaApplicationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.NeededServices; | ||||
|  | ||||
| public interface IVisaApplicationsRepository : IGenericRepository<VisaApplication> | ||||
| { | ||||
|     /// Get applications of one applicant | ||||
|     Task<List<VisaApplication>> GetOfApplicantAsync(Guid applicantId, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Get specific application of specific user | ||||
|     Task<VisaApplication> GetByApplicantAndApplicationIdAsync(Guid applicantId, Guid applicationId, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Returns pending applications for approving authorities | ||||
|     Task<List<VisaApplication>> GetPendingApplicationsAsync(CancellationToken cancellationToken); | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using ApplicationLayer.Services.Applicants.NeededServices; | ||||
| using ApplicationLayer.Services.VisaApplications.Models; | ||||
| using Domains; | ||||
| using Domains.VisaApplicationDomain; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Requests.Validation; | ||||
|  | ||||
| public class VisaApplicationCreateRequestValidator : AbstractValidator<VisaApplicationCreateRequest> | ||||
| { | ||||
|     public VisaApplicationCreateRequestValidator( | ||||
|         IValidator<ReentryPermitModel?> reentryPermitModelValidator, | ||||
|         IValidator<PastVisaModel> pastVisaModelValidator, | ||||
|         IValidator<PermissionToDestCountryModel?> permissionToDestCountryModelValidator, | ||||
|         IValidator<PastVisitModel> pastVisitModelValidator, | ||||
|         IApplicantsRepository applicants, | ||||
|         IUserIdProvider userIdProvider) | ||||
|     { | ||||
|         RuleFor(r => r.PermissionToDestCountry) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("For transit you must provide permission to destination country") | ||||
|             .SetValidator(permissionToDestCountryModelValidator) | ||||
|             .When(r => r.VisaCategory is VisaCategory.Transit); | ||||
|  | ||||
|         RuleFor(r => r.ReentryPermit) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Non-residents must provide re-entry permission") | ||||
|             .SetValidator(reentryPermitModelValidator) | ||||
|             .WhenAsync(async (_, ct) => | ||||
|                 await applicants.IsApplicantNonResidentByUserId(userIdProvider.GetUserId(), ct)); | ||||
|  | ||||
|         RuleFor(r => r.DestinationCountry) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Destination country can not be empty"); | ||||
|  | ||||
|         RuleFor(r => r.VisaCategory) | ||||
|             .IsInEnum(); | ||||
|  | ||||
|         RuleFor(r => r.RequestedNumberOfEntries) | ||||
|             .IsInEnum(); | ||||
|  | ||||
|         RuleFor(r => r.ValidDaysRequested) | ||||
|             .GreaterThan(0) | ||||
|             .WithMessage($"Valid days requested should be positive number and less than {ConfigurationConstraints.MaxValidDays}") | ||||
|             .LessThanOrEqualTo(ConfigurationConstraints.MaxValidDays) | ||||
|             .WithMessage($"Valid days requested must be less than or equal to {ConfigurationConstraints.MaxValidDays}"); | ||||
|  | ||||
|         RuleForEach(r => r.PastVisas) | ||||
|             .SetValidator(pastVisaModelValidator); | ||||
|  | ||||
|         RuleForEach(r => r.PastVisits) | ||||
|             .SetValidator(pastVisitModelValidator); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,37 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using ApplicationLayer.Services.VisaApplications.Models; | ||||
| using Domains; | ||||
| using Domains.VisaApplicationDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Services.VisaApplications.Requests; | ||||
|  | ||||
| /// Model of visa request from user | ||||
| public class VisaApplicationCreateRequest | ||||
| { | ||||
|     public ReentryPermitModel? ReentryPermit { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     [MaxLength(ConfigurationConstraints.CountryNameLength)] | ||||
|     public string DestinationCountry { get; set; } = null!; | ||||
|  | ||||
|     [Required] | ||||
|     public VisaCategory VisaCategory { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     public bool IsForGroup { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     [Range(0, ConfigurationConstraints.MaxValidDays)] | ||||
|     public int ValidDaysRequested { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     public PastVisaModel[] PastVisas { get; set; } = null!; | ||||
|  | ||||
|     public PermissionToDestCountryModel? PermissionToDestCountry { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     public PastVisitModel[] PastVisits { get; set; } = null!; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user