924 lines
36 KiB
Plaintext
924 lines
36 KiB
Plaintext
@page "/Account/Rolemanager"
|
|
|
|
@rendermode InteractiveServer
|
|
@attribute [Authorize]
|
|
|
|
@using Microsoft.AspNetCore.Authorization
|
|
@using MudBlazor
|
|
@using System.Net.Http.Json
|
|
@using Microsoft.AspNetCore.Identity
|
|
@using Microsoft.AspNetCore.Components
|
|
@using RobotNet.IdentityServer.Data
|
|
@using Microsoft.EntityFrameworkCore
|
|
@using System.Threading
|
|
|
|
@inherits LayoutComponentBase
|
|
|
|
@inject AuthenticationStateProvider AuthenticationStateProvider
|
|
@inject UserManager<ApplicationUser> UserManager
|
|
@inject RoleManager<ApplicationRole> RoleManager
|
|
@inject ISnackbar Snackbar
|
|
@inject IDialogService DialogService
|
|
@inject NavigationManager NavigationManager
|
|
|
|
|
|
<MudDialogProvider />
|
|
<MudSnackbarProvider />
|
|
|
|
<div class="pa-4">
|
|
<div class="role-header">
|
|
<MudGrid>
|
|
<MudItem xs="12" md="8">
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@Icons.Material.Filled.AdminPanelSettings" Size="Size.Large" Class="mr-3" />
|
|
<div>
|
|
<MudText Typo="Typo.h4" Class="mb-1">Role Management</MudText>
|
|
<MudText Typo="Typo.body1" Style="opacity: 0.9;">Quản lý vai trò và phân quyền người dùng</MudText>
|
|
</div>
|
|
</div>
|
|
</MudItem>
|
|
<MudItem xs="12" md="4" Class="text-right">
|
|
<div class="stats-card">
|
|
<MudText Typo="Typo.h5">@Roles.Count</MudText>
|
|
<MudText Typo="Typo.body2">Tổng số vai trò</MudText>
|
|
</div>
|
|
</MudItem>
|
|
</MudGrid>
|
|
</div>
|
|
|
|
<MudGrid>
|
|
<MudItem xs="12" lg="4">
|
|
<MudPaper Class="modern-card pa-4" Elevation="0">
|
|
<div class="section-title">
|
|
<MudIcon Icon="@Icons.Material.Filled.Security" />
|
|
<MudText Typo="Typo.h6">Danh Sách Vai Trò</MudText>
|
|
</div>
|
|
|
|
<div class="search-container mb-3">
|
|
<MudTextField @bind-Value="roleSearchTerm"
|
|
Label="Tìm kiếm vai trò"
|
|
Variant="Variant.Outlined"
|
|
Adornment="Adornment.Start"
|
|
AdornmentIcon="@Icons.Material.Filled.Search"
|
|
Margin="Margin.Dense"
|
|
FullWidth="true" />
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Primary"
|
|
StartIcon="@Icons.Material.Filled.Add"
|
|
OnClick="AddRole"
|
|
Class="action-button"
|
|
FullWidth="true">
|
|
Tạo Vai Trò Mới
|
|
</MudButton>
|
|
</div>
|
|
|
|
<div class="table-container">
|
|
<MudTable Items="@FilteredRoles" Hover="true" Dense="true" Striped="true">
|
|
<HeaderContent>
|
|
<MudTh><MudText Typo="Typo.subtitle2">Tên Vai Trò</MudText></MudTh>
|
|
<MudTh Style="width: 100px;"><MudText Typo="Typo.subtitle2">Thao Tác</MudText></MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd>
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@GetRoleIcon(context.Name ?? string.Empty)" Size="Size.Small" Class="mr-2" Color="@GetRoleColor(context.Name ?? string.Empty)" />
|
|
<MudText Typo="Typo.body2">@context.Name</MudText>
|
|
</div>
|
|
</MudTd>
|
|
<MudTd>
|
|
@if (LoggedInUserRoles.Contains(context.Name ?? string.Empty))
|
|
{
|
|
<MudTooltip Text="Vai trò không thể chỉnh sửa ">
|
|
<MudIconButton Icon="@Icons.Material.Filled.Lock"
|
|
Size="Size.Small"
|
|
Color="Color.Default"
|
|
Disabled="true" />
|
|
</MudTooltip>
|
|
}
|
|
else
|
|
{
|
|
<MudTooltip Text="Chỉnh sửa">
|
|
<MudIconButton Icon="@Icons.Material.Filled.Edit"
|
|
Size="Size.Small"
|
|
Color="Color.Primary"
|
|
OnClick="() => EditRole(context)"
|
|
Class="action-button mr-1" />
|
|
</MudTooltip>
|
|
<MudTooltip Text="Xóa">
|
|
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
|
Size="Size.Small"
|
|
Color="Color.Error"
|
|
OnClick="() => DelRole(context.Id, context.Name ?? string.Empty)"
|
|
Class="action-button" />
|
|
</MudTooltip>
|
|
}
|
|
</MudTd>
|
|
</RowTemplate>
|
|
<PagerContent>
|
|
<MudTablePager PageSizeOptions="new int[] { 5, 10, 25, 50, 100, int.MaxValue }"
|
|
RowsPerPageString="@rowsPerPageString" />
|
|
</PagerContent>
|
|
</MudTable>
|
|
</div>
|
|
</MudPaper>
|
|
</MudItem>
|
|
|
|
|
|
<MudItem xs="12" lg="8">
|
|
<MudPaper Class="modern-card pa-4" Elevation="0">
|
|
<div class="section-title">
|
|
<MudIcon Icon="@Icons.Material.Filled.People" />
|
|
<MudText Typo="Typo.h6">Quản Lý Người Dùng</MudText>
|
|
</div>
|
|
|
|
<div class="search-container mb-3">
|
|
<MudTextField @bind-Value="userSearchTerm"
|
|
Label="Tìm kiếm người dùng"
|
|
Variant="Variant.Outlined"
|
|
Adornment="Adornment.Start"
|
|
AdornmentIcon="@Icons.Material.Filled.Search"
|
|
Margin="Margin.Dense"
|
|
FullWidth="true" />
|
|
</div>
|
|
|
|
<div class="table-container">
|
|
<MudTable Items="@FilteredUsers" Hover="true" Dense="true" Striped="true">
|
|
<HeaderContent>
|
|
<MudTh><MudText Typo="Typo.subtitle2">Người Dùng</MudText></MudTh>
|
|
<MudTh><MudText Typo="Typo.subtitle2">Vai Trò</MudText></MudTh>
|
|
<MudTh Style="width: 100px;"><MudText Typo="Typo.subtitle2">Thao Tác</MudText></MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd>
|
|
<div class="d-flex align-center">
|
|
<div class="user-avatar">
|
|
@(context.UserName?.Substring(0, 1).ToUpper())
|
|
</div>
|
|
<div>
|
|
<MudText Typo="Typo.body2" Class="font-weight-medium">@context.UserName</MudText>
|
|
@if (context.UserId == LoggedInUserId)
|
|
{
|
|
<MudChip T="string"
|
|
Size="Size.Small"
|
|
Color="Color.Info"
|
|
Class="mt-1">
|
|
Bạn
|
|
</MudChip>
|
|
}
|
|
</div>
|
|
</div>
|
|
</MudTd>
|
|
<MudTd>
|
|
<div class="d-flex flex-wrap">
|
|
@if (context.Roles.Any())
|
|
{
|
|
foreach (var role in context.Roles)
|
|
{
|
|
<MudChip T="string"
|
|
Size="Size.Small"
|
|
Color="@GetRoleChipColor(role)"
|
|
Icon="@GetRoleIcon(role)"
|
|
Class="role-chip">
|
|
@role
|
|
</MudChip>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<MudChip T="string"
|
|
Size="Size.Small"
|
|
Color="Color.Default"
|
|
Class="role-chip">
|
|
Chưa có vai trò
|
|
</MudChip>
|
|
}
|
|
</div>
|
|
</MudTd>
|
|
<MudTd>
|
|
@if (context.UserId == LoggedInUserId)
|
|
{
|
|
<MudTooltip Text="Không thể chỉnh sửa vai trò của chính mình">
|
|
<MudIconButton Icon="@Icons.Material.Filled.Lock"
|
|
Size="Size.Small"
|
|
Color="Color.Default"
|
|
Disabled="true" />
|
|
</MudTooltip>
|
|
}
|
|
else
|
|
{
|
|
<MudTooltip Text="Quản lý vai trò">
|
|
<MudIconButton Icon="@Icons.Material.Filled.ManageAccounts"
|
|
Size="Size.Small"
|
|
Color="Color.Primary"
|
|
OnClick="() => ManageUserRoles(context.UserId ?? string.Empty, context.UserName ?? string.Empty)"
|
|
Class="action-button" />
|
|
</MudTooltip>
|
|
}
|
|
</MudTd>
|
|
</RowTemplate>
|
|
<PagerContent>
|
|
<MudTablePager PageSizeOptions="new int[] { 5, 10, 25, 50, 100, int.MaxValue }" />
|
|
</PagerContent>
|
|
</MudTable>
|
|
</div>
|
|
</MudPaper>
|
|
</MudItem>
|
|
</MudGrid>
|
|
</div>
|
|
|
|
|
|
<MudDialog @bind-Visible="CreateRoleVisible">
|
|
<TitleContent>
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@Icons.Material.Filled.Add" Class="mr-3" />
|
|
<MudText Typo="Typo.h6">Tạo Vai Trò Mới</MudText>
|
|
</div>
|
|
</TitleContent>
|
|
<DialogContent>
|
|
<MudTextField Label="Tên vai trò"
|
|
@bind-Value="NewRoleName"
|
|
Required="true"
|
|
Variant="Variant.Outlined"
|
|
FullWidth="true"
|
|
Margin="Margin.Dense"
|
|
Style="overflow:hidden;" />
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<MudButton Color="Color.Primary"
|
|
Variant="Variant.Filled"
|
|
OnClick="CreateRole"
|
|
StartIcon="@Icons.Material.Filled.Save">
|
|
Tạo
|
|
</MudButton>
|
|
<MudButton Variant="Variant.Text"
|
|
OnClick="@(() => CreateRoleVisible = false)">
|
|
Hủy
|
|
</MudButton>
|
|
</DialogActions>
|
|
</MudDialog>
|
|
|
|
|
|
<MudDialog @bind-Visible="EditRoleVisible">
|
|
<TitleContent>
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@Icons.Material.Filled.Edit" Class="mr-3" />
|
|
<MudText Typo="Typo.h6">Chỉnh Sửa Vai Trò</MudText>
|
|
</div>
|
|
</TitleContent>
|
|
<DialogContent>
|
|
<MudTextField Label="Tên vai trò mới"
|
|
@bind-Value="EditRoleName"
|
|
Required="true"
|
|
Variant="Variant.Outlined"
|
|
FullWidth="true"
|
|
Margin="Margin.Dense" />
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<MudButton Color="Color.Primary"
|
|
Variant="Variant.Filled"
|
|
OnClick="SaveEditRole"
|
|
StartIcon="@Icons.Material.Filled.Save">
|
|
Lưu
|
|
</MudButton>
|
|
<MudButton Variant="Variant.Text"
|
|
OnClick="@(() => EditRoleVisible = false)">
|
|
Hủy
|
|
</MudButton>
|
|
</DialogActions>
|
|
</MudDialog>
|
|
|
|
|
|
<MudDialog @bind-Visible="DelRoleVisible">
|
|
<TitleContent>
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@Icons.Material.Filled.Warning" Color="Color.Error" Class="mr-3" />
|
|
<MudText Typo="Typo.h6">Xác Nhận Xóa</MudText>
|
|
</div>
|
|
</TitleContent>
|
|
<DialogContent>
|
|
<MudAlert Severity="Severity.Warning" Class="mb-3">
|
|
Bạn có chắc chắn muốn xóa vai trò <strong>@RoleNameToDelete</strong>?
|
|
</MudAlert>
|
|
<MudText Typo="Typo.body2">Hành động này không thể hoàn tác.</MudText>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<MudButton Color="Color.Error"
|
|
Variant="Variant.Filled"
|
|
OnClick="ConfirmDelRole"
|
|
StartIcon="@Icons.Material.Filled.Delete">
|
|
Xóa
|
|
</MudButton>
|
|
<MudButton Variant="Variant.Text"
|
|
OnClick="@(() => DelRoleVisible = false)">
|
|
Hủy
|
|
</MudButton>
|
|
</DialogActions>
|
|
</MudDialog>
|
|
|
|
|
|
<MudDialog @bind-Visible="ManageUserRolesVisible">
|
|
<TitleContent>
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@Icons.Material.Filled.ManageAccounts" Class="mr-3" />
|
|
<MudText Typo="Typo.h6">Quản Lý Vai Trò: @SelectedUserName</MudText>
|
|
</div>
|
|
</TitleContent>
|
|
<DialogContent>
|
|
<MudGrid>
|
|
<MudItem xs="12">
|
|
<MudPaper Class="pa-4" Style="background: #f8fafc; border-radius: 12px;">
|
|
<MudText Typo="Typo.subtitle1" Class="mb-3">
|
|
<MudIcon Icon="@Icons.Material.Filled.Badge" Size="Size.Small" Class="mr-2" />
|
|
Vai Trò Hiện Tại
|
|
</MudText>
|
|
<div class="d-flex flex-wrap">
|
|
@if (AssignedRoles.Any())
|
|
{
|
|
foreach (var role in AssignedRoles)
|
|
{
|
|
if (role.Equals("Administrator", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
<MudChip T="string"
|
|
Color="Color.Warning"
|
|
Variant="Variant.Filled"
|
|
Icon="@Icons.Material.Filled.Lock"
|
|
Class="ma-1">
|
|
@role (Được bảo vệ)
|
|
</MudChip>
|
|
}
|
|
else
|
|
{
|
|
<MudChip T="string"
|
|
Color="@GetRoleChipColor(role)"
|
|
Variant="Variant.Filled"
|
|
Icon="@GetRoleIcon(role)"
|
|
Class="ma-1">
|
|
@role
|
|
</MudChip>
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<MudText Typo="Typo.body2" Color="Color.Default">
|
|
Chưa có vai trò nào
|
|
</MudText>
|
|
}
|
|
</div>
|
|
</MudPaper>
|
|
</MudItem>
|
|
|
|
|
|
<MudItem xs="12" md="6">
|
|
<MudPaper Class="pa-4" Style="border: 2px dashed #e2e8f0; border-radius: 12px;">
|
|
<MudText Typo="Typo.subtitle1" Class="mb-3" Color="Color.Success">
|
|
<MudIcon Icon="@Icons.Material.Filled.Add" Size="Size.Small" Class="mr-2" />
|
|
Thêm Vai Trò
|
|
</MudText>
|
|
<MudSelect T="string"
|
|
Label="Chọn vai trò để thêm"
|
|
MultiSelection="true"
|
|
@bind-SelectedValues="selectedRolesToAdd"
|
|
Variant="Variant.Outlined"
|
|
Clearable="true"
|
|
Dense="true"
|
|
MaxHeight="200"
|
|
FullWidth="true">
|
|
@foreach (var role in AvailableRoles)
|
|
{
|
|
<MudSelectItem T="string" Value="@role">
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@GetRoleIcon(role)" Size="Size.Small" Class="mr-2" />
|
|
@role
|
|
</div>
|
|
</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
<MudButton Color="Color.Success"
|
|
Variant="Variant.Filled"
|
|
StartIcon="@Icons.Material.Filled.Add"
|
|
OnClick="AddSelectedRolesToUser"
|
|
Disabled="@(!selectedRolesToAdd.Any())"
|
|
Class="mt-3"
|
|
FullWidth="true">
|
|
Thêm (@selectedRolesToAdd.Count())
|
|
</MudButton>
|
|
</MudPaper>
|
|
</MudItem>
|
|
|
|
|
|
@{
|
|
var removableRoles = AssignedRoles
|
|
.Where(role => !role.Equals("Administrator", StringComparison.OrdinalIgnoreCase))
|
|
.ToList();
|
|
}
|
|
@if (removableRoles.Any())
|
|
{
|
|
<MudItem xs="12" md="6">
|
|
<MudPaper Class="pa-4" Style="border: 2px dashed #fed7d4; border-radius: 12px;">
|
|
<MudText Typo="Typo.subtitle1" Class="mb-3" Color="Color.Error">
|
|
<MudIcon Icon="@Icons.Material.Filled.Remove" Size="Size.Small" Class="mr-2" />
|
|
Xóa Vai Trò
|
|
</MudText>
|
|
<MudSelect T="string"
|
|
Label="Chọn vai trò để xóa"
|
|
MultiSelection="true"
|
|
@bind-SelectedValues="selectedRolesToRemove"
|
|
Variant="Variant.Outlined"
|
|
Clearable="true"
|
|
Dense="true"
|
|
MaxHeight="200"
|
|
FullWidth="true">
|
|
@foreach (var role in removableRoles)
|
|
{
|
|
<MudSelectItem T="string" Value="@role">
|
|
<div class="d-flex align-center">
|
|
<MudIcon Icon="@GetRoleIcon(role)" Size="Size.Small" Class="mr-2" />
|
|
@role
|
|
</div>
|
|
</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
<MudButton Color="Color.Error"
|
|
Variant="Variant.Filled"
|
|
StartIcon="@Icons.Material.Filled.Remove"
|
|
OnClick="RemoveSelectedRolesFromUser"
|
|
Disabled="@(!selectedRolesToRemove.Any())"
|
|
Class="mt-3"
|
|
FullWidth="true">
|
|
Xóa (@selectedRolesToRemove.Count())
|
|
</MudButton>
|
|
</MudPaper>
|
|
</MudItem>
|
|
}
|
|
</MudGrid>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<MudButton Variant="Variant.Text"
|
|
OnClick="@(() => ManageUserRolesVisible = false)">
|
|
Đóng
|
|
</MudButton>
|
|
</DialogActions>
|
|
</MudDialog>
|
|
|
|
@code {
|
|
|
|
private bool CreateRoleVisible { get; set; }
|
|
private bool DelRoleVisible { get; set; }
|
|
private bool EditRoleVisible { get; set; }
|
|
private bool ManageUserRolesVisible { get; set; } = false;
|
|
|
|
private string CurrentRoleId { get; set; } = "";
|
|
private string EditRoleName { get; set; } = "";
|
|
private string NewRoleName { get; set; } = "";
|
|
private string RoleNameToDelete { get; set; } = "";
|
|
private string RoleIdToDelete { get; set; } = "";
|
|
|
|
private string SelectedUserName { get; set; } = string.Empty;
|
|
private string UserIdToManageRoles { get; set; } = string.Empty;
|
|
|
|
private string LoggedInUserId { get; set; } = string.Empty;
|
|
private List<string> LoggedInUserRoles { get; set; } = new();
|
|
private List<string> AllRoles { get; set; } = new List<string>();
|
|
private List<string> AvailableRoles { get; set; } = new List<string>();
|
|
private List<string> AssignedRoles { get; set; } = new List<string>();
|
|
private List<ApplicationRole> Roles { get; set; } = new List<ApplicationRole>();
|
|
private List<UserRoleModel> UsersWithRoles { get; set; } = new List<UserRoleModel>();
|
|
|
|
|
|
private IEnumerable<string> selectedRolesToAdd = new HashSet<string>();
|
|
private IEnumerable<string> selectedRolesToRemove = new HashSet<string>();
|
|
|
|
|
|
private string rowsPerPageString = "Rows:";
|
|
private string roleSearchTerm = "";
|
|
private string userSearchTerm = "";
|
|
|
|
private IEnumerable<ApplicationRole> FilteredRoles =>
|
|
string.IsNullOrWhiteSpace(roleSearchTerm)
|
|
? Roles
|
|
: Roles?.Where(r => r.Name != null && r.Name.Contains(roleSearchTerm, StringComparison.OrdinalIgnoreCase)) ?? Enumerable.Empty<ApplicationRole>();
|
|
|
|
private IEnumerable<UserRoleModel> FilteredUsers =>
|
|
string.IsNullOrWhiteSpace(userSearchTerm)
|
|
? UsersWithRoles
|
|
: UsersWithRoles?.Where(u => u.UserName != null && u.UserName.Contains(userSearchTerm, StringComparison.OrdinalIgnoreCase)) ?? Enumerable.Empty<UserRoleModel>();
|
|
|
|
|
|
private string GetRoleIcon(string roleName)
|
|
{
|
|
return roleName?.ToLower() switch
|
|
{
|
|
"administrator" => Icons.Material.Filled.SupervisorAccount,
|
|
"user" => Icons.Material.Filled.Person,
|
|
"guest" => Icons.Material.Filled.PersonOutline,
|
|
_ => Icons.Material.Filled.Security
|
|
};
|
|
}
|
|
|
|
private Color GetRoleColor(string roleName)
|
|
{
|
|
return roleName?.ToLower() switch
|
|
{
|
|
"administrator" => Color.Error,
|
|
"user" => Color.Primary,
|
|
"guest" => Color.Default,
|
|
_ => Color.Info
|
|
};
|
|
}
|
|
|
|
private Color GetRoleChipColor(string roleName)
|
|
{
|
|
return roleName?.ToLower() switch
|
|
{
|
|
"administrator" => Color.Error,
|
|
"user" => Color.Primary,
|
|
"guest" => Color.Default,
|
|
_ => Color.Info
|
|
};
|
|
}
|
|
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await base.OnInitializedAsync();
|
|
|
|
var authenticationState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
|
var currentUser = authenticationState.User;
|
|
|
|
if (currentUser.Identity?.IsAuthenticated == true)
|
|
{
|
|
LoggedInUserId = currentUser.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? string.Empty;
|
|
|
|
var currentUserObj = await UserManager.GetUserAsync(currentUser);
|
|
if (currentUserObj != null)
|
|
{
|
|
LoggedInUserRoles = (await UserManager.GetRolesAsync(currentUserObj)).ToList();
|
|
}
|
|
Roles = await RoleManager.Roles.OrderBy(r => r.CreatedDate).ToListAsync();
|
|
await LoadAllRoles();
|
|
await LoadUsersWithRoles();
|
|
StateHasChanged();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add("User is not authenticated.", Severity.Error);
|
|
}
|
|
}
|
|
|
|
private async Task LoadUsersWithRoles()
|
|
{
|
|
try
|
|
{
|
|
var users = await UserManager.Users.ToListAsync();
|
|
if (users == null || !users.Any())
|
|
{
|
|
Snackbar.Add("No users found.", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
var userRoleList = new List<UserRoleModel>();
|
|
|
|
foreach (var user in users)
|
|
{
|
|
var userRoles = await UserManager.GetRolesAsync(user);
|
|
|
|
userRoleList.Add(new UserRoleModel
|
|
{
|
|
UserName = user.UserName,
|
|
Roles = userRoles.ToList(),
|
|
UserId = user.Id
|
|
});
|
|
}
|
|
|
|
UsersWithRoles = userRoleList.OrderBy(u => u.UserId == LoggedInUserId ? 0 : 1).ToList();
|
|
StateHasChanged();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Snackbar.Add($"Lỗi khi tải người dùng và role: {ex.Message}", Severity.Error);
|
|
UsersWithRoles = new List<UserRoleModel>();
|
|
}
|
|
}
|
|
|
|
private async Task LoadAllRoles()
|
|
{
|
|
try
|
|
{
|
|
var roles = await RoleManager.Roles
|
|
.Select(role => role.Name)
|
|
.ToListAsync();
|
|
|
|
AllRoles = roles.Where(name => !string.IsNullOrEmpty(name)).Cast<string>().ToList() ?? new List<string>();
|
|
|
|
if (!AllRoles.Any())
|
|
{
|
|
Snackbar.Add("Không tìm thấy vai trò nào.", Severity.Warning);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Snackbar.Add($"Lỗi khi tải danh sách vai trò: {ex.Message}", Severity.Error);
|
|
AllRoles = new List<string>();
|
|
}
|
|
}
|
|
|
|
private void AddRole()
|
|
{
|
|
CreateRoleVisible = true;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void DelRole(string roleId, string roleName)
|
|
{
|
|
RoleIdToDelete = roleId;
|
|
RoleNameToDelete = roleName;
|
|
DelRoleVisible = true;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void EditRole(ApplicationRole role)
|
|
{
|
|
if (role?.Name is not null)
|
|
{
|
|
CurrentRoleId = role.Id;
|
|
EditRoleName = role.Name;
|
|
EditRoleVisible = true;
|
|
StateHasChanged();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add("Role information is incomplete or invalid.", Severity.Error);
|
|
}
|
|
}
|
|
|
|
private async Task ManageUserRoles(string userId, string userName)
|
|
{
|
|
|
|
if (!LoggedInUserRoles.Contains("Administrator"))
|
|
{
|
|
Snackbar.Add("Bạn không có quyền quản lý role của user khác.", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
if (!AllRoles.Any())
|
|
{
|
|
Snackbar.Add("Không có vai trò nào có thể chỉ định", Severity.Warning);
|
|
return;
|
|
}
|
|
|
|
SelectedUserName = userName;
|
|
UserIdToManageRoles = userId;
|
|
|
|
var user = await UserManager.FindByIdAsync(userId);
|
|
if (user != null)
|
|
{
|
|
var userRoles = await UserManager.GetRolesAsync(user);
|
|
AssignedRoles = userRoles.ToList();
|
|
|
|
AvailableRoles = AllRoles
|
|
.Except(userRoles)
|
|
.Where(role => !role.Equals("Administrator", StringComparison.OrdinalIgnoreCase))
|
|
.ToList();
|
|
}
|
|
|
|
selectedRolesToAdd = new HashSet<string>();
|
|
selectedRolesToRemove = new HashSet<string>();
|
|
|
|
ManageUserRolesVisible = true;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task AddSelectedRolesToUser()
|
|
{
|
|
foreach (var role in selectedRolesToAdd.ToList())
|
|
{
|
|
await AddRoleToSelectedUser(role);
|
|
}
|
|
selectedRolesToAdd = new HashSet<string>();
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task RemoveSelectedRolesFromUser()
|
|
{
|
|
foreach (var role in selectedRolesToRemove.ToList())
|
|
{
|
|
await RemoveRoleFromSelectedUser(role);
|
|
}
|
|
selectedRolesToRemove = new HashSet<string>();
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task AddRoleToSelectedUser(string roleName)
|
|
{
|
|
if (roleName.Equals("Administrator", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Snackbar.Add("Không thể gán role Admin cho user khác.", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
|
|
if (!LoggedInUserRoles.Contains("Administrator"))
|
|
{
|
|
Snackbar.Add("Bạn không có quyền thực hiện thao tác này.", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
var user = await UserManager.FindByIdAsync(UserIdToManageRoles);
|
|
if (user != null)
|
|
{
|
|
var result = await UserManager.AddToRoleAsync(user, roleName);
|
|
|
|
if (result.Succeeded)
|
|
{
|
|
AssignedRoles.Add(roleName);
|
|
AvailableRoles.Remove(roleName);
|
|
|
|
selectedRolesToAdd = selectedRolesToAdd.Where(r => r != roleName);
|
|
|
|
Snackbar.Add($"Thêm role '{roleName}' cho {SelectedUserName} Thành Công.", Severity.Success);
|
|
await LoadUsersWithRoles();
|
|
StateHasChanged();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add($"Failed to add role '{roleName}' to user.", Severity.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task RemoveRoleFromSelectedUser(string roleName)
|
|
{
|
|
if (roleName.Equals("Administrator", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Snackbar.Add("Không thể xóa role Admin của user.", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
|
|
if (!LoggedInUserRoles.Contains("Administrator"))
|
|
{
|
|
Snackbar.Add("Bạn không có quyền thực hiện thao tác này.", Severity.Error);
|
|
return;
|
|
}
|
|
var user = await UserManager.FindByIdAsync(UserIdToManageRoles);
|
|
if (user != null)
|
|
{
|
|
var result = await UserManager.RemoveFromRoleAsync(user, roleName);
|
|
|
|
if (result.Succeeded)
|
|
{
|
|
AssignedRoles.Remove(roleName);
|
|
AvailableRoles.Add(roleName);
|
|
selectedRolesToRemove = selectedRolesToRemove.Where(r => r != roleName);
|
|
|
|
Snackbar.Add($"Thành công xoá role '{roleName}' của {SelectedUserName}.", Severity.Success);
|
|
await LoadUsersWithRoles();
|
|
StateHasChanged();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add($"Failed to remove role '{roleName}' from user.", Severity.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task CreateRole()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(NewRoleName))
|
|
{
|
|
Snackbar.Add(" Tên Role không được để trống.", Severity.Error);
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
|
|
var roleExist = await RoleManager.RoleExistsAsync(NewRoleName.ToUpper());
|
|
if (roleExist)
|
|
{
|
|
Snackbar.Add(" Role đã tồn tại.", Severity.Warning);
|
|
CreateRoleVisible = false;
|
|
NewRoleName = "";
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
|
|
var newRole = new ApplicationRole
|
|
{
|
|
Name = NewRoleName,
|
|
NormalizedName = NewRoleName.ToUpper(),
|
|
CreatedDate = DateTime.UtcNow
|
|
};
|
|
|
|
var result = await RoleManager.CreateAsync(newRole);
|
|
|
|
if (result.Succeeded)
|
|
{
|
|
Roles.Add(newRole);
|
|
Snackbar.Add(" Tạo Role thành công!", Severity.Success);
|
|
await LoadAllRoles();
|
|
CreateRoleVisible = false;
|
|
NewRoleName = "";
|
|
StateHasChanged();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add(" Tạo Role thất bại.", Severity.Error);
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task SaveEditRole()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(EditRoleName))
|
|
{
|
|
Snackbar.Add("Tên Role không được để trống.", Severity.Error);
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
|
|
var role = await RoleManager.FindByIdAsync(CurrentRoleId);
|
|
if (role != null)
|
|
{
|
|
role.Name = EditRoleName;
|
|
role.NormalizedName = EditRoleName.ToUpper();
|
|
|
|
var result = await RoleManager.UpdateAsync(role);
|
|
|
|
if (result.Succeeded)
|
|
{
|
|
var existingRole = Roles.FirstOrDefault(r => r.Id == role.Id);
|
|
if (existingRole != null)
|
|
{
|
|
existingRole.Name = role.Name;
|
|
}
|
|
|
|
Snackbar.Add("Role đã được sửa thành công!", Severity.Success);
|
|
await LoadAllRoles();
|
|
await LoadUsersWithRoles();
|
|
EditRoleVisible = false;
|
|
EditRoleName = "";
|
|
StateHasChanged();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add("Sửa Role thất bại.", Severity.Error);
|
|
EditRoleVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add("Không tìm thấy role với ID đã cho.", Severity.Error);
|
|
EditRoleVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task ConfirmDelRole()
|
|
{
|
|
if (string.IsNullOrEmpty(RoleIdToDelete))
|
|
{
|
|
Snackbar.Add(" Không tìm thấy Role để xóa.", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
var role = await RoleManager.FindByIdAsync(RoleIdToDelete);
|
|
if (role != null)
|
|
{
|
|
var result = await RoleManager.DeleteAsync(role);
|
|
if (result.Succeeded)
|
|
{
|
|
Snackbar.Add(" Đã xóa Role thành công.", Severity.Success);
|
|
Roles = await RoleManager.Roles
|
|
.OrderBy(r => r.CreatedDate)
|
|
.ToListAsync();
|
|
await LoadAllRoles();
|
|
await LoadUsersWithRoles();
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add(" Xóa Role thất bại.", Severity.Error);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add(" Không tìm thấy Role để xóa.", Severity.Error);
|
|
}
|
|
|
|
DelRoleVisible = false;
|
|
RoleIdToDelete = "";
|
|
StateHasChanged();
|
|
}
|
|
|
|
public class UserRoleModel
|
|
{
|
|
public string? UserName { get; set; }
|
|
public List<string> Roles { get; set; } = new List<string>();
|
|
public string? UserId { get; set; }
|
|
}
|
|
|
|
}
|