From 24881ae1db6a180ba8a4d1be6929bb304f53376d Mon Sep 17 00:00:00 2001 From: prtsie Date: Wed, 4 Sep 2024 15:59:36 +0300 Subject: [PATCH 1/2] Fixed errors and wrong model --- .../VisaApplicationRequestsHandler.cs | 6 +++- .../VisaApplicationCreateRequestValidator.cs | 11 +++--- .../Requests/VisaApplicationCreateRequest.cs | 2 -- .../Controllers/UsersController.cs | 2 -- .../Controllers/VisaApplicationController.cs | 1 + SchengenVisaApi/VisaApiClient/Client.cs | 35 +++++++------------ 6 files changed, 24 insertions(+), 33 deletions(-) diff --git a/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs index 23d93b6..4ece238 100644 --- a/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs +++ b/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Handlers/VisaApplicationRequestsHandler.cs @@ -53,6 +53,10 @@ public class VisaApplicationRequestsHandler( { 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); @@ -95,4 +99,4 @@ public class VisaApplicationRequestsHandler( return model; } -} \ No newline at end of file +} diff --git a/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/Validation/VisaApplicationCreateRequestValidator.cs b/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/Validation/VisaApplicationCreateRequestValidator.cs index 84e8bc6..c0cb9d0 100644 --- a/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/Validation/VisaApplicationCreateRequestValidator.cs +++ b/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/Validation/VisaApplicationCreateRequestValidator.cs @@ -17,6 +17,12 @@ public class VisaApplicationCreateRequestValidator : AbstractValidator 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") @@ -43,11 +49,6 @@ public class VisaApplicationCreateRequestValidator : AbstractValidator r.PastVisas) .SetValidator(pastVisaModelValidator); - When(r => r.VisaCategory == VisaCategory.Transit, - () => - RuleFor(r => r.PermissionToDestCountry) - .SetValidator(permissionToDestCountryModelValidator)); - RuleForEach(r => r.PastVisits) .SetValidator(pastVisitModelValidator); } diff --git a/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/VisaApplicationCreateRequest.cs b/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/VisaApplicationCreateRequest.cs index a617022..16be84b 100644 --- a/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/VisaApplicationCreateRequest.cs +++ b/SchengenVisaApi/ApplicationLayer/Services/VisaApplications/Requests/VisaApplicationCreateRequest.cs @@ -32,8 +32,6 @@ public class VisaApplicationCreateRequest [Required] public PastVisaModel[] PastVisas { get; set; } = null!; - //todo remove attribute - [Required] public PermissionToDestCountryModel? PermissionToDestCountry { get; set; } [Required] diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs index 4522cfc..aca41d0 100644 --- a/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/UsersController.cs @@ -26,7 +26,6 @@ public class UsersController( /// Adds applicant with user account [HttpPost("register")] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status409Conflict)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task Register(RegisterApplicantRequest request, CancellationToken cancellationToken) { @@ -40,7 +39,6 @@ public class UsersController( /// Accessible only for admins [HttpPost("authorities")] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status409Conflict)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status400BadRequest)] diff --git a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs index cb4b164..2f98b40 100644 --- a/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs +++ b/SchengenVisaApi/SchengenVisaApi/Controllers/VisaApplicationController.cs @@ -66,6 +66,7 @@ public class VisaApplicationController( [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] [Authorize(policy: PolicyConstants.ApplicantPolicy)] public async Task CloseApplication(Guid applicationId, CancellationToken cancellationToken) { diff --git a/SchengenVisaApi/VisaApiClient/Client.cs b/SchengenVisaApi/VisaApiClient/Client.cs index c65b9de..7cbe2e8 100644 --- a/SchengenVisaApi/VisaApiClient/Client.cs +++ b/SchengenVisaApi/VisaApiClient/Client.cs @@ -131,16 +131,6 @@ namespace VisaApiClient return; } else - if (status_ == 409) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Conflict", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else if (status_ == 400) { var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); @@ -239,16 +229,6 @@ namespace VisaApiClient return; } else - if (status_ == 409) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Conflict", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else if (status_ == 403) { var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); @@ -1220,6 +1200,16 @@ namespace VisaApiClient throw new ApiException("Not Found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad Request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); @@ -1938,9 +1928,8 @@ namespace VisaApiClient [System.ComponentModel.DataAnnotations.Required] public System.Collections.Generic.ICollection PastVisas { get; set; } = new System.Collections.ObjectModel.Collection(); - [Newtonsoft.Json.JsonProperty("permissionToDestCountry", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public PermissionToDestCountryModel PermissionToDestCountry { get; set; } = new PermissionToDestCountryModel(); + [Newtonsoft.Json.JsonProperty("permissionToDestCountry", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public PermissionToDestCountryModel PermissionToDestCountry { get; set; } = default!; [Newtonsoft.Json.JsonProperty("pastVisits", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] From 80e15e88f5a0b2870143b0718b1d1144f5eae3e3 Mon Sep 17 00:00:00 2001 From: prtsie Date: Thu, 5 Sep 2024 22:31:13 +0300 Subject: [PATCH 2/2] started applications page --- .../BlazorWebAssemblyVisaApiClient.csproj | 1 + .../Components/Auth/AuthComponent.razor | 9 +++ .../Applicants/EnumInputList.razor | 12 +--- .../Applicants/PassportInput.razor | 1 + .../Validators/PassportModelValidator.cs | 1 + .../RegisterApplicantRequestValidator.cs | 1 + .../Infrastructure/Helpers/EnumExtensions.cs | 18 ++++++ .../DateTimeProvider.cs | 2 +- .../IDateTimeProvider.cs | 2 +- .../Pages/Applications.razor | 56 +++++++++++++++++++ .../Pages/Register.razor | 1 + 11 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Helpers/EnumExtensions.cs rename SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/{ => DateTimeProvider}/DateTimeProvider.cs (89%) rename SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/{ => DateTimeProvider}/IDateTimeProvider.cs (87%) create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Applications.razor diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/BlazorWebAssemblyVisaApiClient.csproj b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/BlazorWebAssemblyVisaApiClient.csproj index 4798785..24bb67e 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/BlazorWebAssemblyVisaApiClient.csproj +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/BlazorWebAssemblyVisaApiClient.csproj @@ -13,6 +13,7 @@ + diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor index 79947a1..f531914 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor @@ -1,11 +1,16 @@ @using System.Net +@using System.IdentityModel.Tokens.Jwt +@using System.Security.Claims @using BlazorWebAssemblyVisaApiClient.Components.Auth.Exceptions @using BlazorWebAssemblyVisaApiClient.ErrorHandling @using VisaApiClient @code { public static bool LoggedIn; + public static ApplicantModel? CurrentApplicant; //todo api action + public static string? CurrentRole; private static AuthData savedData = null!; + private static readonly JwtSecurityTokenHandler TokenHandler = new(); [CascadingParameter] private GlobalErrorHandler ErrorHandler { get; set; } = null!; @@ -24,6 +29,10 @@ { var token = await Client.LoginAsync(authData.Email, authData.Password); Client.SetAuthToken(token); + CurrentRole = TokenHandler.ReadJwtToken(token.Token) + .Claims + .FirstOrDefault(claim => claim.Type == ClaimTypes.Role)? + .Value; savedData = authData; Status?.SetSucces("Logged in successfully."); diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/EnumInputList.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/EnumInputList.razor index 0895b65..3980d03 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/EnumInputList.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/EnumInputList.razor @@ -1,6 +1,6 @@ -@using System.ComponentModel.DataAnnotations -@using System.Linq.Expressions +@using System.Linq.Expressions @using System.Reflection +@using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers @typeparam TItem where TItem : class @typeparam TMember where TMember : struct, Enum @@ -22,18 +22,12 @@ protected override void OnInitialized() { - var enumMembers = typeof(TMember).GetMembers(); var modelMemberName = ((MemberExpression)EnumProperty.Body).Member.Name; modelMemberInfo = typeof(TItem).GetProperty(modelMemberName)!; foreach (var value in Enum.GetValues()) { - var member = enumMembers.First(info => info.Name == value.ToString()); - var displayAttribute = (DisplayAttribute?)member - .GetCustomAttributes(typeof(DisplayAttribute), false) - .FirstOrDefault(); - var displayName = displayAttribute?.Name ?? value.ToString(); - enumValues.Add(value, displayName); + enumValues.Add(value, value.GetDisplayName()); } } diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/PassportInput.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/PassportInput.razor index ec52b6c..8e6401b 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/PassportInput.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/FormComponents/Applicants/PassportInput.razor @@ -1,4 +1,5 @@ @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services +@using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider @using VisaApiClient
diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/PassportModelValidator.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/PassportModelValidator.cs index 289b8c4..a8d0fbe 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/PassportModelValidator.cs +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/PassportModelValidator.cs @@ -1,4 +1,5 @@ using BlazorWebAssemblyVisaApiClient.Infrastructure.Services; +using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider; using FluentValidation; using VisaApiClient; diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/RegisterApplicantRequestValidator.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/RegisterApplicantRequestValidator.cs index d7c626d..907e159 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/RegisterApplicantRequestValidator.cs +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/FluentValidation/Applicants/Validators/RegisterApplicantRequestValidator.cs @@ -1,5 +1,6 @@ using BlazorWebAssemblyVisaApiClient.FluentValidation.Applicants.Models; using BlazorWebAssemblyVisaApiClient.Infrastructure.Services; +using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider; using FluentValidation; using VisaApiClient; using PlaceOfWorkModel = BlazorWebAssemblyVisaApiClient.FluentValidation.Applicants.Models.PlaceOfWorkModel; diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Helpers/EnumExtensions.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Helpers/EnumExtensions.cs new file mode 100644 index 0000000..d49ba1b --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Helpers/EnumExtensions.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers +{ + public static class EnumExtensions + { + public static string GetDisplayName(this Enum value) + { + var enumMembers = value.GetType().GetMembers(); + var member = enumMembers.First(info => info.Name == value.ToString()); + var displayAttribute = (DisplayAttribute?)member + .GetCustomAttributes(typeof(DisplayAttribute), false) + .FirstOrDefault(); + var displayName = displayAttribute?.Name ?? value.ToString(); + return displayName; + } + } +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider/DateTimeProvider.cs similarity index 89% rename from SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider.cs rename to SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider/DateTimeProvider.cs index 35e9e91..340eb09 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider.cs +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider/DateTimeProvider.cs @@ -1,4 +1,4 @@ -namespace BlazorWebAssemblyVisaApiClient.Infrastructure.Services +namespace BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider { public class DateTimeProvider : IDateTimeProvider { diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/IDateTimeProvider.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider/IDateTimeProvider.cs similarity index 87% rename from SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/IDateTimeProvider.cs rename to SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider/IDateTimeProvider.cs index d0f7596..4dc42ba 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/IDateTimeProvider.cs +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Infrastructure/Services/DateTimeProvider/IDateTimeProvider.cs @@ -1,4 +1,4 @@ -namespace BlazorWebAssemblyVisaApiClient.Infrastructure.Services +namespace BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider { public interface IDateTimeProvider { diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Applications.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Applications.razor new file mode 100644 index 0000000..06dab63 --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Applications.razor @@ -0,0 +1,56 @@ +@page "/applications" +@using System.Net +@using System.Text +@using BlazorWebAssemblyVisaApiClient.Components +@using BlazorWebAssemblyVisaApiClient.Components.Auth +@using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers +@using VisaApiClient +@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase + +@(AuthComponent.CurrentRole ?? "bruh") + +@((MarkupString)htmlMarkup) + +@code { + private string htmlMarkup = "bruh"; + + protected override async Task OnInitializedAsync() + { + var stringBuilder = new StringBuilder(); + + try + { + switch (AuthComponent.CurrentRole) + { + case "Applicant": + var applications = await Client.GetForApplicantAsync(); + + stringBuilder.AppendLine(""); + foreach (var application in applications) + { + stringBuilder.AppendLine($""); + } + + stringBuilder.AppendLine("
Destination CountryVisa CategoryRequest dateDays requestedStatus
{application.DestinationCountry}{application.VisaCategory.GetDisplayName()}{application.RequestDate.ToString("d")}{application.ValidDaysRequested}{application.Status.GetDisplayName()}
"); + htmlMarkup = stringBuilder.ToString(); + break; + default: + htmlMarkup = AuthComponent.CurrentRole; + break; + } + } + catch (Exception e) + { + if (e is ApiException { Result.Status: (int)HttpStatusCode.Unauthorized } problemDetailsException) + { + htmlMarkup = problemDetailsException.Result.Detail!; + } + else + { + //ErrorHandler.Handle(e); + throw; + } + } + } + +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor index c195c19..cfdf329 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor @@ -10,6 +10,7 @@ @using Newtonsoft.Json @using Newtonsoft.Json.Linq @using BlazorWebAssemblyVisaApiClient.Components +@using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase Registration