@namespace OpenArchival.Blazor.AdminPages.Shared
@using OpenArchival.Blazor.AdminPages.Shared;
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.EntityFrameworkCore
@using MudBlazor
@using MudExtensions
@using OpenArchival.Blazor.ArchiveSearch
@using OpenArchival.DataAccess
@using Microsoft.AspNetCore.Identity
@layout AdminControlPanelLayout
New User
Edit
@inject IArtifactGroupingProvider GroupingProvider;
@inject IDialogService DialogService;
@inject IArtifactGroupingProvider GroupingProvider;
@inject IDbContextFactory ContextFactory;
@inject ISnackbar Snackbar;
@inject NavigationManager NavigationManager;
@inject UserManager UserManager;
@inject RoleManager RoleManager;
@inject IDbContextFactory ContextFactory;
@code
{
public class UserRowElementComparer: IEqualityComparer
{
public bool Equals(UserDto? x, UserDto? y)
{
if (ReferenceEquals(x, y)) return true;
if (x is null || y is null) return false;
return x.Id == y.Id;
}
public int GetHashCode(UserDto obj)
{
return obj.Id.GetHashCode();
}
}
private UserRowElementComparer _comparer = new();
public MudDataGrid DataGrid { get; set; } = default!;
private HashSet _selectedItems = new(new UserRowElementComparer());
private string _searchString { get; set; } = "";
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
StateHasChanged();
}
private async Task CreateNewUser(MouseEventArgs args)
{
var options = new DialogOptions { CloseOnEscapeKey = true, BackdropClick = false};
var dialog = await DialogService.ShowAsync("Create a User", options);
var newUserDto = await dialog.Result;
if (newUserDto is not null && !newUserDto.Canceled)
{
var userDto = (UserDto?)newUserDto.Data;
if (userDto is null)
{
Snackbar.Add("The new user dialog did not return a user model.", Severity.Error);
return;
}
if (userDto.Username is null)
{
Snackbar.Add("The user model returned by the dialog did not have a username set.");
return;
}
if (userDto.Password is null)
{
Snackbar.Add("The user model returned by the dialog did not have a password.", Severity.Error);
return;
}
var appUser = UserDto.ToApplicationUser(userDto);
if (appUser.Email is null)
{
Snackbar.Add("The application user converted from the DTO did not have an email");
return;
}
ApplicationUser? existing = await UserManager.FindByEmailAsync(appUser.Email);
if (existing is not null)
{
Snackbar.Add("A user with this email already exists!", Severity.Warning);
return;
}
appUser.EmailConfirmed = true; // Bypass email confirmation
IdentityResult result = await UserManager.CreateAsync(appUser, userDto.Password);
if (result.Succeeded)
{
IdentityResult roleResult = await UserManager.AddToRolesAsync(appUser, userDto.Roles);
if (!roleResult.Succeeded)
{
Snackbar.Add("Failed to set roles on user!", Severity.Error);
foreach (IdentityError error in roleResult.Errors)
{
Snackbar.Add(error.Description, Severity.Error);
}
}
Snackbar.Add("User created!", Severity.Success);
await DataGrid.ReloadServerData();
StateHasChanged();
return;
}
else
{
Snackbar.Add($"Failed to create user with errors, check logs. {result.Errors.ToString()}");
return;
}
}
}
private async Task OnEditClicked(UserDto row)
{
}
private async Task OnDeleteClicked(UserDto row)
{
// Check if we are trying to delete the last Admin user
// solution: https://stackoverflow.com/questions/20449008/count-the-number-of-users-in-a-role-in-aspnet-identity-not-membership
var context = await ContextFactory.CreateDbContextAsync();
IdentityRole adminRole = await context.Roles.FirstAsync(r => r.Name == UserRoles.Admin);
Int32 countAdminUsers = await context.Set().CountAsync();
if (countAdminUsers == 1)
{
Snackbar.Add("Cannot delete the only admin user!", Severity.Error);
return;
}
bool? confirmed = await DialogService.ShowMessageBox
(
new MessageBoxOptions(){
Message=$"Are you sure you want to delete this user?",
Title="Delete User?",
CancelText="Cancel",
YesText="Delete"
});
if (confirmed is not null)
{
// Grab the user from the database, ASP.NET identity will only allow you to
// delete the exact object from the database
if (row.Id is null)
{
Snackbar.Add("The user row ID was null, cannot delete", Severity.Error);
return;
}
ApplicationUser? appUser = await UserManager.FindByIdAsync(row.Id);
if (appUser is null)
{
Snackbar.Add("User no longer in database, cannot find by ID.", Severity.Error);
return;
}
IdentityResult result = await UserManager.DeleteAsync(appUser);
if (result.Succeeded)
{
await DataGrid.ReloadServerData();
StateHasChanged();
Snackbar.Add("User deleted!", Severity.Success);
} else
{
Snackbar.Add("Call to DeleteAsync failed.", Severity.Error);
foreach (var error in result.Errors)
{
Snackbar.Add(error.Description, Severity.Error);
}
}
}
}
private async Task> ServerReload(GridState state)
{
var context = await ContextFactory.CreateDbContextAsync();
int totalItems = await context.Users.CountAsync();
IEnumerable users = await context.Users
.Skip(state.Page * state.PageSize)
.Take(state.PageSize)
.Select(user=>new UserDto
{
Id = user.Id,
Username = user.UserName,
Roles = (from userRole in context.UserRoles
join role in context.Roles on userRole.RoleId equals role.Id
where userRole.UserId == user.Id
select role.Name).ToList()
}).ToListAsync();
return new GridData()
{
TotalItems = totalItems,
Items = users
};
}
public async Task> SelectedItems()
{
List selectedUsers = [];
foreach (UserDto row in DataGrid.SelectedItems)
{
await using var context = await ContextFactory.CreateDbContextAsync();
var user = await context.Users.Where(user => user.Id == row.Id).FirstAsync();
if (user is null)
{
Snackbar.Add($"User with id {row.Id} no longer exists in the database.", Severity.Error);
continue;
}
selectedUsers.Add(user);
}
return selectedUsers;
}
public async Task SetSelectedItemsAsync(IEnumerable postsToSelect)
{
var context = await ContextFactory.CreateDbContextAsync();
var rowElementsToSelect = postsToSelect.Select(user=> new UserDto
{
Id = user.Id,
Username = user.UserName,
Roles = (from userRole in context.UserRoles
join role in context.Roles on userRole.RoleId equals role.Id
select role.Name).ToList()
});
_selectedItems = new HashSet(rowElementsToSelect, _comparer);
_selectedItems = new HashSet();
StateHasChanged();
}
public void ClearSelected()
{
_selectedItems = new HashSet(_comparer);
}
}