From 1f050a6fd4577be65945452f91c739c89b9402d3 Mon Sep 17 00:00:00 2001 From: prtsie Date: Sun, 1 Sep 2024 19:30:28 +0300 Subject: [PATCH] Auth and error handling components --- .../BlazorWebAssemblyVisaApiClient/App.razor | 28 ++++---- .../Common/BlazorClientException.cs | 4 ++ .../Components/Auth/AuthComponent.razor | 67 +++++++++++++++++++ .../Auth/Exceptions/NotLoggedInException.cs | 7 ++ .../Base/VisaClientComponentBase.razor | 9 +++ .../Components/Status.razor | 34 ++++++++++ .../ErrorHandling/GlobalErrorHandler.razor | 14 ++++ .../Pages/Auth.razor | 23 ++----- .../Pages/Register.razor | 48 +++++-------- 9 files changed, 174 insertions(+), 60 deletions(-) create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Common/BlazorClientException.cs create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/Exceptions/NotLoggedInException.cs create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Base/VisaClientComponentBase.razor create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Status.razor create mode 100644 SchengenVisaApi/BlazorWebAssemblyVisaApiClient/ErrorHandling/GlobalErrorHandler.razor diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/App.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/App.razor index a8cf817..b965270 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/App.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/App.razor @@ -1,12 +1,16 @@ - - - - - - - Not found - -

Sorry, there's nothing at this address.

-
-
-
+@using BlazorWebAssemblyVisaApiClient.ErrorHandling + + + + + + + + + Not found + +

Sorry, there's nothing at this address.

