add support for API permissions at the UI layer - including ability to delegate user, role, profile management
This commit is contained in:
@ -33,7 +33,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
@if (_canViewAdminDashboard || UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
<button type="button" class="btn @ButtonClass" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel">
|
||||
<span class="oi oi-cog"></span>
|
||||
@ -46,16 +46,17 @@
|
||||
</div>
|
||||
<div class="@BodyClass">
|
||||
<div class="container-fluid">
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
@if (_canViewAdminDashboard)
|
||||
{
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="app-rule" />
|
||||
|
||||
}
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label class="control-label">@Localizer["Page.Manage"] </label>
|
||||
@ -80,144 +81,149 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<hr class="app-rule" />
|
||||
|
||||
@if (_deleteConfirmation)
|
||||
{
|
||||
<div class="app-admin-modal">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@Localizer["Page.Delete"]</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="ConfirmDelete"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are You Sure You Want To Delete This Page?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" @onclick="DeletePage">@SharedLocalizer["Delete"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@SharedLocalizer["Cancel"]</button>
|
||||
@if (_deleteConfirmation)
|
||||
{
|
||||
<div class="app-admin-modal">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@Localizer["Page.Delete"]</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="ConfirmDelete"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are You Sure You Want To Delete This Page?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" @onclick="DeletePage">@SharedLocalizer["Delete"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<hr class="app-rule" />
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
||||
<select class="form-select" @bind="@ModuleType">
|
||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||
</select>
|
||||
@if (ModuleType == "new")
|
||||
{
|
||||
@if (_moduleDefinitions != null)
|
||||
{
|
||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||
@foreach (var category in _categories)
|
||||
{
|
||||
if (category == Category)
|
||||
{
|
||||
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@category">@category @Localizer["Modules"]</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @onchange="(e => ModuleChanged(e))">
|
||||
@if (ModuleDefinitionName == "-")
|
||||
{
|
||||
<option value="-" selected><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
@foreach (var moduledefinition in _moduleDefinitions)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
{
|
||||
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
||||
{
|
||||
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
|
||||
}
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select" @onchange="(e => PageChanged(e))">
|
||||
<option value="-"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page p in _pages)
|
||||
{
|
||||
<option value="@p.PageId">@p.Name</option>
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @bind="@ModuleId">
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
@foreach (Module module in _modules)
|
||||
{
|
||||
<option value="@module.ModuleId">@module.Title</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
||||
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
||||
</div>
|
||||
</div>
|
||||
@if (_pane.Length > 1)
|
||||
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
||||
<select class="form-select" @bind="@Pane">
|
||||
@foreach (string pane in PageState.Page.Panes)
|
||||
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
||||
<select class="form-select" @bind="@ModuleType">
|
||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||
</select>
|
||||
@if (ModuleType == "new")
|
||||
{
|
||||
@if (_moduleDefinitions != null)
|
||||
{
|
||||
<option value="@pane">@pane Pane</option>
|
||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||
@foreach (var category in _categories)
|
||||
{
|
||||
if (category == Category)
|
||||
{
|
||||
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@category">@category @Localizer["Modules"]</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @onchange="(e => ModuleChanged(e))">
|
||||
@if (ModuleDefinitionName == "-")
|
||||
{
|
||||
<option value="-" selected><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
@foreach (var moduledefinition in _moduleDefinitions)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
{
|
||||
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
||||
{
|
||||
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
|
||||
}
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select" @onchange="(e => PageChanged(e))">
|
||||
<option value="-"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page p in _pages)
|
||||
{
|
||||
<option value="@p.PageId">@p.Name</option>
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @bind="@ModuleId">
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
@foreach (Module module in _modules)
|
||||
{
|
||||
<option value="@module.ModuleId">@module.Title</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
||||
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
||||
</div>
|
||||
</div>
|
||||
@if (_pane.Length > 1)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
||||
<select class="form-select" @bind="@Pane">
|
||||
@foreach (string pane in PageState.Page.Panes)
|
||||
{
|
||||
<option value="@pane">@pane Pane</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
||||
<select class="form-select" @bind="@ContainerType">
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="visibility" class="control-label">@Localizer["Visibility"]</label>
|
||||
<select class="form-select" @bind="@Visibility">
|
||||
<option value="view">@Localizer["VisibilityView"]</option>
|
||||
<option value="edit">@Localizer["VisibilityEdit"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
||||
@((MarkupString)Message)
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
||||
<select class="form-select" @bind="@ContainerType">
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="visibility" class="control-label">@Localizer["Visibility"]</label>
|
||||
<select class="form-select" @bind="@Visibility">
|
||||
<option value="view">@Localizer["VisibilityView"]</option>
|
||||
<option value="edit">@Localizer["VisibilityEdit"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
||||
@((MarkupString) Message)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code{
|
||||
private bool _canViewAdminDashboard = false;
|
||||
private bool _showEditMode = false;
|
||||
private bool _deleteConfirmation = false;
|
||||
private List<string> _categories = new List<string>();
|
||||
@ -286,6 +292,7 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_canViewAdminDashboard = CanViewAdminDashboard();
|
||||
_showEditMode = false;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
@ -321,6 +328,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanViewAdminDashboard()
|
||||
{
|
||||
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
||||
if (admin != null)
|
||||
{
|
||||
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.Permissions))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CategoryChanged(ChangeEventArgs e)
|
||||
{
|
||||
Category = (string)e.Value;
|
||||
@ -465,12 +488,10 @@
|
||||
case "Admin":
|
||||
// get admin dashboard moduleid
|
||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
||||
|
||||
if (module != null)
|
||||
{
|
||||
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, module.ModuleId, "Index", ""));
|
||||
}
|
||||
|
||||
break;
|
||||
case "Add":
|
||||
case "Edit":
|
||||
@ -551,19 +572,19 @@
|
||||
{
|
||||
page.IsDeleted = true;
|
||||
await PageService.UpdatePageAsync(page);
|
||||
await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
||||
await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
||||
NavigationManager.NavigateTo(NavigateUrl(""));
|
||||
}
|
||||
else // personalized page
|
||||
{
|
||||
await PageService.DeletePageAsync(page.PageId);
|
||||
await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
||||
await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message);
|
||||
await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,8 +617,8 @@
|
||||
private async Task UpdateSettingsAsync()
|
||||
{
|
||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
SettingService.SetSetting(settings, settingCategory, _category);
|
||||
SettingService.SetSetting(settings, settingPane, _pane);
|
||||
settings = SettingService.SetSetting(settings, settingCategory, _category);
|
||||
settings = SettingService.SetSetting(settings, settingPane, _pane);
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace Oqtane.Themes.Controls
|
||||
|
||||
protected async Task LogoutUser()
|
||||
{
|
||||
await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User.Username);
|
||||
await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username);
|
||||
|
||||
// check if anonymous user can access page
|
||||
var url = PageState.Alias.Path + "/" + PageState.Page.Path;
|
||||
|
Reference in New Issue
Block a user