Extract workspace admin coordinator
This commit is contained in:
@@ -186,93 +186,11 @@ public partial class Workspace : IAsyncDisposable
|
||||
return SwitchScreenAsync(ScreenAdmin);
|
||||
}
|
||||
|
||||
private async Task EnsureAdminUsersLoadedAsync()
|
||||
{
|
||||
if (!IsCurrentUserAdmin || HasLoadedAdminUsers || IsAdminDataLoading)
|
||||
return;
|
||||
private Task EnsureAdminUsersLoadedAsync() => Admin.EnsureAdminUsersLoadedAsync();
|
||||
|
||||
IsAdminDataLoading = true;
|
||||
try
|
||||
{
|
||||
await ReloadAdminUsersAsync();
|
||||
}
|
||||
catch (ApiRequestException ex) when (ex.StatusCode == 401)
|
||||
{
|
||||
ClearAuthenticatedState();
|
||||
await StopStateEventsAsync();
|
||||
await LoggedOut.InvokeAsync("Session expired. Please log in again.");
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
SetStatus(ex.Message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsAdminDataLoading = false;
|
||||
}
|
||||
}
|
||||
private Task ToggleAdminRoleAsync(AdminUserSummary user) => Admin.ToggleAdminRoleAsync(user);
|
||||
|
||||
private async Task ReloadAdminUsersAsync()
|
||||
{
|
||||
AdminUsers = (await WorkspaceQuery.GetAdminUsersAsync())
|
||||
.OrderBy(user => user.Username, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
HasLoadedAdminUsers = true;
|
||||
}
|
||||
|
||||
private async Task ToggleAdminRoleAsync(AdminUserSummary user)
|
||||
{
|
||||
if (IsMutating || User is null || !IsCurrentUserAdmin || user.Id == User.Id)
|
||||
return;
|
||||
|
||||
IsMutating = true;
|
||||
try
|
||||
{
|
||||
IReadOnlyList<string> roles = HasAdminRole(user) ? Array.Empty<string>() : [UserRoles.Admin];
|
||||
_ = await ApiClient.RequestAsync<AdminUserSummary>(
|
||||
"PUT",
|
||||
$"/api/admin/users/{user.Id}/roles",
|
||||
new UpdateUserRolesRequest(roles));
|
||||
|
||||
await ReloadAdminUsersAsync();
|
||||
SetStatus("User roles updated.", false);
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
SetStatus(ex.Message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsMutating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteUserAsync(AdminUserSummary user)
|
||||
{
|
||||
if (IsMutating || User is null || !IsCurrentUserAdmin || user.Id == User.Id)
|
||||
return;
|
||||
|
||||
var confirmed = await JS.InvokeAsync<bool>("confirm", $"Delete user '{user.Username}'?");
|
||||
if (!confirmed)
|
||||
return;
|
||||
|
||||
IsMutating = true;
|
||||
try
|
||||
{
|
||||
_ = await ApiClient.RequestAsync<bool>("DELETE", $"/api/admin/users/{user.Id}");
|
||||
await ReloadAdminUsersAsync();
|
||||
SetStatus("User deleted.", false);
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
SetStatus(ex.Message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsMutating = false;
|
||||
}
|
||||
}
|
||||
private Task DeleteUserAsync(AdminUserSummary user) => Admin.DeleteUserAsync(user);
|
||||
|
||||
private async Task SetMobilePanelAsync(string panel)
|
||||
{
|
||||
@@ -970,14 +888,18 @@ public partial class Workspace : IAsyncDisposable
|
||||
private bool CanDeleteSelectedCampaign => State.CanDeleteSelectedCampaign;
|
||||
private bool IsSelectedCampaignD6 => State.IsSelectedCampaignD6;
|
||||
|
||||
private static bool HasAdminRole(AdminUserSummary user)
|
||||
{
|
||||
return user.Roles.Contains(UserRoles.Admin, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private bool IsPlayScreen => State.IsPlayScreen;
|
||||
private bool IsManagementScreen => State.IsManagementScreen;
|
||||
private bool IsAdminScreen => State.IsAdminScreen;
|
||||
private WorkspaceAdminCoordinator Admin => m_Admin ??= new(
|
||||
State,
|
||||
Feedback,
|
||||
JS,
|
||||
ApiClient,
|
||||
WorkspaceQuery,
|
||||
ClearAuthenticatedState,
|
||||
StopStateEventsAsync,
|
||||
message => LoggedOut.InvokeAsync(message));
|
||||
private WorkspaceFeedbackService Feedback => m_Feedback ??= new(State, () => InvokeAsync(StateHasChanged));
|
||||
private WorkspaceSessionCoordinator Session => m_Session ??= new(
|
||||
State,
|
||||
@@ -1021,6 +943,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
private const string MobilePanelSessionKey = "play-panel";
|
||||
private const int CampaignLogWindowSize = 25;
|
||||
|
||||
private WorkspaceAdminCoordinator? m_Admin;
|
||||
private WorkspaceFeedbackService? m_Feedback;
|
||||
private WorkspaceSessionCoordinator? m_Session;
|
||||
}
|
||||
|
||||
132
RpgRoller/Components/Pages/WorkspaceAdminCoordinator.cs
Normal file
132
RpgRoller/Components/Pages/WorkspaceAdminCoordinator.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.JSInterop;
|
||||
using RpgRoller.Contracts;
|
||||
using RpgRoller.Domain;
|
||||
|
||||
namespace RpgRoller.Components.Pages;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
public sealed class WorkspaceAdminCoordinator
|
||||
{
|
||||
public WorkspaceAdminCoordinator(
|
||||
WorkspaceState state,
|
||||
WorkspaceFeedbackService feedback,
|
||||
IJSRuntime js,
|
||||
RpgRollerApiClient apiClient,
|
||||
WorkspaceQueryService workspaceQuery,
|
||||
Action clearAuthenticatedState,
|
||||
Func<Task> stopStateEventsAsync,
|
||||
Func<string?, Task> onLoggedOutAsync)
|
||||
{
|
||||
m_State = state;
|
||||
m_Feedback = feedback;
|
||||
m_JS = js;
|
||||
m_ApiClient = apiClient;
|
||||
m_WorkspaceQuery = workspaceQuery;
|
||||
m_ClearAuthenticatedState = clearAuthenticatedState;
|
||||
m_StopStateEventsAsync = stopStateEventsAsync;
|
||||
m_OnLoggedOutAsync = onLoggedOutAsync;
|
||||
}
|
||||
|
||||
public async Task EnsureAdminUsersLoadedAsync()
|
||||
{
|
||||
if (!m_State.IsCurrentUserAdmin || m_State.HasLoadedAdminUsers || m_State.IsAdminDataLoading)
|
||||
return;
|
||||
|
||||
m_State.IsAdminDataLoading = true;
|
||||
try
|
||||
{
|
||||
await ReloadAdminUsersAsync();
|
||||
}
|
||||
catch (ApiRequestException ex) when (ex.StatusCode == 401)
|
||||
{
|
||||
m_ClearAuthenticatedState();
|
||||
await m_StopStateEventsAsync();
|
||||
await m_OnLoggedOutAsync("Session expired. Please log in again.");
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
m_Feedback.SetStatus(ex.Message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_State.IsAdminDataLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ToggleAdminRoleAsync(AdminUserSummary user)
|
||||
{
|
||||
if (m_State.IsMutating || m_State.User is null || !m_State.IsCurrentUserAdmin || user.Id == m_State.User.Id)
|
||||
return;
|
||||
|
||||
m_State.IsMutating = true;
|
||||
try
|
||||
{
|
||||
IReadOnlyList<string> roles = HasAdminRole(user) ? Array.Empty<string>() : [UserRoles.Admin];
|
||||
_ = await m_ApiClient.RequestAsync<AdminUserSummary>(
|
||||
"PUT",
|
||||
$"/api/admin/users/{user.Id}/roles",
|
||||
new UpdateUserRolesRequest(roles));
|
||||
|
||||
await ReloadAdminUsersAsync();
|
||||
m_Feedback.SetStatus("User roles updated.", false);
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
m_Feedback.SetStatus(ex.Message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_State.IsMutating = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteUserAsync(AdminUserSummary user)
|
||||
{
|
||||
if (m_State.IsMutating || m_State.User is null || !m_State.IsCurrentUserAdmin || user.Id == m_State.User.Id)
|
||||
return;
|
||||
|
||||
var confirmed = await m_JS.InvokeAsync<bool>("confirm", $"Delete user '{user.Username}'?");
|
||||
if (!confirmed)
|
||||
return;
|
||||
|
||||
m_State.IsMutating = true;
|
||||
try
|
||||
{
|
||||
_ = await m_ApiClient.RequestAsync<bool>("DELETE", $"/api/admin/users/{user.Id}");
|
||||
await ReloadAdminUsersAsync();
|
||||
m_Feedback.SetStatus("User deleted.", false);
|
||||
}
|
||||
catch (ApiRequestException ex)
|
||||
{
|
||||
m_Feedback.SetStatus(ex.Message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_State.IsMutating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReloadAdminUsersAsync()
|
||||
{
|
||||
m_State.AdminUsers = (await m_WorkspaceQuery.GetAdminUsersAsync())
|
||||
.OrderBy(user => user.Username, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
m_State.HasLoadedAdminUsers = true;
|
||||
}
|
||||
|
||||
private static bool HasAdminRole(AdminUserSummary user)
|
||||
{
|
||||
return user.Roles.Contains(UserRoles.Admin, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private readonly RpgRollerApiClient m_ApiClient;
|
||||
private readonly Action m_ClearAuthenticatedState;
|
||||
private readonly WorkspaceFeedbackService m_Feedback;
|
||||
private readonly IJSRuntime m_JS;
|
||||
private readonly Func<string?, Task> m_OnLoggedOutAsync;
|
||||
private readonly WorkspaceState m_State;
|
||||
private readonly Func<Task> m_StopStateEventsAsync;
|
||||
private readonly WorkspaceQueryService m_WorkspaceQuery;
|
||||
}
|
||||
Reference in New Issue
Block a user