+
+
+
+
diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Common/BlazorClientException.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Common/BlazorClientException.cs new file mode 100644 index 0000000..94264ad --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Common/BlazorClientException.cs @@ -0,0 +1,4 @@ +namespace BlazorWebAssemblyVisaApiClient.Common +{ + public class BlazorClientException(string message) : Exception(message); +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor new file mode 100644 index 0000000..79947a1 --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/AuthComponent.razor @@ -0,0 +1,67 @@ +@using System.Net +@using BlazorWebAssemblyVisaApiClient.Components.Auth.Exceptions +@using BlazorWebAssemblyVisaApiClient.ErrorHandling +@using VisaApiClient + +@code { + public static bool LoggedIn; + private static AuthData savedData = null!; + + [CascadingParameter] private GlobalErrorHandler ErrorHandler { get; set; } = null!; + + [CascadingParameter] private Status? Status { get; set; } + + [Inject] private Client Client { get; set; } = null!; + + [Inject] private NavigationManager Nav { get; set; } = null!; + + ///Authorize with email and password + /// Message to user + public async Task TryAuthorize(AuthData authData) + { + Status?.SetMessage("Wait..."); + try + { + var token = await Client.LoginAsync(authData.Email, authData.Password); + Client.SetAuthToken(token); + savedData = authData; + + Status?.SetSucces("Logged in successfully."); + } + catch (ApiException e) + { + if (e.Result.Status == (int)HttpStatusCode.Forbidden) + { + Status?.SetError(e.Result.Detail!); + } + else + { + Status?.SetError("Error occured"); + ErrorHandler.Handle(e); + } + } + catch (Exception e) + { + Status?.SetError("Error occured"); + ErrorHandler.Handle(e); + } + } + + ///Re-auth if token expired or something + public async Task ReAuthenticate(bool redirectOnFailure = true) + { + if (!LoggedIn) + { + if (redirectOnFailure) + { + Nav.NavigateTo("/"); + return; + } + + throw new NotLoggedInException(); + } + + await TryAuthorize(savedData); + } + +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/Exceptions/NotLoggedInException.cs b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/Exceptions/NotLoggedInException.cs new file mode 100644 index 0000000..4346983 --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Auth/Exceptions/NotLoggedInException.cs @@ -0,0 +1,7 @@ +using BlazorWebAssemblyVisaApiClient.Common; +using VisaApiClient; + +namespace BlazorWebAssemblyVisaApiClient.Components.Auth.Exceptions +{ + public class NotLoggedInException() : BlazorClientException("User is not logged in"); +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Base/VisaClientComponentBase.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Base/VisaClientComponentBase.razor new file mode 100644 index 0000000..99d7312 --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Base/VisaClientComponentBase.razor @@ -0,0 +1,9 @@ +@using BlazorWebAssemblyVisaApiClient.ErrorHandling +@using VisaApiClient + +@code +{ + [CascadingParameter] protected GlobalErrorHandler ErrorHandler { get; set; } = null!; + + [Inject] protected Client Client { get; set; } = null!; +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Status.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Status.razor new file mode 100644 index 0000000..fb92472 --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Components/Status.razor @@ -0,0 +1,34 @@ +

@((MarkupString)StatusText)

+ + @ChildContent + + +@code { + private string statusClass = string.Empty; + + [Parameter] + public RenderFragment? ChildContent { get; set; } + + public string StatusText { get; set; } = string.Empty; + + public void SetMessage(string message) + { + statusClass = string.Empty; + StatusText = message; + StateHasChanged(); + } + + public void SetError(string message) + { + statusClass = "validation-message"; + StatusText = message; + StateHasChanged(); + } + + public void SetSucces(string message) + { + statusClass = "text-success"; + StatusText = message; + StateHasChanged(); + } +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/ErrorHandling/GlobalErrorHandler.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/ErrorHandling/GlobalErrorHandler.razor new file mode 100644 index 0000000..cd8bbc8 --- /dev/null +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/ErrorHandling/GlobalErrorHandler.razor @@ -0,0 +1,14 @@ + + @ChildContent + + +@code +{ + [Parameter] + public RenderFragment? ChildContent { get; set; } + + public void Handle(Exception ex) + { + + } +} diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Auth.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Auth.razor index 9fcbcac..11208ab 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Auth.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Auth.razor @@ -1,6 +1,10 @@ @page "/" +@using System.Net +@using BlazorWebAssemblyVisaApiClient.Components.Auth @using VisaApiClient @using BlazorWebAssemblyVisaApiClient.Components.FormComponents.Applicants +@using BlazorWebAssemblyVisaApiClient.Components +@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase Authentication @@ -13,30 +17,17 @@ or Register -

@loginResult

+ @code { private AuthData loginData = new(); - private string loginResult = string.Empty; - - [Inject] private Client Client { get; set; } = null!; + private AuthComponent auth = null!; private async Task TryLogin() { - loginResult = "Wait..."; - StateHasChanged(); - try - { - var token = await Client.LoginAsync(loginData.Email, loginData.Password); - Client.SetAuthToken(token); - loginResult = "Logged in successfully."; - } - catch (ApiException e) - { - loginResult = e.Result.Detail!; - } + await auth.TryAuthorize(loginData); } } diff --git a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor index 454bac2..c195c19 100644 --- a/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor +++ b/SchengenVisaApi/BlazorWebAssemblyVisaApiClient/Pages/Register.razor @@ -9,6 +9,8 @@ @using global::FluentValidation @using Newtonsoft.Json @using Newtonsoft.Json.Linq +@using BlazorWebAssemblyVisaApiClient.Components +@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase Registration @@ -122,17 +124,14 @@
-

@((MarkupString)requestResult)

+ @code { private RegisterApplicantRequestModel requestModel = new(); - private string requestResult = string.Empty; - private string requestResultClass = string.Empty; - - [Inject] public Client Client { get; set; } = null!; + private Status status = null!; [Inject] IValidator RegisterApplicantRequestValidator { get; set; } = null!; @@ -145,27 +144,6 @@ requestModel.BirthDate = DateTime.Now; } - private void SetRequestResultMessage(string message) - { - requestResult = message; - requestResultClass = string.Empty; - StateHasChanged(); - } - - private void SetRequestResultSuccess(string message) - { - requestResult = message; - requestResultClass = "text-success"; - StateHasChanged(); - } - - private void SetRequestResultError(string message) - { - requestResult = message; - requestResultClass = "validation-message"; - StateHasChanged(); - } - private string ErrorsToString(IEnumerable errors) { var stringBuilder = new StringBuilder(); @@ -183,18 +161,18 @@ if (!validationResult.IsValid) { var errorsString = ErrorsToString(validationResult.Errors.Select(e => e.ErrorMessage)); - SetRequestResultError(errorsString); + status.SetError(errorsString); return; } - SetRequestResultMessage("Wait..."); + status.SetMessage("Wait..."); var request = Mapper.Map(requestModel); try { await Client.RegisterAsync(request); - SetRequestResultSuccess("Register successful. Now log in."); + status.SetSucces("Register successful. Now log in."); } catch (ApiException e) { @@ -204,15 +182,21 @@ var errorsList = ((JArray)errors).ToObject>(); if (errorsList is null) { - throw new JsonException(); + ErrorHandler.Handle(new JsonException("Can't convert validation errors to list")); + + return; } - SetRequestResultError(ErrorsToString(errorsList)); + status.SetError(ErrorsToString(errorsList)); } else { - SetRequestResultError(e.Result.Detail!); + ErrorHandler.Handle(e); } } + catch (Exception e) + { + ErrorHandler.Handle(e); + } } }