Validation fixes, finished application creation, added required char (*) for required fields
This commit is contained in:
		| @@ -27,7 +27,7 @@ | ||||
|             Client.AuthToken = token; | ||||
|             AuthData = authData; | ||||
|  | ||||
|             Status?.SetSucces("Logged in successfully."); | ||||
|             Status?.SetSuccess("Logged in successfully."); | ||||
|         } | ||||
|         catch (ApiException<ProblemDetails> e) | ||||
|         { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| <div> | ||||
|     <div > | ||||
|         <label> | ||||
|             First name:<br/> | ||||
|             First name@(Constants.RequiredFieldMarkup):<br/> | ||||
|             <InputText DisplayName="First name" class="rounded" @bind-Value="Name.FirstName"/> | ||||
|         </label><br/> | ||||
|         <ValidationMessage For="() => Name.FirstName"></ValidationMessage> | ||||
| @@ -11,7 +11,7 @@ | ||||
|  | ||||
|     <div > | ||||
|         <label> | ||||
|             Surname:<br/> | ||||
|             Surname@(Constants.RequiredFieldMarkup):<br/> | ||||
|             <InputText class="rounded" @bind-Value="Name.Surname"/> | ||||
|         </label><br/> | ||||
|         <ValidationMessage For="() => Name.Surname"></ValidationMessage> | ||||
|   | ||||
| @@ -25,7 +25,7 @@ | ||||
|         StateHasChanged(); | ||||
|     } | ||||
|  | ||||
|     public void SetSucces(string message) | ||||
|     public void SetSuccess(string message) | ||||
|     { | ||||
|         statusClass = "text-success"; | ||||
|         StatusText = message; | ||||
|   | ||||
							
								
								
									
										16
									
								
								SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Constants.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Constants.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| using System.Text.RegularExpressions; | ||||
| using Microsoft.AspNetCore.Components; | ||||
|  | ||||
| namespace BlazorWebAssemblyVisaApiClient | ||||
| { | ||||
|     public static class Constants | ||||
|     { | ||||
|         public readonly static Regex EnglishWordRegex = new("^[a-zA-Z]*$"); | ||||
|  | ||||
|         public readonly static Regex EnglishPhraseRegex = new(@"^[a-zA-Z№0-9?><;,{}[\]\-_+=!@#$%\^&*|']*$"); | ||||
|  | ||||
|         public readonly static Regex PhoneNumRegex = new(@"^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$"); | ||||
|  | ||||
|         public readonly static MarkupString RequiredFieldMarkup = (MarkupString)"<span style=\"color: red;\">*</span>"; | ||||
|     } | ||||
| } | ||||
| @@ -22,7 +22,7 @@ | ||||
|         <ObjectGraphDataAnnotationsValidator/> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Visa</h5> | ||||
|             <h5>Visa@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <label> | ||||
|                 Destination Country:<br/> | ||||
|                 <InputText DisplayName="Destination Country" class="rounded" @bind-Value="requestModel.DestinationCountry"/> | ||||
| @@ -56,7 +56,7 @@ | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Past visas</h5> | ||||
|             @if (currentPastVisa > 0) | ||||
|             @if (requestModel.PastVisas.Count > 0) | ||||
|             { | ||||
|                 <table class="table table-bordered"> | ||||
|                     <thead> | ||||
| @@ -65,9 +65,8 @@ | ||||
|                     </tr> | ||||
|                     </thead> | ||||
|                     <tbody> | ||||
|                     @for (var i = 0; i < currentPastVisa; i++) | ||||
|                     @foreach (var visa in requestModel.PastVisas) | ||||
|                     { | ||||
|                         var visa = requestModel.PastVisas[i]; | ||||
|                         <tr> | ||||
|                             <th>@visa.Name</th> | ||||
|                             <th>@visa.IssueDate.ToString("d.MM.yyyy")</th> | ||||
| @@ -81,39 +80,94 @@ | ||||
|                 </table> | ||||
|             } | ||||
|             <label> | ||||
|                 Name: | ||||
|                 <InputText DisplayName="Past visa name" @bind-Value="requestModel.PastVisas[currentPastVisa].Name"/> | ||||
|                 Name:<br/> | ||||
|                 <InputText DisplayName="Past visa name" class="rounded" @bind-Value="editableVisa.Name"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.PastVisas[currentPastVisa].Name"></ValidationMessage><br/> | ||||
|             <ValidationMessage For="() => editableVisa.Name"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Issue date:<br/> | ||||
|                 <InputDate DisplayName="Past visa issue date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="requestModel.PastVisas[currentPastVisa].IssueDate" | ||||
|                            @bind-Value="editableVisa.IssueDate" | ||||
|                            max="@formattedNow"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.PastVisas[currentPastVisa].IssueDate"></ValidationMessage><br/> | ||||
|             <ValidationMessage For="() => editableVisa.IssueDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Expiration date:<br/> | ||||
|                 <InputDate DisplayName="Past visa expiration date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="requestModel.PastVisas[currentPastVisa].ExpirationDate" | ||||
|                            min="@formattedNow"/> | ||||
|                            @bind-Value="editableVisa.ExpirationDate"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.PastVisas[currentPastVisa].ExpirationDate"></ValidationMessage><br/> | ||||
|             <ValidationMessage For="() => editableVisa.ExpirationDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <input type="button" class="btn-outline-primary" | ||||
|                    disabled="@(currentPastVisa == requestModel.PastVisas.Length - 1)" | ||||
|                    disabled="@(requestModel.PastVisas.Count == ConfigurationConstraints.MaxPastVisas)" | ||||
|                    @onclick="AddPastVisa" value="Add"/> | ||||
|             <Status @ref="pastVisaStatus"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Past visits</h5> | ||||
|             @if (requestModel.PastVisits.Count > 0) | ||||
|             { | ||||
|                 <table class="table table-bordered"> | ||||
|                     <thead> | ||||
|                     <tr> | ||||
|                         <th>Destination Country</th><th>Start date</th><th>End date</th><th></th> | ||||
|                     </tr> | ||||
|                     </thead> | ||||
|                     <tbody> | ||||
|                     @foreach (var visit in requestModel.PastVisits) | ||||
|                     { | ||||
|                         <tr> | ||||
|                             <th>@visit.DestinationCountry</th> | ||||
|                             <th>@visit.StartDate.ToString("d.MM.yyyy")</th> | ||||
|                             <th>@visit.EndDate.ToString("d.MM.yyyy")</th> | ||||
|                             <th> | ||||
|                                 <input type="button" class="border-danger" @onclick="() => RemovePastVisit(visit)" value="X"/> | ||||
|                             </th> | ||||
|                         </tr> | ||||
|                     } | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             } | ||||
|             <label> | ||||
|                 Destination Country:<br/> | ||||
|                 <InputText DisplayName="Past visit destination Country" class="rounded" @bind-Value="editableVisit.DestinationCountry"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisit.DestinationCountry"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Start date:<br/> | ||||
|                 <InputDate DisplayName="Past visit start date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="editableVisit.StartDate" | ||||
|                            max="@formattedNow"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisit.StartDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 End date:<br/> | ||||
|                 <InputDate DisplayName="Past visit end date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="editableVisit.EndDate" | ||||
|                            max="@formattedNow"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisit.EndDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <input type="button" class="btn-outline-primary" | ||||
|                    disabled="@(requestModel.PastVisits.Count == ConfigurationConstraints.MaxPastVisits)" | ||||
|                    @onclick="AddPastVisit" value="Add"/> | ||||
|             <Status @ref="pastVisitStatus"/> | ||||
|         </div> | ||||
|  | ||||
|         @if (requestModel.VisaCategory is VisaCategory.Transit) | ||||
|         { | ||||
|             requestModel.PermissionToDestCountry ??= NewPermissionToDestCountry(); | ||||
|             <div class="form-block"> | ||||
|                 <h5>Permission to destination Country</h5> | ||||
|                 <h5>Permission to destination Country@(Constants.RequiredFieldMarkup)</h5> | ||||
|                 <PermissionToDestCountryInput PermissionToDestCountry="requestModel.PermissionToDestCountry"/> | ||||
|             </div> | ||||
|         } | ||||
| @@ -124,14 +178,14 @@ | ||||
|  | ||||
|         @if (isNonResident) | ||||
|         { | ||||
|             requestModel.ReentryPermit = NewReentryPermit(); | ||||
|             <div class="form-block"> | ||||
|                 <h5>Re-entry permission</h5> | ||||
|                 <h5>Re-entry permission@(Constants.RequiredFieldMarkup)</h5> | ||||
|                 <ReentryPermitInput ReentryPermit="requestModel.ReentryPermit"/> | ||||
|             </div> | ||||
|             <br/> | ||||
|         } | ||||
|  | ||||
|         <input type="submit" class="btn-outline-primary" value="Register"/> | ||||
|         <br/><input type="submit" class="btn-outline-primary" value="Register"/> | ||||
|         <ValidationSummary/> | ||||
|         <Status @ref="status"/> | ||||
|     </EditForm> | ||||
| @@ -143,10 +197,11 @@ | ||||
|     private VisaApplicationCreateRequestModel requestModel = new(); | ||||
|     private Status status = null!; | ||||
|     private Status pastVisaStatus = null!; | ||||
|     private Status pastVisitStatus = null!; | ||||
|     private bool isNonResident; | ||||
|     private int currentPastVisa; | ||||
|     private int currentPastVisit; | ||||
|     private string formattedNow = null!; | ||||
|     private PastVisaModel editableVisa = null!; | ||||
|     private PastVisitModel editableVisit = null!; | ||||
|  | ||||
|     [Inject] IDateTimeProvider DateTimeProvider { get; set; } = null!; | ||||
|  | ||||
| @@ -156,19 +211,16 @@ | ||||
|  | ||||
|     [Inject] IValidator<PastVisaModel> PastVisaModelValidator { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IValidator<PastVisitModel> PastVisitModelValidator { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IMapper Mapper { get; set; } = null!; | ||||
|  | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         requestModel.PastVisas = new PastVisaModel[ConfigurationConstraints.MaxPastVisas]; | ||||
|         for (var i = 0; i < requestModel.PastVisas.Length; i++) | ||||
|         { | ||||
|             requestModel.PastVisas[i] = new() | ||||
|             { | ||||
|                 IssueDate = DateTimeProvider.Now(), | ||||
|                 ExpirationDate = DateTimeProvider.Now() | ||||
|             }; | ||||
|         } | ||||
|         editableVisa = NewPastVisa(); | ||||
|         editableVisit = NewPastVisit(); | ||||
|         requestModel.PermissionToDestCountry = NewPermissionToDestCountry(); | ||||
|         formattedNow = DateTimeProvider.FormattedNow(); | ||||
|  | ||||
|         try | ||||
|         { | ||||
| @@ -178,16 +230,10 @@ | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|  | ||||
|         formattedNow = DateTimeProvider.FormattedNow(); | ||||
|         requestModel.PermissionToDestCountry!.ExpirationDate = DateTimeProvider.Now(); | ||||
|     } | ||||
|  | ||||
|     private async Task TryCreate() | ||||
|     { | ||||
|         requestModel.PastVisas = currentPastVisa == 0 ? [] : requestModel.PastVisas[..currentPastVisa]; | ||||
|         requestModel.PastVisits = currentPastVisit == 0 ? [] : requestModel.PastVisits[..currentPastVisit]; | ||||
|  | ||||
|         var validationResult = await VisaApplicationCreateRequestValidator.ValidateAsync(requestModel); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
| @@ -201,7 +247,7 @@ | ||||
|         try | ||||
|         { | ||||
|             await Client.CreateApplicationAsync(request); | ||||
|             status.SetSucces("Application created successfully."); | ||||
|             status.SetSuccess("Application created successfully."); | ||||
|         } | ||||
|         catch (ApiException<ProblemDetails> e) | ||||
|         { | ||||
| @@ -230,49 +276,87 @@ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private PastVisaModel NewPastVisa() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             ExpirationDate = DateTimeProvider.Now(), | ||||
|             IssueDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private ReentryPermitModel NewReentryPermit() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             ExpirationDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private PermissionToDestCountryModel NewPermissionToDestCountry() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             ExpirationDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private PastVisitModel NewPastVisit() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             StartDate = DateTimeProvider.Now(), | ||||
|             EndDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private void AddPastVisa() | ||||
|     { | ||||
|         var validationResult = PastVisaModelValidator.Validate(requestModel.PastVisas[currentPastVisa]); | ||||
|         if (requestModel.PastVisas.Count >= ConfigurationConstraints.MaxPastVisas) | ||||
|         { | ||||
|             pastVisaStatus.SetError($"{ConfigurationConstraints.MaxPastVisas} past visas is maximum"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var validationResult = PastVisaModelValidator.Validate(editableVisa); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             pastVisaStatus.SetError(validationResult.ToErrorsString()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (currentPastVisa < requestModel.PastVisas.Length - 1) | ||||
|         { | ||||
|             currentPastVisa++; | ||||
|             pastVisaStatus.SetSucces("Added"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             pastVisaStatus.SetError($"{requestModel.PastVisas.Length} past visas is maximum"); | ||||
|         } | ||||
|         requestModel.PastVisas.Add(editableVisa); | ||||
|         editableVisa = NewPastVisa(); | ||||
|         pastVisaStatus.SetSuccess("Added successfully"); | ||||
|     } | ||||
|  | ||||
|     private void RemovePastVisa(PastVisaModel visa) | ||||
|     { | ||||
|         currentPastVisa--; | ||||
|         var found = false; | ||||
|         requestModel.PastVisas.Remove(visa); | ||||
|     } | ||||
|  | ||||
|         if (requestModel.PastVisas[^1] == visa) | ||||
|     private void AddPastVisit() | ||||
|     { | ||||
|         if (requestModel.PastVisits.Count >= ConfigurationConstraints.MaxPastVisits) | ||||
|         { | ||||
|             requestModel.PastVisas[^1] = new(); | ||||
|             pastVisitStatus.SetError($"{ConfigurationConstraints.MaxPastVisits} past visits is maximum"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for (var i = 0; i < requestModel.PastVisas.Length - 1; i++) | ||||
|         var validationResult = PastVisitModelValidator.Validate(editableVisit); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             if (requestModel.PastVisas[i] == visa) | ||||
|             { | ||||
|                 found = true; | ||||
|             } | ||||
|  | ||||
|             if (found) | ||||
|             { | ||||
|                 requestModel.PastVisas[i] = requestModel.PastVisas[i + 1]; | ||||
|             } | ||||
|             pastVisitStatus.SetError(validationResult.ToErrorsString()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         requestModel.PastVisits.Add(editableVisit); | ||||
|         editableVisit = NewPastVisit(); | ||||
|         pastVisitStatus.SetSuccess("Added successfully"); | ||||
|     } | ||||
|  | ||||
|     private void RemovePastVisit(PastVisitModel visit) | ||||
|     { | ||||
|         requestModel.PastVisits.Remove(visit); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.Applicants.Models | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| @@ -20,7 +21,7 @@ | ||||
|         <ObjectGraphDataAnnotationsValidator/> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Authentication data</h5> | ||||
|             <h5>Authentication data@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <AuthDataInput AuthData="requestModel.RegisterRequest.AuthData"/> | ||||
|         </div> | ||||
|  | ||||
| @@ -40,12 +41,12 @@ | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Your passport</h5> | ||||
|             <h5>Your passport@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <PassportInput Passport="requestModel.Passport"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Birth data</h5> | ||||
|             <h5>Birth data@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Country of birth:<br/> | ||||
| @@ -59,14 +60,14 @@ | ||||
|                 <ValidationMessage For="() => requestModel.CityOfBirth"></ValidationMessage><br/> | ||||
|                 <label> | ||||
|                     Birth date:<br/> | ||||
|                     <InputDate DisplayName="Birth date" class="rounded" @bind-Value="requestModel.BirthDate" max="@DateTimeProvider.FormattedNow()"/> | ||||
|                     <InputDate DisplayName="Birth date" class="rounded" @bind-Value="requestModel.BirthDate" max="@formattedMaxBirthdayDate"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.BirthDate"></ValidationMessage> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Citizenship</h5> | ||||
|             <h5>Citizenship@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Citizenship:<br/> | ||||
| @@ -82,14 +83,14 @@ | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Address of your place of work</h5> | ||||
|             <h5>Address of your place of work@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <AddressInput Address="requestModel.PlaceOfWork.Address"/> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Place of work data</h5> | ||||
|             <h5>Place of work data@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <PlaceOfWorkInput PlaceOfWork="requestModel.PlaceOfWork"/><br/> | ||||
|  | ||||
| @@ -132,6 +133,7 @@ | ||||
| { | ||||
|     private RegisterApplicantRequestModel requestModel = new(); | ||||
|     private Status status = null!; | ||||
|     private string formattedMaxBirthdayDate = null!; | ||||
|  | ||||
|     [Inject] IValidator<RegisterApplicantRequestModel> RegisterApplicantRequestValidator { get; set; } = null!; | ||||
|  | ||||
| @@ -141,7 +143,8 @@ | ||||
|  | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         requestModel.BirthDate = DateTime.Now; | ||||
|         requestModel.BirthDate = DateTime.Now.AddYears(-ConfigurationConstraints.ApplicantMinAge); | ||||
|         formattedMaxBirthdayDate = requestModel.BirthDate.ToString("yyyy-MM-dd"); | ||||
|     } | ||||
|  | ||||
|     private async void TryRegisterApplicant() | ||||
| @@ -161,7 +164,7 @@ | ||||
|         try | ||||
|         { | ||||
|             await Client.RegisterAsync(request); | ||||
|             status.SetSucces("Register successful. Now log in."); | ||||
|             status.SetSuccess("Register successful. Now log in."); | ||||
|         } | ||||
|         catch (ApiException<ProblemDetails> e) | ||||
|         { | ||||
|   | ||||
| @@ -10,16 +10,22 @@ public class NameModelValidator : AbstractValidator<NameModel> | ||||
|         RuleFor(m => m.FirstName) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("First Name can not be empty") | ||||
|             .Matches(Constants.EnglishWordRegex) | ||||
|             .WithMessage("First name must be in english characters") | ||||
|             .MaximumLength(ConfigurationConstraints.NameLength) | ||||
|             .WithMessage($"First Name length must be less than {ConfigurationConstraints.NameLength}"); | ||||
|  | ||||
|         RuleFor(m => m.Surname) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Surname can not be empty") | ||||
|             .Matches(Constants.EnglishWordRegex) | ||||
|             .WithMessage("Surname must be in english characters") | ||||
|             .MaximumLength(ConfigurationConstraints.NameLength) | ||||
|             .WithMessage($"Surname length must be less than {ConfigurationConstraints.NameLength}"); | ||||
|  | ||||
|         RuleFor(m => m.Patronymic) | ||||
|             .Matches(Constants.EnglishWordRegex) | ||||
|             .WithMessage("Patronymic must be in english characters") | ||||
|             .MaximumLength(ConfigurationConstraints.NameLength) | ||||
|             .WithMessage($"Patronymic length must be less than {ConfigurationConstraints.NameLength}"); | ||||
|     } | ||||
|   | ||||
| @@ -11,12 +11,16 @@ public class PassportModelValidator : AbstractValidator<PassportModel> | ||||
|         RuleFor(r => r.Issuer) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Passport issuer can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Passport issuer field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.IssuerNameLength) | ||||
|             .WithMessage($"Passport issuer length must be less than {ConfigurationConstraints.IssuerNameLength}"); | ||||
|  | ||||
|         RuleFor(r => r.Number) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Passport number can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Passport number field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.PassportNumberLength) | ||||
|             .WithMessage($"Passport number length must be less than {ConfigurationConstraints.PassportNumberLength}"); | ||||
|  | ||||
|   | ||||
| @@ -10,12 +10,16 @@ public class PlaceOfWorkModelValidator : AbstractValidator<PlaceOfWorkModel> | ||||
|         RuleFor(p => p.Name) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Place of work name can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Place of work name field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.PlaceOfWorkNameLength) | ||||
|             .WithMessage($"Place of work name length must be less than {ConfigurationConstraints.PlaceOfWorkNameLength}"); | ||||
|  | ||||
|         RuleFor(p => p.PhoneNum) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Place of work phone number can not be empty") | ||||
|             .Matches(Constants.PhoneNumRegex) | ||||
|             .WithMessage("Place of work phone number field must be valid") | ||||
|             .MaximumLength(ConfigurationConstraints.PhoneNumberLength) | ||||
|             .WithMessage( | ||||
|                 $"Phone number length must be in range from {ConfigurationConstraints.PhoneNumberMinLength} to {ConfigurationConstraints.PhoneNumberLength}") | ||||
| @@ -23,27 +27,39 @@ public class PlaceOfWorkModelValidator : AbstractValidator<PlaceOfWorkModel> | ||||
|             .WithMessage( | ||||
|                 $"Phone number length must be in range from {ConfigurationConstraints.PhoneNumberMinLength} to {ConfigurationConstraints.PhoneNumberLength}"); | ||||
|  | ||||
|         RuleFor(p => p.Address) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Place of work address can not be empty"); | ||||
|  | ||||
|         RuleFor(p => p.Address.Country) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Country name of place of work can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Place of work Country field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|             .WithMessage($"Country name of place of work length must be less than {ConfigurationConstraints.CountryNameLength}"); | ||||
|  | ||||
|         RuleFor(p => p.Address.City) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("City name of place of work can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Place of work City field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CityNameLength) | ||||
|             .WithMessage($"City name of place of work length must be less than {ConfigurationConstraints.CityNameLength}"); | ||||
|  | ||||
|         RuleFor(p => p.Address.Street) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Street name of place of work can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Place of work Street field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.StreetNameLength) | ||||
|             .WithMessage($"Street name of place of work length must be less than {ConfigurationConstraints.StreetNameLength}"); | ||||
|  | ||||
|         RuleFor(p => p.Address.Building) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Building of place of work can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Place of work building field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|             .WithMessage($"Building of place of work length must be less than {ConfigurationConstraints.BuildingNumberLength}"); | ||||
|     } | ||||
|   | ||||
| @@ -11,23 +11,28 @@ public class RegisterApplicantRequestValidator : AbstractValidator<RegisterAppli | ||||
|     public RegisterApplicantRequestValidator( | ||||
|         IDateTimeProvider dateTimeProvider, | ||||
|         IValidator<NameModel> nameValidator, | ||||
|         IValidator<RegisterRequestModel> registerRequestModelValidator, | ||||
|         IValidator<RegisterRequestModel> registerRequestValidator, | ||||
|         IValidator<PassportModel> passportValidator, | ||||
|         IValidator<PlaceOfWorkModel> placeOfWorkModelValidator) | ||||
|     { | ||||
|         RuleFor(r => r.RegisterRequest) | ||||
|             .SetValidator(registerRequestModelValidator); | ||||
|             .NotEmpty() | ||||
|             .SetValidator(registerRequestValidator); | ||||
|  | ||||
|         RuleFor(r => r.ApplicantName) | ||||
|             .NotEmpty() | ||||
|             .SetValidator(nameValidator); | ||||
|  | ||||
|         RuleFor(r => r.FatherName) | ||||
|             .NotEmpty() | ||||
|             .SetValidator(nameValidator); | ||||
|  | ||||
|         RuleFor(r => r.MotherName) | ||||
|             .NotEmpty() | ||||
|             .SetValidator(nameValidator); | ||||
|  | ||||
|         RuleFor(r => r.Passport) | ||||
|             .NotEmpty() | ||||
|             .SetValidator(passportValidator); | ||||
|  | ||||
|         RuleFor(r => r.BirthDate) | ||||
| @@ -39,38 +44,51 @@ public class RegisterApplicantRequestValidator : AbstractValidator<RegisterAppli | ||||
|         RuleFor(r => r.CountryOfBirth) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Country of birth can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Country of birth field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|             .WithMessage($"Country of birth name length must be less than {ConfigurationConstraints.CountryNameLength}"); | ||||
|  | ||||
|         RuleFor(r => r.CityOfBirth) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("City of birth can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("City of birth field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CityNameLength) | ||||
|             .WithMessage($"City of birth name length must be less than {ConfigurationConstraints.CityNameLength}"); | ||||
|  | ||||
|         RuleFor(r => r.Citizenship) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Citizenship can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Citizenship field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CitizenshipLength) | ||||
|             .WithMessage($"Citizenship length must be less than {ConfigurationConstraints.CitizenshipLength}"); | ||||
|  | ||||
|         RuleFor(r => r.CitizenshipByBirth) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Citizenship by birth can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Citizenship by birth field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.CitizenshipLength) | ||||
|             .WithMessage($"Citizenship by birth length must be less than {ConfigurationConstraints.CitizenshipLength}"); | ||||
|  | ||||
|         RuleFor(r => r.Gender).IsInEnum(); | ||||
|         RuleFor(r => r.Gender) | ||||
|             .IsInEnum(); | ||||
|  | ||||
|         RuleFor(r => r.MaritalStatus).IsInEnum(); | ||||
|         RuleFor(r => r.MaritalStatus) | ||||
|             .IsInEnum(); | ||||
|  | ||||
|         RuleFor(r => r.JobTitle) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Title of job can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Title of job field can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.JobTitleLength) | ||||
|             .WithMessage($"Title of job length must be less than {ConfigurationConstraints.JobTitleLength}"); | ||||
|  | ||||
|         RuleFor(r => r.PlaceOfWork) | ||||
|             .NotEmpty() | ||||
|             .SetValidator(placeOfWorkModelValidator); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -18,6 +18,8 @@ public class AuthDataValidator : AbstractValidator<AuthData> | ||||
|         RuleFor(d => d.Password) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Password can not be empty") | ||||
|             .Matches(Constants.EnglishPhraseRegex) | ||||
|             .WithMessage("Password can contain only english letters, digits and special symbols") | ||||
|             .MaximumLength(ConfigurationConstraints.PasswordLength) | ||||
|             .WithMessage($"Password length must be less than {ConfigurationConstraints.PasswordLength}"); | ||||
|     } | ||||
|   | ||||
| @@ -4,11 +4,12 @@ using VisaApiClient; | ||||
| 
 | ||||
| namespace BlazorWebAssemblyVisaApiClient.Validation.Common; | ||||
| 
 | ||||
| public class RegisterRequestModelValidator : AbstractValidator<RegisterRequestModel> | ||||
| public class RegisterRequestValidator : AbstractValidator<RegisterRequestModel> | ||||
| { | ||||
|     public RegisterRequestModelValidator(IValidator<AuthData> authDataValidator) | ||||
|     public RegisterRequestValidator(IValidator<AuthData> authDataValidator) | ||||
|     { | ||||
|         RuleFor(r => r.AuthData) | ||||
|             .NotEmpty() | ||||
|             .SetValidator(authDataValidator); | ||||
|     } | ||||
| } | ||||
| @@ -7,7 +7,7 @@ namespace BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models | ||||
|     public class VisaApplicationCreateRequestModel | ||||
|     { | ||||
|         [ValidateComplexType] | ||||
|         public ReentryPermitModel? ReentryPermit { get; set; } = new(); | ||||
|         public ReentryPermitModel? ReentryPermit { get; set; } = default!; | ||||
|  | ||||
|         [Required] | ||||
|         [MaxLength(ConfigurationConstraints.CountryNameLength)] | ||||
| @@ -26,11 +26,13 @@ namespace BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models | ||||
|         [Range(0, ConfigurationConstraints.MaxValidDays)] | ||||
|         public int ValidDaysRequested { get; set; } | ||||
|  | ||||
|         [ValidateComplexType] public PastVisaModel[] PastVisas { get; set; } = default!; | ||||
|         [ValidateComplexType] | ||||
|         public List<PastVisaModel> PastVisas { get; set; } = []; | ||||
|  | ||||
|         [ValidateComplexType] | ||||
|         public PermissionToDestCountryModel? PermissionToDestCountry { get; set; } = new(); | ||||
|         public PermissionToDestCountryModel? PermissionToDestCountry { get; set; } = default!; | ||||
|  | ||||
|         [ValidateComplexType] public PastVisitModel[] PastVisits { get; set; } = default!; | ||||
|         [ValidateComplexType] | ||||
|         public List<PastVisitModel> PastVisits { get; set; } = []; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,10 @@ public class PastVisaModelValidator : AbstractValidator<PastVisaModel> | ||||
|  | ||||
|         RuleFor(v => v.Name) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Name of past visa can not be empty"); | ||||
|             .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}"); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -23,6 +23,8 @@ public class PastVisitModelValidator : AbstractValidator<PastVisitModel> | ||||
|         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}"); | ||||
|     } | ||||
|   | ||||
| @@ -17,6 +17,8 @@ public class PermissionToDestCountryModelValidator : AbstractValidator<Permissio | ||||
|         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 BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider; | ||||
| using FluentValidation; | ||||
| using VisaApiClient; | ||||
|  | ||||
| namespace BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Validators; | ||||
|  | ||||
| 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"); | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +1,18 @@ | ||||
| using BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models; | ||||
| using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider; | ||||
| using BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models; | ||||
| using FluentValidation; | ||||
| using VisaApiClient; | ||||
| 
 | ||||
| namespace BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Validators; | ||||
| 
 | ||||
| public class VisaApplicationCreateRequestModelValidator : AbstractValidator<VisaApplicationCreateRequestModel> | ||||
| public class VisaApplicationCreateRequestValidator : AbstractValidator<VisaApplicationCreateRequestModel> | ||||
| { | ||||
|     public VisaApplicationCreateRequestModelValidator( | ||||
|     public VisaApplicationCreateRequestValidator( | ||||
|         IValidator<ReentryPermitModel?> reentryPermitModelValidator, | ||||
|         IValidator<PastVisaModel> pastVisaModelValidator, | ||||
|         IValidator<PermissionToDestCountryModel?> permissionToDestCountryModelValidator, | ||||
|         IValidator<PastVisitModel> pastVisitModelValidator) | ||||
|         IValidator<PastVisitModel> pastVisitModelValidator, | ||||
|         IUserDataProvider userDataProvider) | ||||
|     { | ||||
|         RuleFor(r => r.PermissionToDestCountry) | ||||
|             .NotEmpty() | ||||
| @@ -17,6 +20,13 @@ public class VisaApplicationCreateRequestModelValidator : AbstractValidator<Visa | ||||
|             .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 (_, _) => | ||||
|                 (await userDataProvider.GetApplicant()).IsNonResident); | ||||
| 
 | ||||
|         RuleFor(r => r.DestinationCountry) | ||||
|             .NotEmpty() | ||||
|             .WithMessage("Destination country can not be empty"); | ||||
		Reference in New Issue
	
	Block a user