fix #4965 - improve user/site management

This commit is contained in:
sbwalker
2025-01-21 12:21:27 -05:00
parent 4793ab4bc9
commit 16477052e2
10 changed files with 187 additions and 105 deletions

View File

@ -58,7 +58,7 @@ else
<td>@context.EffectiveDate</td>
<td>@context.ExpiryDate</td>
<td>
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
</td>
</Row>
</Pager>
@ -180,27 +180,28 @@ else
private async Task DeleteUserRole(int UserRoleId)
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
try
{
try
var userrole = await UserRoleService.GetUserRoleAsync(UserRoleId);
if (userrole.Role.Name == RoleNames.Registered)
{
userrole.ExpiryDate = DateTime.UtcNow;
await UserRoleService.UpdateUserRoleAsync(userrole);
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
else
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
AddModuleMessage(Localizer["Confirm.User.RoleRemoved"], MessageType.Success);
await GetUserRoles();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error);
await logger.LogInformation("User {Username} Removed From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
AddModuleMessage(Localizer["Confirm.User.RoleRemoved"], MessageType.Success);
await GetUserRoles();
StateHasChanged();
}
else
catch (Exception ex)
{
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error);
}
}
}

View File

@ -51,15 +51,18 @@
<input id="displayname" class="form-control" @bind="@displayname" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
<div class="col-sm-9">
<select id="isdeleted" class="form-select" @bind="@isdeleted">
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
<div class="col-sm-9">
<select id="isdeleted" class="form-select" @bind="@isdeleted">
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
}
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="lastlogin" HelpText="The date and time when the user last signed in" ResourceKey="LastLogin"></Label>
<div class="col-sm-9">
@ -127,8 +130,11 @@
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && isdeleted == "True")
{
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
}
<br /><br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@ -226,8 +232,10 @@
user.Password = _password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
}
user = await UserService.UpdateUserAsync(user);
if (user != null)
@ -259,6 +267,25 @@
}
}
private async Task DeleteUser()
{
try
{
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && userid != PageState.User.UserId)
{
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
await logger.LogInformation("User Permanently Deleted {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Permanently Deleting User {UserId} {Error}", userid, ex.Message);
AddModuleMessage(Localizer["Error.DeleteUser"], MessageType.Error);
}
}
private bool ValidateProfiles()
{
foreach (Profile profile in profiles)

View File

@ -35,7 +35,7 @@ else
<ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
</td>
<td>
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId || context.User.IsDeleted)" ResourceKey="DeleteUser" />
</td>
<td>
<ActionLink Action="Roles" Text="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
@ -611,19 +611,31 @@ else
{
try
{
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
if (user != null)
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
await logger.LogInformation("User Deleted {User}", UserRole.User);
await LoadUsersAsync(true);
StateHasChanged();
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
if (user != null)
{
user.IsDeleted = true;
await UserService.UpdateUserAsync(user);
await logger.LogInformation("User Soft Deleted {User}", user);
}
}
else
{
var userrole = await UserRoleService.GetUserRoleAsync(UserRole.UserRoleId);
userrole.ExpiryDate = DateTime.UtcNow;
await UserRoleService.UpdateUserRoleAsync(userrole);
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
AddModuleMessage(Localizer["Success.DeleteUser"], MessageType.Success);
await LoadUsersAsync(true);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting User {User} {Error}", UserRole.User, ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
AddModuleMessage(Localizer["Error.DeleteUser"], MessageType.Error);
}
}

View File

@ -53,17 +53,17 @@ else
<p align="center">
<Pager Items="@userroles">
<Header>
<th>@Localizer["Roles"]</th>
<th>@Localizer["Effective"]</th>
<th>@Localizer["Expiry"]</th>
<th>&nbsp;</th>
<th>@Localizer["Roles"]</th>
<th>@Localizer["Effective"]</th>
<th>@Localizer["Expiry"]</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.Role.Name</td>
<td>@Utilities.UtcAsLocalDate(context.EffectiveDate)</td>
<td>@Utilities.UtcAsLocalDate(context.ExpiryDate)</td>
<td>
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" />
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.Name == RoleNames.Host && userid == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
</td>
</Row>
</Pager>
@ -171,8 +171,18 @@ else
{
try
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
var userrole = await UserRoleService.GetUserRoleAsync(UserRoleId);
if (userrole.Role.Name == RoleNames.Registered)
{
userrole.ExpiryDate = DateTime.UtcNow;
await UserRoleService.UpdateUserRoleAsync(userrole);
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
else
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await logger.LogInformation("User {Username} Removed From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
AddModuleMessage(Localizer["Success.User.Remove"], MessageType.Success);
await GetUserRoles();
StateHasChanged();