list of authorities, changing authority auth data

This commit is contained in:
2024-09-12 21:14:30 +03:00
parent 18e02792ec
commit 9015348aa6
25 changed files with 442 additions and 175 deletions

View File

@@ -49,6 +49,20 @@
}
}
public void Logout()
{
Client.AuthToken = null;
AuthData = null;
try
{
UserDataProvider.UpdateCurrentRole();
}
catch (Exception e)
{
ErrorHandler.Handle(e);
}
}
///Re-auth if token expired or something
public async Task ReAuthenticate()
{

View File

@@ -20,21 +20,27 @@ namespace BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvide
public void UpdateCurrentRole()
{
var role = CurrentRole;
if (client.AuthToken is null)
{
CurrentRole = null;
return;
if (CurrentRole is not null)
{
role = null;
}
}
var token = tokenHandler.ReadJwtToken(client.AuthToken.Token);
var role = token.Claims.FirstOrDefault(claim => claim.Type == ClaimTypes.Role)?.Value;
switch (role)
else
{
case Constants.ApplicantRole: break;
case Constants.ApprovingAuthorityRole: break;
case Constants.AdminRole: break;
default: throw new UnknownRoleException();
var token = tokenHandler.ReadJwtToken(client.AuthToken.Token);
role = token.Claims.FirstOrDefault(claim => claim.Type == ClaimTypes.Role)?.Value;
switch (role)
{
case Constants.ApplicantRole: break;
case Constants.ApprovingAuthorityRole: break;
case Constants.AdminRole: break;
default: throw new UnknownRoleException();
}
}
if (CurrentRole != role)

View File

@@ -1,12 +1,41 @@
@inherits LayoutComponentBase
@using BlazorWebAssemblyVisaApiClient.Components.Auth
@using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu/>
</div>
<main>
<article class="content px-4 fullscreen">
<main class="fullscreen">
<div class="top-row px-4">
<AuthComponent @ref="authComponent"/>
@if (UserDataProvider.CurrentRole is not null)
{
<p>
Logged as @UserDataProvider.CurrentRole (@AuthComponent.AuthData?.Email)
<button class="btn-secondary" @onclick="authComponent.Logout">Log out</button>
</p>
}
else
{
<NavLink href="/">Log in</NavLink>
}
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
@code
{
private AuthComponent authComponent = null!;
[Inject] private IUserDataProvider UserDataProvider { get; set; } = null!;
protected override void OnInitialized()
{
UserDataProvider.OnRoleChanged += StateHasChanged;
}
}

View File

@@ -26,7 +26,7 @@
</div>
</nav>
}
@if(UserDataProvider.CurrentRole is Constants.ApplicantRole)
@if (UserDataProvider.CurrentRole is Constants.ApplicantRole)
{
<nav class="flex-column">
<div class="nav-item px-3">
@@ -36,6 +36,16 @@
</div>
</nav>
}
@if (UserDataProvider.CurrentRole is Constants.AdminRole)
{
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="authorities" Match="NavLinkMatch.All">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Authorities
</NavLink>
</div>
</nav>
}
</div>
@code {

View File

@@ -1,4 +1,5 @@
@page "/applications/{ApplicationId}"
@using System.Net
@using BlazorWebAssemblyVisaApiClient.Common.Exceptions
@using BlazorWebAssemblyVisaApiClient.Components
@using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers
@@ -210,6 +211,11 @@
}
catch (Exception e)
{
if (e is ApiException<ProblemDetails> { Result.Status: (int)HttpStatusCode.Conflict })
{
Nav.NavigateTo("/applications");
}
ErrorHandler.Handle(e);
}
}

View File

@@ -0,0 +1,42 @@
@page "/authorities"
@using VisaApiClient
@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Email</th><th></th>
</tr>
</thead>
<tbody>
@foreach (var authority in authorities)
{
var path = $"authorities/{authority.Id}/{authority.Email}";
<tr>
<td>@authority.Email</td>
<td>
<NavLink href="@path">
<button class="btn-outline-primary">Change</button>
</NavLink>
</td>
</tr>
}
</tbody>
</table>
@code {
private IEnumerable<UserModel> authorities = [];
protected override async Task OnInitializedAsync()
{
try
{
authorities = await Client.GetAuthorityAccountsAsync();
}
catch (Exception e)
{
ErrorHandler.Handle(e);
}
}
}

View File

