Merge pull request #6 from prtsie/visa-applications-controller
Visa applications controller
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
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!;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using Domains.ApplicantDomain;
|
||||||
|
|
||||||
|
namespace ApplicationLayer.Services.Applicants.Models
|
||||||
|
{
|
||||||
|
/// Model of <see cref="Applicant"/>
|
||||||
|
public class ApplicantModel
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="Applicant.Name"/>
|
||||||
|
public Name Name { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.Passport"/>
|
||||||
|
public Passport Passport { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.BirthDate"/>
|
||||||
|
public DateTime BirthDate { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.CountryOfBirth"/>
|
||||||
|
public string CountryOfBirth { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.CityOfBirth"/>
|
||||||
|
public string CityOfBirth { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.Citizenship"/>
|
||||||
|
public string Citizenship { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.CitizenshipByBirth"/>
|
||||||
|
public string CitizenshipByBirth { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.Gender"/>
|
||||||
|
public Gender Gender { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.MaritalStatus"/>
|
||||||
|
public MaritalStatus MaritalStatus { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.FatherName"/>
|
||||||
|
public Name FatherName { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.MotherName"/>
|
||||||
|
public Name MotherName { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.JobTitle"/>
|
||||||
|
public string JobTitle { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.PlaceOfWork"/>
|
||||||
|
public PlaceOfWork PlaceOfWork { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Applicant.IsNonResident"/>
|
||||||
|
public bool IsNonResident { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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!;
|
|
||||||
}
|
|
||||||
@@ -5,5 +5,5 @@ namespace ApplicationLayer.Services.GeneralExceptions;
|
|||||||
/// Exception to throw when entity not found
|
/// Exception to throw when entity not found
|
||||||
/// <param name="id">Identifier of entity</param>
|
/// <param name="id">Identifier of entity</param>
|
||||||
/// <typeparam name="T">Type of entity</typeparam>
|
/// <typeparam name="T">Type of entity</typeparam>
|
||||||
public class EntityNotFoundByIdException<T>(Guid id) : EntityNotFoundException<T>($"{typeof(T).Name} with id {id} not found.")
|
public class EntityNotFoundByIdException<T>(Guid id) : EntityNotFoundException($"{typeof(T).Name} with id {id} not found.")
|
||||||
where T : class, IEntity;
|
where T : class, IEntity;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using ApplicationLayer.GeneralExceptions;
|
using ApplicationLayer.GeneralExceptions;
|
||||||
using Domains;
|
|
||||||
|
|
||||||
namespace ApplicationLayer.Services.GeneralExceptions;
|
namespace ApplicationLayer.Services.GeneralExceptions;
|
||||||
|
|
||||||
/// Exception to throw when entity not found
|
/// Exception to throw when entity not found
|
||||||
/// <typeparam name="T">Not found entity type</typeparam>
|
public class EntityNotFoundException(string message) : ApiException(message);
|
||||||
public class EntityNotFoundException<T>(string message) : ApiException(message)
|
|
||||||
where T : class, IEntity;
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using ApplicationLayer.GeneralExceptions;
|
||||||
|
|
||||||
|
namespace ApplicationLayer.Services.VisaApplications.Exceptions
|
||||||
|
{
|
||||||
|
public class ApplicationAlreadyProcessedException() : ApiException("This application already processed or closed by applicant.");
|
||||||
|
}
|
||||||
@@ -1,13 +1,21 @@
|
|||||||
using ApplicationLayer.Services.VisaApplications.Models;
|
using ApplicationLayer.Services.VisaApplications.Models;
|
||||||
using ApplicationLayer.Services.VisaApplications.Requests;
|
using ApplicationLayer.Services.VisaApplications.Requests;
|
||||||
using Domains.VisaApplicationDomain;
|
|
||||||
|
|
||||||
namespace ApplicationLayer.Services.VisaApplications.Handlers;
|
namespace ApplicationLayer.Services.VisaApplications.Handlers;
|
||||||
|
|
||||||
public interface IVisaApplicationRequestsHandler
|
public interface IVisaApplicationRequestsHandler
|
||||||
{
|
{
|
||||||
Task<List<VisaApplication>> Get(CancellationToken cancellationToken);
|
/// Returns all applications for approving authorities
|
||||||
Task<List<VisaApplicationModelForApplicant>> GetForApplicant(Guid userId, CancellationToken cancellationToken);
|
Task<List<VisaApplicationModelForAuthority>> GetAllAsync(CancellationToken cancellationToken);
|
||||||
|
|
||||||
Task HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken);
|
/// Returns all applications of one applicant
|
||||||
|
Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(Guid userId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// Creates application for applicant with specific user identifier
|
||||||
|
Task HandleCreateRequestAsync(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// Sets application status to closed
|
||||||
|
Task HandleCloseRequestAsync(Guid userId, Guid applicationId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task SetApplicationStatusFromAuthorityAsync(Guid applicationId, AuthorityRequestStatuses status, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using ApplicationLayer.InfrastructureServicesInterfaces;
|
using ApplicationLayer.InfrastructureServicesInterfaces;
|
||||||
|
using ApplicationLayer.Services.Applicants.Models;
|
||||||
using ApplicationLayer.Services.Applicants.NeededServices;
|
using ApplicationLayer.Services.Applicants.NeededServices;
|
||||||
|
using ApplicationLayer.Services.VisaApplications.Exceptions;
|
||||||
using ApplicationLayer.Services.VisaApplications.Models;
|
using ApplicationLayer.Services.VisaApplications.Models;
|
||||||
using ApplicationLayer.Services.VisaApplications.NeededServices;
|
using ApplicationLayer.Services.VisaApplications.NeededServices;
|
||||||
using ApplicationLayer.Services.VisaApplications.Requests;
|
using ApplicationLayer.Services.VisaApplications.Requests;
|
||||||
@@ -13,9 +15,57 @@ public class VisaApplicationRequestsHandler(
|
|||||||
IApplicantsRepository applicants,
|
IApplicantsRepository applicants,
|
||||||
IUnitOfWork unitOfWork) : IVisaApplicationRequestsHandler
|
IUnitOfWork unitOfWork) : IVisaApplicationRequestsHandler
|
||||||
{
|
{
|
||||||
public async Task<List<VisaApplication>> Get(CancellationToken cancellationToken) => await applications.GetAllAsync(cancellationToken);
|
async Task<List<VisaApplicationModelForAuthority>> IVisaApplicationRequestsHandler.GetAllAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var applicationsList = await applications.GetAllAsync(cancellationToken);
|
||||||
|
|
||||||
public async Task<List<VisaApplicationModelForApplicant>> GetForApplicant(Guid userId, CancellationToken cancellationToken)
|
//todo mapper
|
||||||
|
var applicationModels = applicationsList
|
||||||
|
.Select(a => MapVisaApplicationToModelForAuthorities(a, cancellationToken).Result)
|
||||||
|
.ToList();
|
||||||
|
return applicationModels;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<VisaApplicationModelForAuthority> MapVisaApplicationToModelForAuthorities(VisaApplication visaApplication,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var applicant = await applicants.GetByIdAsync(visaApplication.ApplicantId, cancellationToken);
|
||||||
|
var applicantModel = new ApplicantModel
|
||||||
|
{
|
||||||
|
Citizenship = applicant.Citizenship,
|
||||||
|
Gender = applicant.Gender,
|
||||||
|
Name = applicant.Name,
|
||||||
|
Passport = applicant.Passport,
|
||||||
|
BirthDate = applicant.BirthDate,
|
||||||
|
FatherName = applicant.FatherName,
|
||||||
|
JobTitle = applicant.JobTitle,
|
||||||
|
MaritalStatus = applicant.MaritalStatus,
|
||||||
|
MotherName = applicant.MotherName,
|
||||||
|
CitizenshipByBirth = applicant.CitizenshipByBirth,
|
||||||
|
CityOfBirth = applicant.CityOfBirth,
|
||||||
|
CountryOfBirth = applicant.CountryOfBirth,
|
||||||
|
IsNonResident = applicant.IsNonResident,
|
||||||
|
PlaceOfWork = applicant.PlaceOfWork,
|
||||||
|
};
|
||||||
|
return new VisaApplicationModelForAuthority
|
||||||
|
{
|
||||||
|
PastVisits = visaApplication.PastVisits,
|
||||||
|
ReentryPermit = visaApplication.ReentryPermit,
|
||||||
|
VisaCategory = visaApplication.VisaCategory,
|
||||||
|
PermissionToDestCountry = visaApplication.PermissionToDestCountry,
|
||||||
|
DestinationCountry = visaApplication.DestinationCountry,
|
||||||
|
PastVisas = visaApplication.PastVisas,
|
||||||
|
RequestDate = visaApplication.RequestDate,
|
||||||
|
ValidDaysRequested = visaApplication.ValidDaysRequested,
|
||||||
|
RequestedNumberOfEntries = visaApplication.RequestedNumberOfEntries,
|
||||||
|
ForGroup = visaApplication.ForGroup,
|
||||||
|
Applicant = applicantModel,
|
||||||
|
Id = visaApplication.Id,
|
||||||
|
Status = visaApplication.Status
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(Guid userId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//todo mapper
|
//todo mapper
|
||||||
var applicantId = await applicants.GetApplicantIdByUserId(userId, cancellationToken);
|
var applicantId = await applicants.GetApplicantIdByUserId(userId, cancellationToken);
|
||||||
@@ -31,11 +81,14 @@ public class VisaApplicationRequestsHandler(
|
|||||||
ForGroup = va.ForGroup,
|
ForGroup = va.ForGroup,
|
||||||
PastVisas = va.PastVisas,
|
PastVisas = va.PastVisas,
|
||||||
RequestDate = va.RequestDate,
|
RequestDate = va.RequestDate,
|
||||||
PastVisits = va.PastVisits
|
PastVisits = va.PastVisits,
|
||||||
}).ToList();
|
Id = va.Id,
|
||||||
|
Status = va.Status
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken)
|
public async Task HandleCreateRequestAsync(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//TODO mapper
|
//TODO mapper
|
||||||
|
|
||||||
@@ -53,11 +106,49 @@ public class VisaApplicationRequestsHandler(
|
|||||||
PastVisas = request.PastVisas.ToList(),
|
PastVisas = request.PastVisas.ToList(),
|
||||||
PastVisits = request.PastVisits.ToList(),
|
PastVisits = request.PastVisits.ToList(),
|
||||||
ForGroup = request.IsForGroup,
|
ForGroup = request.IsForGroup,
|
||||||
RequestDate = DateTime.Today
|
RequestDate = DateTime.Today,
|
||||||
|
Status = ApplicationStatus.Pending
|
||||||
};
|
};
|
||||||
|
|
||||||
await applications.AddAsync(visaApplication, cancellationToken);
|
await applications.AddAsync(visaApplication, cancellationToken);
|
||||||
|
|
||||||
await unitOfWork.SaveAsync(cancellationToken);
|
await unitOfWork.SaveAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async Task IVisaApplicationRequestsHandler.HandleCloseRequestAsync(Guid userId, Guid applicationId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var applicantId = await applicants.GetApplicantIdByUserId(userId, cancellationToken);
|
||||||
|
var application = await applications.GetByApplicantAndApplicationIdAsync(applicantId, applicationId, cancellationToken);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
//todo refactor exceptions
|
||||||
|
throw new ApplicationAlreadyProcessedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo mapper
|
||||||
|
ApplicationStatus 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ApplicationLayer.Services.VisaApplications.Models
|
||||||
|
{
|
||||||
|
public enum AuthorityRequestStatuses
|
||||||
|
{
|
||||||
|
Approved,
|
||||||
|
Rejected
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,11 @@ namespace ApplicationLayer.Services.VisaApplications.Models
|
|||||||
/// Model of <see cref="VisaApplication"/>
|
/// Model of <see cref="VisaApplication"/>
|
||||||
public class VisaApplicationModelForApplicant
|
public class VisaApplicationModelForApplicant
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc cref="VisaApplication.Id"/>
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.Status"/>
|
||||||
|
public ApplicationStatus Status { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="VisaApplication.ReentryPermit"/>
|
/// <inheritdoc cref="VisaApplication.ReentryPermit"/>
|
||||||
public ReentryPermit? ReentryPermit { get; set; }
|
public ReentryPermit? ReentryPermit { get; set; }
|
||||||
@@ -18,6 +23,7 @@ namespace ApplicationLayer.Services.VisaApplications.Models
|
|||||||
/// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/>
|
/// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/>
|
||||||
public PermissionToDestCountry? PermissionToDestCountry { get; set; }
|
public PermissionToDestCountry? PermissionToDestCountry { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.PastVisits"/>
|
||||||
public List<PastVisit> PastVisits { get; set; } = null!;
|
public List<PastVisit> PastVisits { get; set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc cref="VisaApplication.VisaCategory"/>
|
/// <inheritdoc cref="VisaApplication.VisaCategory"/>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using ApplicationLayer.Services.Applicants.Models;
|
||||||
|
using Domains.VisaApplicationDomain;
|
||||||
|
|
||||||
|
namespace ApplicationLayer.Services.VisaApplications.Models
|
||||||
|
{
|
||||||
|
/// Model of <see cref="VisaApplication"/> with applicant property
|
||||||
|
public class VisaApplicationModelForAuthority
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="VisaApplication.Id"/>
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
/// Applicant of application
|
||||||
|
public ApplicantModel Applicant { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.Status"/>
|
||||||
|
public ApplicationStatus Status { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.ReentryPermit"/>
|
||||||
|
public ReentryPermit? ReentryPermit { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.DestinationCountry"/>
|
||||||
|
public string DestinationCountry { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.PastVisas"/>
|
||||||
|
public List<PastVisa> PastVisas { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/>
|
||||||
|
public PermissionToDestCountry? PermissionToDestCountry { get; set; }
|
||||||
|
|
||||||
|
public List<PastVisit> PastVisits { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.VisaCategory"/>
|
||||||
|
public VisaCategory VisaCategory { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.ForGroup"/>
|
||||||
|
public bool ForGroup { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.RequestedNumberOfEntries"/>
|
||||||
|
public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.RequestDate"/>
|
||||||
|
public DateTime RequestDate { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VisaApplication.ValidDaysRequested"/>
|
||||||
|
public int ValidDaysRequested { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,4 +7,7 @@ public interface IVisaApplicationsRepository : IGenericRepository<VisaApplicatio
|
|||||||
{
|
{
|
||||||
/// Get applications of one applicant
|
/// Get applications of one applicant
|
||||||
Task<List<VisaApplication>> GetOfApplicantAsync(Guid applicantId, CancellationToken cancellationToken);
|
Task<List<VisaApplication>> GetOfApplicantAsync(Guid applicantId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// Get specific application of specific user
|
||||||
|
Task<VisaApplication> GetByApplicantAndApplicationIdAsync(Guid applicantId, Guid applicationId, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Domains.VisaApplicationDomain
|
||||||
|
{
|
||||||
|
public enum ApplicationStatus
|
||||||
|
{
|
||||||
|
/// Waits for approve
|
||||||
|
Pending,
|
||||||
|
Approved,
|
||||||
|
Rejected,
|
||||||
|
/// Closed by applicant
|
||||||
|
Closed
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,9 @@ public class VisaApplication : IEntity
|
|||||||
/// Identifier of the <see cref="Applicant"/>
|
/// Identifier of the <see cref="Applicant"/>
|
||||||
public Guid ApplicantId { get; set; }
|
public Guid ApplicantId { get; set; }
|
||||||
|
|
||||||
|
/// Status of application
|
||||||
|
public ApplicationStatus Status { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Domains.VisaApplicationDomain.ReentryPermit"/>
|
/// <inheritdoc cref="Domains.VisaApplicationDomain.ReentryPermit"/>
|
||||||
/// <remarks>always null if <see cref="Applicant"/> is not a non-resident</remarks>
|
/// <remarks>always null if <see cref="Applicant"/> is not a non-resident</remarks>
|
||||||
public ReentryPermit? ReentryPermit { get; set; }
|
public ReentryPermit? ReentryPermit { get; set; }
|
||||||
@@ -18,9 +21,7 @@ public class VisaApplication : IEntity
|
|||||||
/// Country that <see cref="Applicant"/> wants to visit
|
/// Country that <see cref="Applicant"/> wants to visit
|
||||||
public string DestinationCountry { get; set; } = null!;
|
public string DestinationCountry { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of <see cref="PastVisa"/> that applicant had before
|
/// List of <see cref="PastVisa"/> that applicant had before
|
||||||
/// </summary>
|
|
||||||
public List<PastVisa> PastVisas { get; set; } = null!;
|
public List<PastVisa> PastVisas { get; set; } = null!;
|
||||||
|
|
||||||
/// Permission to enter the destination country of <see cref="Applicant"/>
|
/// Permission to enter the destination country of <see cref="Applicant"/>
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter w
|
|||||||
async Task<Applicant> IApplicantsRepository.FindByUserIdAsync(Guid userId, CancellationToken cancellationToken)
|
async Task<Applicant> IApplicantsRepository.FindByUserIdAsync(Guid userId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = await LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken);
|
var result = await LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken);
|
||||||
return result ?? throw new ApplicantNotFoundByUserIdException(userId);
|
return result ?? throw new ApplicantNotFoundByUserIdException();
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<Guid> IApplicantsRepository.GetApplicantIdByUserId(Guid userId, CancellationToken cancellationToken)
|
async Task<Guid> IApplicantsRepository.GetApplicantIdByUserId(Guid userId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = await base.LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken);
|
var result = await base.LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken);
|
||||||
return result?.Id ?? throw new ApplicantNotFoundByUserIdException(userId);
|
return result?.Id ?? throw new ApplicantNotFoundByUserIdException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using ApplicationLayer.Services.GeneralExceptions;
|
using ApplicationLayer.Services.GeneralExceptions;
|
||||||
using Domains.ApplicantDomain;
|
|
||||||
|
|
||||||
namespace Infrastructure.Database.Applicants.Repositories.Exceptions
|
namespace Infrastructure.Database.Applicants.Repositories.Exceptions
|
||||||
{
|
{
|
||||||
public class ApplicantNotFoundByUserIdException(Guid id) : EntityNotFoundException<Applicant>("Applicant not found.")
|
public class ApplicantNotFoundByUserIdException() : EntityNotFoundException("Applicant not found.");
|
||||||
{
|
|
||||||
public Guid UserId { get; private set; } = id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using ApplicationLayer.Services.GeneralExceptions;
|
||||||
|
|
||||||
|
namespace Infrastructure.Database.VisaApplications.Repositories.Exceptions
|
||||||
|
{
|
||||||
|
public class ApplicationNotFoundByApplicantAndApplicationIdException(Guid applicationId)
|
||||||
|
: EntityNotFoundException($"Application with id {applicationId} not found for authenticated user");
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using ApplicationLayer.Services.VisaApplications.NeededServices;
|
using ApplicationLayer.Services.VisaApplications.NeededServices;
|
||||||
using Domains.VisaApplicationDomain;
|
using Domains.VisaApplicationDomain;
|
||||||
using Infrastructure.Database.Generic;
|
using Infrastructure.Database.Generic;
|
||||||
|
using Infrastructure.Database.VisaApplications.Repositories.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Infrastructure.Database.VisaApplications.Repositories;
|
namespace Infrastructure.Database.VisaApplications.Repositories;
|
||||||
@@ -16,4 +17,14 @@ public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWr
|
|||||||
|
|
||||||
async Task<List<VisaApplication>> IVisaApplicationsRepository.GetOfApplicantAsync(Guid applicantId, CancellationToken cancellationToken)
|
async Task<List<VisaApplication>> IVisaApplicationsRepository.GetOfApplicantAsync(Guid applicantId, CancellationToken cancellationToken)
|
||||||
=> await LoadDomain().Where(va => va.ApplicantId == applicantId).ToListAsync(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace SchengenVisaApi.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
[Route("authority")]
|
[Route("authorities")]
|
||||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||||
public async Task<IActionResult> RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken)
|
public async Task<IActionResult> RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace SchengenVisaApi.Controllers
|
|||||||
[ProducesResponseType<List<User>>(StatusCodes.Status200OK)]
|
[ProducesResponseType<List<User>>(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
[Route("authority")]
|
[Route("authorities")]
|
||||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||||
public async Task<IActionResult> GetAuthorityAccounts(CancellationToken cancellationToken)
|
public async Task<IActionResult> GetAuthorityAccounts(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@@ -75,8 +75,9 @@ namespace SchengenVisaApi.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
[Route("authority/{authorityAccountId:guid}")]
|
[Route("authorities/{authorityAccountId:guid}")]
|
||||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||||
|
//todo replace args with ChangeAuthorityAuthDataRequest or something
|
||||||
public async Task<IActionResult> ChangeAuthorityAuthData(Guid authorityAccountId, RegisterRequest authData, CancellationToken cancellationToken)
|
public async Task<IActionResult> ChangeAuthorityAuthData(Guid authorityAccountId, RegisterRequest authData, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await authorityService.ChangeAccountAuthDataAsync(authorityAccountId, authData, cancellationToken);
|
await authorityService.ChangeAccountAuthDataAsync(authorityAccountId, authData, cancellationToken);
|
||||||
@@ -90,7 +91,7 @@ namespace SchengenVisaApi.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
[Route("authority/{authorityAccountId:guid}")]
|
[Route("authorities/{authorityAccountId:guid}")]
|
||||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||||
public async Task<IActionResult> RemoveAuthorityAccount(Guid authorityAccountId, CancellationToken cancellationToken)
|
public async Task<IActionResult> RemoveAuthorityAccount(Guid authorityAccountId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Security.Claims;
|
|
||||||
using ApplicationLayer.Services.VisaApplications.Handlers;
|
using ApplicationLayer.Services.VisaApplications.Handlers;
|
||||||
using ApplicationLayer.Services.VisaApplications.Models;
|
using ApplicationLayer.Services.VisaApplications.Models;
|
||||||
using ApplicationLayer.Services.VisaApplications.Requests;
|
using ApplicationLayer.Services.VisaApplications.Requests;
|
||||||
using Domains.VisaApplicationDomain;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using SchengenVisaApi.Common;
|
using SchengenVisaApi.Common;
|
||||||
@@ -11,21 +9,19 @@ namespace SchengenVisaApi.Controllers;
|
|||||||
|
|
||||||
/// <summary> Controller for <see cref="Domains.VisaApplicationDomain"/> </summary>
|
/// <summary> Controller for <see cref="Domains.VisaApplicationDomain"/> </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("visaApplication")]
|
[Route("visaApplications")]
|
||||||
public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : VisaApiControllerBase
|
public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : VisaApiControllerBase
|
||||||
{
|
{
|
||||||
//todo should return only pending applications
|
|
||||||
//todo should return model
|
|
||||||
/// <summary> Returns all applications from DB </summary>
|
/// <summary> Returns all applications from DB </summary>
|
||||||
/// <remarks> Accessible only for approving authorities </remarks>
|
/// <remarks> Accessible only for approving authorities </remarks>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType<List<VisaApplication>>(StatusCodes.Status200OK)]
|
[ProducesResponseType<List<VisaApplicationModelForAuthority>>(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
[Authorize(policy: PolicyConstants.ApprovingAuthorityPolicy)]
|
[Authorize(policy: PolicyConstants.ApprovingAuthorityPolicy)]
|
||||||
public async Task<IActionResult> Get(CancellationToken cancellationToken)
|
public async Task<IActionResult> Get(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = await visaApplicationRequestsHandler.Get(cancellationToken);
|
var result = await visaApplicationRequestsHandler.GetAllAsync(cancellationToken);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +37,7 @@ public class VisaApplicationController(IVisaApplicationRequestsHandler visaAppli
|
|||||||
public async Task<IActionResult> GetForApplicant(CancellationToken cancellationToken)
|
public async Task<IActionResult> GetForApplicant(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
var result = await visaApplicationRequestsHandler.GetForApplicant(userId, cancellationToken);
|
var result = await visaApplicationRequestsHandler.GetForApplicantAsync(userId, cancellationToken);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +52,38 @@ public class VisaApplicationController(IVisaApplicationRequestsHandler visaAppli
|
|||||||
public async Task<IActionResult> Create(VisaApplicationCreateRequest request, CancellationToken cancellationToken)
|
public async Task<IActionResult> Create(VisaApplicationCreateRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
await visaApplicationRequestsHandler.HandleCreateRequest(userId, request, cancellationToken);
|
await visaApplicationRequestsHandler.HandleCreateRequestAsync(userId, request, cancellationToken);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Sets application status to closed</summary>
|
||||||
|
/// <remarks> Accessible only for applicant</remarks>
|
||||||
|
[HttpPatch]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Authorize(policy: PolicyConstants.ApplicantPolicy)]
|
||||||
|
[Route("{applicationId:guid}")]
|
||||||
|
public async Task<IActionResult> CloseApplication(Guid applicationId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var userId = GetUserId();
|
||||||
|
await visaApplicationRequestsHandler.HandleCloseRequestAsync(userId, applicationId, cancellationToken);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Allows approving authorities approve or reject applications</summary>
|
||||||
|
/// <remarks> Accessible only for authorities</remarks>
|
||||||
|
[HttpPatch]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Authorize(policy: PolicyConstants.ApprovingAuthorityPolicy)]
|
||||||
|
[Route("approving/{applicationId:guid}")]
|
||||||
|
public async Task<IActionResult> SetStatusFromAuthority(Guid applicationId, AuthorityRequestStatuses status, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await visaApplicationRequestsHandler.SetApplicationStatusFromAuthorityAsync(applicationId, status, cancellationToken);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using ApplicationLayer.GeneralExceptions;
|
using ApplicationLayer.GeneralExceptions;
|
||||||
using ApplicationLayer.Services.AuthServices.LoginService.Exceptions;
|
using ApplicationLayer.Services.AuthServices.LoginService.Exceptions;
|
||||||
using ApplicationLayer.Services.GeneralExceptions;
|
using ApplicationLayer.Services.GeneralExceptions;
|
||||||
using Domains;
|
using ApplicationLayer.Services.VisaApplications.Exceptions;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ namespace SchengenVisaApi.ExceptionFilters
|
|||||||
problemDetails.Detail = exception.Message;
|
problemDetails.Detail = exception.Message;
|
||||||
switch (exception)
|
switch (exception)
|
||||||
{
|
{
|
||||||
case EntityNotFoundException<IEntity>:
|
case EntityNotFoundException:
|
||||||
problemDetails.Status = StatusCodes.Status404NotFound;
|
problemDetails.Status = StatusCodes.Status404NotFound;
|
||||||
problemDetails.Title = "Requested entity not found";
|
problemDetails.Title = "Requested entity not found";
|
||||||
problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4";
|
problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4";
|
||||||
@@ -36,6 +36,11 @@ namespace SchengenVisaApi.ExceptionFilters
|
|||||||
problemDetails.Title = "Already exists";
|
problemDetails.Title = "Already exists";
|
||||||
problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8";
|
problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8";
|
||||||
break;
|
break;
|
||||||
|
case ApplicationAlreadyProcessedException:
|
||||||
|
problemDetails.Status = StatusCodes.Status409Conflict;
|
||||||
|
problemDetails.Title = "Already processed";
|
||||||
|
problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
problemDetails.Status = StatusCodes.Status400BadRequest;
|
problemDetails.Status = StatusCodes.Status400BadRequest;
|
||||||
problemDetails.Title = "Bad request";
|
problemDetails.Title = "Bad request";
|
||||||
|
|||||||
Reference in New Issue
Block a user