Changed exceptions, added action for closing applications by applicant
This commit is contained in:
		| @@ -14,4 +14,8 @@ | ||||
|       <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0-preview.7.24405.7" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|       <Folder Include="Services\VisaApplications\Handlers\Exceptions\" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
|   | ||||
| @@ -5,5 +5,5 @@ namespace ApplicationLayer.Services.GeneralExceptions; | ||||
| /// Exception to throw when entity not found | ||||
| /// <param name="id">Identifier of entity</param> | ||||
| /// <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; | ||||
|   | ||||
| @@ -1,9 +1,6 @@ | ||||
| using ApplicationLayer.GeneralExceptions; | ||||
| using Domains; | ||||
|  | ||||
| namespace ApplicationLayer.Services.GeneralExceptions; | ||||
|  | ||||
| /// Exception to throw when entity not found | ||||
| /// <typeparam name="T">Not found entity type</typeparam> | ||||
| public class EntityNotFoundException<T>(string message) : ApiException(message) | ||||
|     where T : class, IEntity; | ||||
| public class EntityNotFoundException(string message) : ApiException(message); | ||||
|   | ||||
| @@ -14,4 +14,7 @@ public interface IVisaApplicationRequestsHandler | ||||
|  | ||||
|     /// Creates application for applicant with specific user identifier | ||||
|     Task HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken); | ||||
|  | ||||
|     /// Sets application status to closed | ||||
|     Task HandleCloseRequest(Guid userId, Guid applicationId, CancellationToken cancellationToken); | ||||
| } | ||||
|   | ||||
| @@ -114,4 +114,15 @@ public class VisaApplicationRequestsHandler( | ||||
|  | ||||
|         await unitOfWork.SaveAsync(cancellationToken); | ||||
|     } | ||||
|  | ||||
|     async Task IVisaApplicationRequestsHandler.HandleCloseRequest(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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -7,4 +7,7 @@ public interface IVisaApplicationsRepository : IGenericRepository<VisaApplicatio | ||||
| { | ||||
|     /// 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); | ||||
| } | ||||
|   | ||||
| @@ -21,12 +21,12 @@ public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter w | ||||
|     async Task<Applicant> IApplicantsRepository.FindByUserIdAsync(Guid userId, CancellationToken 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) | ||||
|     { | ||||
|         var result = await base.LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken); | ||||
|         return result?.Id ?? throw new ApplicantNotFoundByUserIdException(userId); | ||||
|         return result?.Id ?? throw new ApplicantNotFoundByUserIdException(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,8 +3,5 @@ using Domains.ApplicantDomain; | ||||
|  | ||||
| namespace Infrastructure.Database.Applicants.Repositories.Exceptions | ||||
| { | ||||
|     public class ApplicantNotFoundByUserIdException(Guid id) : EntityNotFoundException<Applicant>("Applicant not found.") | ||||
|     { | ||||
|         public Guid UserId { get; private set; } = id; | ||||
|     } | ||||
|     public class ApplicantNotFoundByUserIdException() : EntityNotFoundException("Applicant not found."); | ||||
| } | ||||
|   | ||||
| @@ -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 Domains.VisaApplicationDomain; | ||||
| using Infrastructure.Database.Generic; | ||||
| using Infrastructure.Database.VisaApplications.Repositories.Exceptions; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| 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) | ||||
|         => 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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -57,4 +57,20 @@ public class VisaApplicationController(IVisaApplicationRequestsHandler visaAppli | ||||
|         await visaApplicationRequestsHandler.HandleCreateRequest(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.HandleCloseRequest(userId, applicationId, cancellationToken); | ||||
|         return Ok(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,7 +21,7 @@ namespace SchengenVisaApi.ExceptionFilters | ||||
|                 problemDetails.Detail = exception.Message; | ||||
|                 switch (exception) | ||||
|                 { | ||||
|                     case EntityNotFoundException<IEntity>: | ||||
|                     case EntityNotFoundException: | ||||
|                         problemDetails.Status = StatusCodes.Status404NotFound; | ||||
|                         problemDetails.Title = "Requested entity not found"; | ||||
|                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user