@@ -0,0 +1,83 @@
@page "/authorities/{authorityId}/{oldEmail}"
@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase
@using BlazorWebAssemblyVisaApiClient.Common.Exceptions
@using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider
@using VisaApiClient
@using BlazorWebAssemblyVisaApiClient.Components
@using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers
@using FluentValidation
<EditForm Model="model" class="with-centered-content">
<div >
<label>
New email:<br/>
<InputText class="rounded" @bind-Value="model.Email"/>
</label><br/><p/>
<label>
New password (leave blank if shouldn't be changed):<br/>
<InputText class="rounded" @bind-Value="model.Password"/>
</label><br/><p/>
<button class="btn-primary rounded" @onclick="Save">Save</button><br/>
<Status @ref="status"/>
</div>
</EditForm>
@code
{
private Status status = null!;
private ChangeAuthData model = new();
[Parameter] public string AuthorityId { get; set; } = null!;
[Parameter] public string OldEmail { get; set; } = null!;
[Inject] private IUserDataProvider UserDataProvider { get; set; } = null!;
[Inject] private IValidator<ChangeUserAuthDataRequest> ChangeUserAuthDataRequestValidator { get; set; } = null!;
protected override void OnInitialized()
{
try
{
if (UserDataProvider.CurrentRole is not Constants.AdminRole)
{
throw new NotLoggedInException();
}
model.Email = OldEmail;
}
catch (Exception e)
{
ErrorHandler.Handle(e);
}
}
private async Task Save()
{
var request = new ChangeUserAuthDataRequest
{
UserId = Guid.Parse(AuthorityId),
NewAuthData = model
};
var validationResult = await ChangeUserAuthDataRequestValidator.ValidateAsync(request);
if (!validationResult.IsValid)
{
status.SetError(validationResult.ToErrorsString());
return;
}
try
{
status.SetMessage("Wait...");
await Client.ChangeAuthorityAuthDataAsync(request);
status.SetSuccess("Success");
}
catch (Exception e)
{
ErrorHandler.Handle(e);
}
}
}

View File

@@ -102,7 +102,7 @@
</label><br/>
<ValidationMessage For="() => editableVisa.ExpirationDate"></ValidationMessage><br/>
<input type="button" class="btn-outline-primary"
<input type="button" class="btn-outline-primary rounded"
disabled="@(requestModel.PastVisas.Count == ConfigurationConstraints.MaxPastVisas)"
@onclick="AddPastVisa" value="Add"/>
<Status @ref="pastVisaStatus"/>
@@ -157,7 +157,7 @@
</label><br/>
<ValidationMessage For="() => editableVisit.EndDate"></ValidationMessage><br/>
<input type="button" class="btn-outline-primary"
<input type="button" class="btn-outline-primary rounded"
disabled="@(requestModel.PastVisits.Count == ConfigurationConstraints.MaxPastVisits)"
@onclick="AddPastVisit" value="Add"/>
<Status @ref="pastVisitStatus"/>
@@ -185,7 +185,7 @@
</div>
}
<br/><input type="submit" class="btn-outline-primary" value="Register"/>
<br/><input type="submit" class="btn-outline-primary rounded" value="Register"/>
<ValidationSummary/>
<Status @ref="status"/>
</EditForm>

View File

@@ -1,7 +1,7 @@
using FluentValidation;
using VisaApiClient;
namespace BlazorWebAssemblyVisaApiClient.Validation.Common;
namespace BlazorWebAssemblyVisaApiClient.Validation.Auth;
public class AuthDataValidator : AbstractValidator<AuthData>
{

View File

@@ -0,0 +1,21 @@
using FluentValidation;
using VisaApiClient;
namespace BlazorWebAssemblyVisaApiClient.Validation.Auth
{
public class ChangeUserAuthDataRequestValidator : AbstractValidator<ChangeUserAuthDataRequest>
{
public ChangeUserAuthDataRequestValidator()
{
RuleFor(r => r.NewAuthData)
.NotEmpty();
RuleFor(r => r.NewAuthData.Email)
.NotEmpty()
.EmailAddress()
.WithMessage("Email should be valid")
.MaximumLength(ConfigurationConstraints.EmailLength)
.WithMessage($"Email address length must be less than {ConfigurationConstraints.EmailLength}");
}
}
}

View File

@@ -2,7 +2,7 @@
using FluentValidation;
using VisaApiClient;
namespace BlazorWebAssemblyVisaApiClient.Validation.Common;
namespace BlazorWebAssemblyVisaApiClient.Validation.Auth;
public class RegisterRequestValidator : AbstractValidator<RegisterRequestModel>
{