@@ -6,7 +6,7 @@ namespace ApplicationLayer.Services.VisaApplications.Handlers;
|
||||
public interface IVisaApplicationRequestsHandler
|
||||
{
|
||||
/// Returns all applications for approving authorities
|
||||
Task<List<VisaApplicationModelForAuthority>> GetAllAsync(CancellationToken cancellationToken);
|
||||
Task<List<VisaApplicationModelForAuthority>> GetPendingAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// Returns all applications of one applicant
|
||||
Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(CancellationToken cancellationToken);
|
||||
|
||||
@@ -19,9 +19,9 @@ public class VisaApplicationRequestsHandler(
|
||||
IDateTimeProvider dateTimeProvider,
|
||||
IUserIdProvider userIdProvider) : IVisaApplicationRequestsHandler
|
||||
{
|
||||
async Task<List<VisaApplicationModelForAuthority>> IVisaApplicationRequestsHandler.GetAllAsync(CancellationToken cancellationToken)
|
||||
async Task<List<VisaApplicationModelForAuthority>> IVisaApplicationRequestsHandler.GetPendingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var applicationsList = await applications.GetAllAsync(cancellationToken);
|
||||
var applicationsList = await applications.GetPendingApplicationsAsync(cancellationToken);
|
||||
|
||||
var applicationModels = applicationsList
|
||||
.Select(a => MapVisaApplicationToModelForAuthorities(a, cancellationToken).Result)
|
||||
|
||||
@@ -10,4 +10,7 @@ public interface IVisaApplicationsRepository : IGenericRepository<VisaApplicatio
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
@@ -27,4 +27,10 @@ public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWr
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace SchengenVisaApi.Common;
|
||||
|
||||
/// Adds auth for swagger
|
||||
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
|
||||
{
|
||||
void IConfigureOptions<SwaggerGenOptions>.Configure(SwaggerGenOptions options)
|
||||
{
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Provide a JWT-token.",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.Http,
|
||||
BearerFormat = "JWT",
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,11 @@ public class UsersController(
|
||||
IValidator<RegisterApplicantRequest> registerApplicantRequestValidator,
|
||||
IValidator<AuthData> authDataValidator) : ControllerBase
|
||||
{
|
||||
/// <summary> Adds applicant with user account to DB </summary>
|
||||
[HttpPost]
|
||||
/// <summary> Adds applicant with user account </summary>
|
||||
[HttpPost("register")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[Route("register")]
|
||||
public async Task<IActionResult> Register(RegisterApplicantRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
await registerApplicantRequestValidator.ValidateAndThrowAsync(request, cancellationToken);
|
||||
@@ -36,15 +35,14 @@ public class UsersController(
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary> Adds approving authority with user account to DB </summary>
|
||||
/// <summary> Adds approving authority with user account </summary>
|
||||
///<remarks> Accessible only for admins </remarks>
|
||||
[HttpPost]
|
||||
[HttpPost("authorities")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[Route("authorities")]
|
||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||
public async Task<IActionResult> RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -55,10 +53,9 @@ public class UsersController(
|
||||
}
|
||||
|
||||
/// <summary> Returns JWT-token for authentication </summary>
|
||||
[HttpGet]
|
||||
[HttpGet("login")]
|
||||
[ProducesResponseType<string>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[Route("login")]
|
||||
public async Task<IActionResult> Login(string email, string password, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await loginService.LoginAsync(email, password, cancellationToken);
|
||||
@@ -67,11 +64,10 @@ public class UsersController(
|
||||
|
||||
/// <summary> Returns list of authority accounts </summary>
|
||||
/// <remarks> Accessible only for admins </remarks>
|
||||
[HttpGet]
|
||||
[HttpGet("authorities")]
|
||||
[ProducesResponseType<List<User>>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[Route("authorities")]
|
||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||
public async Task<IActionResult> GetAuthorityAccounts(CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -81,13 +77,12 @@ public class UsersController(
|
||||
|
||||
/// <summary> Changes authority's account authentication data </summary>
|
||||
/// <remarks> Accessible only for admins </remarks>
|
||||
[HttpPut]
|
||||
[HttpPut("authorities/{authorityAccountId:guid}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[Route("authorities/{authorityAccountId:guid}")]
|
||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||
public async Task<IActionResult> ChangeAuthorityAuthData(Guid authorityAccountId, AuthData authData, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -97,14 +92,13 @@ public class UsersController(
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary> Removes authority's account authentication data </summary>
|
||||
/// <summary> Removes authority's account </summary>
|
||||
/// <remarks> Accessible only for admins </remarks>
|
||||
[HttpDelete]
|
||||
[HttpDelete("authorities/{authorityAccountId:guid}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[Route("authorities/{authorityAccountId:guid}")]
|
||||
[Authorize(policy: PolicyConstants.AdminPolicy)]
|
||||
public async Task<IActionResult> RemoveAuthorityAccount(Guid authorityAccountId, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -8,42 +8,41 @@ using SchengenVisaApi.Common;
|
||||
|
||||
namespace SchengenVisaApi.Controllers;
|
||||
|
||||
/// <summary> Controller for <see cref="Domains.VisaApplicationDomain"/> </summary>
|
||||
/// <summary> Controller for visa applications </summary>
|
||||
[ApiController]
|
||||
[Route("visaApplications")]
|
||||
public class VisaApplicationController(
|
||||
IVisaApplicationRequestsHandler visaApplicationRequestsHandler,
|
||||
IValidator<VisaApplicationCreateRequest> visaApplicationCreateRequestValidator) : ControllerBase
|
||||
{
|
||||
/// <summary> Returns all applications from DB </summary>
|
||||
/// <summary> Returns pending applications </summary>
|
||||
/// <remarks> Accessible only for approving authorities </remarks>
|
||||
[HttpGet]
|
||||
[HttpGet("pending")]
|
||||
[ProducesResponseType<List<VisaApplicationModelForAuthority>>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[Authorize(policy: PolicyConstants.ApprovingAuthorityPolicy)]
|
||||
public async Task<IActionResult> Get(CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> GetPending(CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await visaApplicationRequestsHandler.GetAllAsync(cancellationToken);
|
||||
var result = await visaApplicationRequestsHandler.GetPendingAsync(cancellationToken);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary> Returns all applications of one applicant </summary>
|
||||
/// <remarks> Returns applications of authorized applicant </remarks>
|
||||
[HttpGet]
|
||||
[HttpGet("ofApplicant")]
|
||||
[ProducesResponseType<List<VisaApplicationModelForApplicant>>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Authorize(policy: PolicyConstants.ApplicantPolicy)]
|
||||
[Route("OfApplicant")]
|
||||
public async Task<IActionResult> GetForApplicant(CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await visaApplicationRequestsHandler.GetForApplicantAsync(cancellationToken);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary> Adds new application to DB </summary>
|
||||
/// <summary> Adds new application </summary>
|
||||
/// <remarks> Adds application for authorized applicant </remarks>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
@@ -52,7 +51,7 @@ public class VisaApplicationController(
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[Authorize(policy: PolicyConstants.ApplicantPolicy)]
|
||||
public async Task<IActionResult> Create(VisaApplicationCreateRequest request, CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> CreateApplication(VisaApplicationCreateRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
await visaApplicationCreateRequestValidator.ValidateAndThrowAsync(request, cancellationToken);
|
||||
|
||||
@@ -62,28 +61,26 @@ public class VisaApplicationController(
|
||||
|
||||
/// <summary> Sets application status to closed</summary>
|
||||
/// <remarks> Accessible only for applicant</remarks>
|
||||
[HttpPatch]
|
||||
[HttpPatch("{applicationId:guid}")]
|
||||
[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)
|
||||
{
|
||||
await visaApplicationRequestsHandler.HandleCloseRequestAsync(applicationId, cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary> Allows approving authorities approve or reject applications</summary>
|
||||
/// <summary> Approve or reject applications</summary>
|
||||
/// <remarks> Accessible only for authorities</remarks>
|
||||
[HttpPatch]
|
||||
[HttpPatch("approving/{applicationId:guid}")]
|
||||
[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);
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using System.Reflection;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using ApplicationLayer;
|
||||
using Domains.Users;
|
||||
using Infrastructure;
|
||||
using Infrastructure.Auth;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using SchengenVisaApi.Common;
|
||||
using SchengenVisaApi.ExceptionFilters;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
@@ -42,7 +43,8 @@ public static class DependencyInjection
|
||||
|
||||
services.AddProblemDetails();
|
||||
|
||||
services.AddControllers(opts => opts.Filters.Add<GlobalExceptionsFilter>());
|
||||
services.AddControllers(opts => opts.Filters.Add<GlobalExceptionsFilter>())
|
||||
.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
|
||||
}
|
||||
|
||||
/// Adds authentication, authorization and token generator
|
||||
@@ -90,11 +92,38 @@ public static class DependencyInjection
|
||||
/// Add swagger
|
||||
private static void AddSwagger(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
||||
|
||||
options.CustomOperationIds(apiDescription =>
|
||||
apiDescription.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null);
|
||||
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Provide a JWT-token.",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.Http,
|
||||
BearerFormat = "JWT",
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user