Merge pull request #5 from oqtane/master

Latest Changes From Master
This commit is contained in:
ADefWebserver 2019-11-11 18:43:38 -08:00 committed by GitHub
commit 27c6700f9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
257 changed files with 20097 additions and 3291 deletions

View File

@ -1,7 +1,4 @@
@using Microsoft.AspNetCore.Components.Authorization
@using Oqtane.Shared
@using Oqtane.Services
@inject IInstallationService InstallationService
@inject IInstallationService InstallationService
@if (Initialized)
{

View File

@ -1,37 +1,31 @@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Routing
@using Oqtane.Modules
@using Oqtane.Services
@using Oqtane.Models;
@using Oqtane.Security
@namespace Oqtane.Modules.Admin.Dashboard
@namespace Oqtane.Modules.Admin.Dashboard
@inherits ModuleBase
@inject IPageService PageService
@inject IUserService UserService
<ul class="list-group">
<div class="row">
@foreach (var p in pages)
{
if (UserSecurity.IsAuthorized(PageState.User, "View", p.Permissions))
{
string url = NavigateUrl(p.Path);
<li class="list-group-item">
<div class="col-md-2 mx-auto text-center">
<NavLink class="nav-link" href="@url" Match="NavLinkMatch.All">
<span class="oi @p.Icon" aria-hidden="true"></span> @p.Name
<h2><span class="oi oi-@p.Icon" aria-hidden="true"></span></h2>@p.Name
</NavLink>
</li>
</div>
}
}
</ul>
<br />
<br />
</div>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<Page> pages;
protected override void OnInitialized()
{
// display list of pages which are children of current page
pages = PageState.Pages.Where(item => item.ParentId == PageState.Page.PageId).ToList();
Page admin = PageState.Pages.Where(item => item.Path == "admin").FirstOrDefault();
pages = PageState.Pages.Where(item => item.ParentId == admin.PageId).ToList();
}
}
}

View File

@ -0,0 +1,56 @@
@namespace Oqtane.Modules.Admin.Files
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IFileService FileService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Files: </label>
</td>
<td>
<FileUpload Multiple="true" @ref="fileupload"></FileUpload>
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="UploadFile">Upload</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
FileUpload fileupload;
private async Task UploadFile()
{
string[] files = await fileupload.GetFiles();
if (files.Length > 0)
{
try
{
ShowProgressIndicator();
string result = await FileService.UploadFilesAsync(PageState.Site.SiteRootPath, files, "");
if (result == "")
{
await logger.LogInformation("Files Uploaded Successfully");
AddModuleMessage("Files Uploaded Successfully", MessageType.Success);
}
else
{
await logger.LogError("Upload Failed For {Files}", result.Replace(",",", "));
AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Upload Failed {Error}", ex.Message);
AddModuleMessage("Upload Failed. " + ex.Message, MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Select Some Files To Upload", MessageType.Warning);
}
}
}

View File

@ -0,0 +1,61 @@
@namespace Oqtane.Modules.Admin.Files
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IFileService FileService
@if (Files == null)
{
<p><em>Loading...</em></p>
}
else
{
<ActionLink Action="Add" Text="Add Files" />
<Pager Items="@Files">
<Header>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionDialog Header="Delete File" Message="@("Are You Sure You Wish To Delete " + context + "?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" /></td>
<td><a href="@(uri.Scheme + "://" + uri.Authority + "/" + PageState.Site.SiteRootPath + context)" target="_new">@context</a></td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<string> Files;
Uri uri;
protected override async Task OnParametersSetAsync()
{
try
{
Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath);
uri = new Uri(NavigationManager.Uri);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);
AddModuleMessage("Error Loading Files", MessageType.Error);
}
}
private async Task DeleteFile(string filename)
{
try
{
await FileService.DeleteFileAsync(PageState.Site.SiteRootPath, filename);
Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath);
await logger.LogInformation("File Deleted {File}", filename);
AddModuleMessage("File " + filename + " Deleted", MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting File {File} {Error}", filename, ex.Message);
AddModuleMessage("Error Deleting File " + filename, MessageType.Error);
}
}
}

View File

@ -1,13 +1,4 @@
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Routing
@using Oqtane.Modules
@using Microsoft.JSInterop
@using Oqtane.Models
@using Oqtane.Services
@using Oqtane.Providers
@using Oqtane.Shared
@namespace Oqtane.Modules.Admin.Login
@namespace Oqtane.Modules.Admin.Login
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IJSRuntime jsRuntime
@ -23,7 +14,6 @@
</Authorized>
<NotAuthorized>
<div class="container">
@((MarkupString)Message)
<div class="form-group">
<label for="Username" class="control-label">Username: </label>
<input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Username" />
@ -47,7 +37,6 @@
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
public string Message { get; set; } = "";
public string Username { get; set; } = "";
public string Password { get; set; } = "";
public bool Remember { get; set; } = false;
@ -67,6 +56,7 @@
user = await UserService.LoginUserAsync(user, false, false);
if (user.IsAuthenticated)
{
await logger.LogInformation("Login Successful For Username {Username}", Username);
// complete the login on the server so that the cookies are set correctly on SignalR
var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
@ -75,7 +65,8 @@
}
else
{
Message = "<div class=\"alert alert-danger\" role=\"alert\">Login Failed. Please Remember That Passwords Are Case Sensitive.</div>";
await logger.LogInformation("Login Failed For Username {Username}", Username);
AddModuleMessage("Login Failed. Please Remember That Passwords Are Case Sensitive.", MessageType.Error);
}
}
else
@ -88,13 +79,14 @@
user = await UserService.LoginUserAsync(user, true, Remember);
if (user.IsAuthenticated)
{
await logger.LogInformation("Login Successful For Username {Username}", Username);
authstateprovider.NotifyAuthenticationChanged();
PageState.Reload = Constants.ReloadSite;
NavigationManager.NavigateTo(NavigateUrl(ReturnUrl));
NavigationManager.NavigateTo(NavigateUrl(ReturnUrl, Reload.Site));
}
else
{
Message = "<div class=\"alert alert-danger\" role=\"alert\">Login Failed. Please Remember That Passwords Are Case Sensitive.</div>";
await logger.LogInformation("Login Failed For Username {Username}", Username);
AddModuleMessage("Login Failed. Please Remember That Passwords Are Case Sensitive.", MessageType.Error);
}
}
}

View File

@ -0,0 +1,207 @@
@namespace Oqtane.Modules.Admin.Logs
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ILogService LogService
@inject IPageService PageService
@inject IPageModuleService PageModuleService
@inject IUserService UserService
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Date/Time: </label>
</td>
<td>
<input class="form-control" @bind="@logdate" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Level: </label>
</td>
<td>
<input class="form-control" @bind="@level" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Feature: </label>
</td>
<td>
<input class="form-control" @bind="@feature" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Function: </label>
</td>
<td>
<input class="form-control" @bind="@function" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Category: </label>
</td>
<td>
<input class="form-control" @bind="@category" disabled />
</td>
</tr>
@if (pagename != "")
{
<tr>
<td>
<label class="control-label">Page: </label>
</td>
<td>
<input class="form-control" @bind="@pagename" disabled />
</td>
</tr>
}
@if (moduletitle != "")
{
<tr>
<td>
<label class="control-label">Module: </label>
</td>
<td>
<input class="form-control" @bind="@moduletitle" disabled />
</td>
</tr>
}
@if (username != "")
{
<tr>
<td>
<label class="control-label">User: </label>
</td>
<td>
<input class="form-control" @bind="@username" disabled />
</td>
</tr>
}
<tr>
<td>
<label class="control-label">Url: </label>
</td>
<td>
<input class="form-control" @bind="@url" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Template: </label>
</td>
<td>
<input class="form-control" @bind="@template" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Message: </label>
</td>
<td>
<textarea class="form-control" @bind="@message" rows="5" disabled />
</td>
</tr>
@if (!string.IsNullOrEmpty(exception))
{
<tr>
<td>
<label class="control-label">Exception: </label>
</td>
<td>
<textarea class="form-control" @bind="@exception" rows="5" disabled />
</td>
</tr>
}
<tr>
<td>
<label class="control-label">Properties: </label>
</td>
<td>
<textarea class="form-control" @bind="@properties" rows="5" disabled />
</td>
</tr>
<tr>
<td>
<label class="control-label">Server: </label>
</td>
<td>
<input class="form-control" @bind="@server" disabled />
</td>
</tr>
</table>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
int logid;
string logdate = "";
string level = "";
string feature = "";
string function = "";
string category = "";
string pagename = "";
string moduletitle = "";
string username = "";
string url = "";
string template = "";
string message = "";
string exception = "";
string properties = "";
string server = "";
protected override async Task OnInitializedAsync()
{
try
{
logid = Int32.Parse(PageState.QueryString["id"]);
Log log = await LogService.GetLogAsync(logid);
if (log != null)
{
logdate = log.LogDate.ToString();
level = log.Level;
feature = log.Feature;
function = log.Function;
category = log.Category;
if (log.PageId != null)
{
Page page = await PageService.GetPageAsync(log.PageId.Value);
if (page != null)
{
pagename = page.Name;
}
}
if (log.PageId != null && log.ModuleId != null)
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value);
if (pagemodule != null)
{
moduletitle = pagemodule.Title;
}
}
if (log.UserId != null)
{
User user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId);
if (user != null)
{
username = user.Username;
}
}
url = log.Url;
template = log.MessageTemplate;
message = log.Message;
exception = log.Exception;
properties = log.Properties;
server = log.Server;
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Log {LogId} {Error}", logid, ex.Message);
AddModuleMessage("Error Loading Log", MessageType.Error);
}
}
}

View File

@ -0,0 +1,162 @@
@namespace Oqtane.Modules.Admin.Logs
@inherits ModuleBase
@inject ILogService LogService
@if (Logs == null)
{
<p><em>Loading...</em></p>
}
else
{
<div class="form-group">
<label>Level: </label>
<select class="form-control" @onchange="(e => LevelChanged(e))">
<option value="-">&lt;All Levels&gt;</option>
<option value="Trace">Trace</option>
<option value="Debug">Debug</option>
<option value="Information">Information</option>
<option value="Warning">Warning</option>
<option value="Error">Error</option>
<option value="Critical">Critical</option>
</select>
<label>Function: </label>
<select class="form-control" @onchange="(e => FunctionChanged(e))">
<option value="-">&lt;All Functions&gt;</option>
<option value="Create">Create</option>
<option value="Read">Read</option>
<option value="Update">Update</option>
<option value="Delete">Delete</option>
<option value="Security">Security</option>
<option value="Other">Other</option>
</select>
<label>Rows: </label>
<select class="form-control" @onchange="(e => RowsChanged(e))">
<option value="10">10</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
@if (Logs.Any())
{
<Pager Items="@Logs">
<Header>
<th>&nbsp;</th>
<th>Date</th>
<th>Level</th>
<th>Feature</th>
<th>Function</th>
</Header>
<Row>
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" /></td>
<td class="@GetClass(context.Function)">@context.LogDate</td>
<td class="@GetClass(context.Function)">@context.Level</td>
<td class="@GetClass(context.Function)">@context.Feature</td>
<td class="@GetClass(context.Function)">@context.Function</td>
</Row>
</Pager>
}
else
{
<p><em>No Logs Match The Criteria Specified</em></p>
}
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string level = "-";
string function = "-";
string rows = "10";
List<Log> Logs;
protected override async Task OnInitializedAsync()
{
try
{
await GetLogs();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Logs {Error}", ex.Message);
AddModuleMessage("Error Loading Logs", MessageType.Error);
}
}
private async void LevelChanged(ChangeEventArgs e)
{
try
{
level = (string)e.Value;
await GetLogs();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Logs {Error}", ex.Message);
AddModuleMessage("Error Loading Logs", MessageType.Error);
}
}
private async void FunctionChanged(ChangeEventArgs e)
{
try
{
function = (string)e.Value;
await GetLogs();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Logs {Error}", ex.Message);
AddModuleMessage("Error Loading Logs", MessageType.Error);
}
}
private async void RowsChanged(ChangeEventArgs e)
{
try
{
rows = (string)e.Value;
await GetLogs();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Logs {Error}", ex.Message);
AddModuleMessage("Error Loading Logs", MessageType.Error);
}
}
private async Task GetLogs()
{
Logs = await LogService.GetLogsAsync(PageState.Site.SiteId, ((level == "-") ? "" : level), ((function == "-") ? "" : function), int.Parse(rows));
}
private string GetClass(string function)
{
string classname = "";
switch (function)
{
case "Create":
classname = "table-primary";
break;
case "Read":
classname = "table-secondary";
break;
case "Update":
classname = "table-success";
break;
case "Delete":
classname = "table-danger";
break;
case "Security":
classname = "table-warning";
break;
default:
classname = "";
break;
}
return classname;
}
}

View File

@ -1,14 +1,9 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Modules
@using Oqtane.Services
@using Oqtane.Shared
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IFileService FileService
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
<table class="table table-borderless">
<tr>
@ -16,36 +11,136 @@
<label for="Name" class="control-label">Module: </label>
</td>
<td>
<FileUpload Filter=".nupkg"></FileUpload>
<FileUpload Filter=".nupkg" @ref="fileupload"></FileUpload>
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="UploadFile">Upload Module</button>
@if (packages != null)
{
<hr class="app-rule" />
<div class="mx-auto text-center"><h2>Available Modules</h2></div>
<Pager Items="@packages">
<Header>
<th>Name</th>
<th>Version</th>
<th></th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadModule(context.PackageId, context.Version))>Download Module</button>
</td>
</Row>
</Pager>
}
@if (uploaded)
{
<button type="button" class="btn btn-success" @onclick="InstallFile">Install</button>
}
else
{
<button type="button" class="btn btn-success" @onclick="UploadFile">Upload</button>
<button type="button" class="btn btn-success" @onclick="InstallModules">Install</button>
}
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
bool uploaded = false;
List<Package> packages;
FileUpload fileupload;
protected override async Task OnInitializedAsync()
{
try
{
List<ModuleDefinition> moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
packages = await PackageService.GetPackagesAsync("module");
foreach(Package package in packages.ToArray())
{
if (moduledefinitions.Exists(item => Utilities.GetTypeName(item.ModuleDefinitionName) == package.PackageId))
{
packages.Remove(package);
}
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message);
AddModuleMessage("Error Loading Packages", MessageType.Error);
}
}
private async Task UploadFile()
{
await FileService.UploadFilesAsync("Modules");
uploaded = true;
StateHasChanged();
string[] files = await fileupload.GetFiles();
if (files.Length > 0)
{
if (files[0].Contains(".Module."))
{
try
{
string result = await FileService.UploadFilesAsync("Modules", files, "");
if (result == "")
{
await logger.LogInformation("Module Uploaded Successfully {Package}", files[0]);
AddModuleMessage("Module Uploaded Successfully. Click Install To Complete Installation.", MessageType.Success);
uploaded = true;
StateHasChanged();
}
else
{
await logger.LogError("Module Upload Failed For {Package}", files[0]);
AddModuleMessage("Module Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Module Upload Failed For {Package} {Error}", files[0], ex.Message);
AddModuleMessage("Module Upload Failed.", MessageType.Error);
}
}
else
{
await logger.LogError("Invalid Module Package {Package}", files[0]);
AddModuleMessage("Invalid Module Package", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Select A Module To Upload", MessageType.Warning);
}
}
private async Task InstallFile()
private async Task InstallModules()
{
await ModuleDefinitionService.InstallModulesAsync();
PageState.Reload = Constants.ReloadApplication;
NavigationManager.NavigateTo(NavigateUrl());
try
{
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Installating Module");
}
}
private async Task DownloadModule(string moduledefinitionname, string version)
{
try
{
await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules");
await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", moduledefinitionname, version);
AddModuleMessage("Module Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
uploaded = true;
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", moduledefinitionname, version);
AddModuleMessage("Error Downloading Module", MessageType.Error);
}
}
}

View File

@ -0,0 +1,82 @@
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@inject IModuleDefinitionService ModuleDefinitionService
@inject NavigationManager NavigationManager
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="ModuleDefinition" PermissionNames="Utilize" Permissions="@permissions" @ref="permissiongrid" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
int ModuleDefinitionId;
string name;
string permissions;
string createdby;
DateTime createdon;
string modifiedby;
DateTime modifiedon;
PermissionGrid permissiongrid;
protected override async Task OnInitializedAsync()
{
try
{
ModuleDefinitionId = Int32.Parse(PageState.QueryString["id"]);
ModuleDefinition moduledefinition = PageState.ModuleDefinitions.Where(item => item.ModuleDefinitionId == ModuleDefinitionId).FirstOrDefault();
if (moduledefinition != null)
{
name = moduledefinition.Name;
permissions = moduledefinition.Permissions;
createdby = moduledefinition.CreatedBy;
createdon = moduledefinition.CreatedOn;
modifiedby = moduledefinition.ModifiedBy;
modifiedon = moduledefinition.ModifiedOn;
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading ModuleDefinition {ModuleDefinitionId} {Error}", ModuleDefinitionId, ex.Message);
AddModuleMessage("Error Loading Module", MessageType.Error);
}
}
private async Task SaveModuleDefinition()
{
try
{
ModuleDefinition moduledefinition = PageState.ModuleDefinitions.Where(item => item.ModuleDefinitionId == ModuleDefinitionId).FirstOrDefault();
moduledefinition.Permissions = permissiongrid.GetPermissions();
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
NavigationManager.NavigateTo(NavigateUrl(Reload.Site));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", ModuleDefinitionId, ex.Message);
AddModuleMessage("Error Saving Module", MessageType.Error);
}
}
}

View File

@ -1,11 +1,8 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
@if (moduledefinitions == null)
{
@ -14,30 +11,94 @@
else
{
<ActionLink Action="Add" Text="Install Module" />
<table class="table table-borderless">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (var moduledefinition in moduledefinitions)
{
<tr>
<td>@moduledefinition.Name</td>
</tr>
}
</tbody>
</table>
<Pager Items="@moduledefinitions">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
<th>Version</th>
<th>&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" /></td>
<td>
@if (context.AssemblyName != "Oqtane.Client")
{
<ActionDialog Header="Delete Module" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Module?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" />
}
</td>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
@if (UpgradeAvailable(context.ModuleDefinitionName, context.Version))
{
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadModule(context.ModuleDefinitionName, context.Version))>Upgrade</button>
}
</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
List<ModuleDefinition> moduledefinitions;
List<Package> packages;
protected override async Task OnInitializedAsync()
{
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync();
try
{
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
packages = await PackageService.GetPackagesAsync("module");
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Modules {Error}", ex.Message);
AddModuleMessage("Error Loading Modules", MessageType.Error);
}
}
private bool UpgradeAvailable(string moduledefinitionname, string version)
{
bool upgradeavailable = false;
Package package = packages.Where(item => item.PackageId == Utilities.GetTypeName(moduledefinitionname)).FirstOrDefault();
if (package != null)
{
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
}
return upgradeavailable;
}
private async Task DownloadModule(string moduledefinitionname, string version)
{
try
{
await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules");
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", moduledefinitionname, version);
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version} {Error}", moduledefinitionname, version, ex.Message);
AddModuleMessage("Error Downloading Module", MessageType.Error);
}
}
private async Task DeleteModule(ModuleDefinition ModuleDefinition)
{
try
{
await ModuleDefinitionService.DeleteModuleDefinitionAsync(ModuleDefinition.ModuleDefinitionId, ModuleDefinition.SiteId);
await logger.LogInformation("Module Deleted {ModuleDefinition}", ModuleDefinition);
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Module {ModuleDefinition} {Error}", ModuleDefinition, ex.Message);
AddModuleMessage("Error Deleting Module", MessageType.Error);
}
}
}

View File

@ -0,0 +1,32 @@
@namespace Oqtane.Modules.Admin.Modules
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleService ModuleService
<table class="table table-borderless">
<tbody>
<tr>
<td>
<label for="Title" class="control-label">Content: </label>
</td>
<td>
<textarea class="form-control" @bind="@content" rows="5" />
</td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-success" @onclick="ExportModule">Export</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Title { get { return "Export Module"; } }
string content = "";
private async Task ExportModule()
{
content = await ModuleService.ExportModuleAsync(ModuleState.ModuleId);
}
}

View File

@ -0,0 +1,49 @@
@namespace Oqtane.Modules.Admin.Modules
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleService ModuleService
<table class="table table-borderless">
<tbody>
<tr>
<td>
<label for="Title" class="control-label">Content: </label>
</td>
<td>
<textarea class="form-control" @bind="@content" rows="5" />
</td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-success" @onclick="ImportModule">Import</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Title { get { return "Import Module"; } }
string content = "";
private async Task ImportModule()
{
if (content != "")
{
try
{
await ModuleService.ImportModuleAsync(ModuleState.ModuleId, content);
NavigationManager.NavigateTo(NavigateUrl(Reload.Page));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Importing Module {ModuleId} {Error}", ModuleState.ModuleId, ex.Message);
AddModuleMessage("Error Importing Module", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Enter Some Content To Import", MessageType.Warning);
}
}
}

View File

@ -1,12 +1,4 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Security
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.ModuleSettings
@namespace Oqtane.Modules.Admin.Modules
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService
@ -14,7 +6,7 @@
@inject IPageModuleService PageModuleService
<table class="table table-borderless">
<thead>
<tbody>
<tr>
<td>
<label for="Title" class="control-label">Title: </label>
@ -23,8 +15,6 @@
<input type="text" name="Title" class="form-control" @bind="@title" />
</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<label for="Container" class="control-label">Container: </label>
@ -44,7 +34,7 @@
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Module" Permissions="@permissions" @ref="permissiongrid" />
<PermissionGrid EntityName="Module" PermissionNames="@permissionnames" Permissions="@permissions" @ref="permissiongrid" />
</td>
</tr>
<tr>
@ -76,6 +66,7 @@
Dictionary<string, string> containers = new Dictionary<string, string>();
string title;
string containertype;
string permissionnames = "";
string permissions;
string pageid;
@ -90,6 +81,7 @@
containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync());
containertype = ModuleState.ContainerType;
permissions = ModuleState.Permissions;
permissionnames = PageState.ModuleDefinitions.Find(item => item.ModuleDefinitionName == ModuleState.ModuleDefinitionName).PermissionNames;
pageid = ModuleState.PageId.ToString();
DynamicComponent = builder =>
@ -111,9 +103,11 @@
await ModuleService.UpdateModuleAsync(module);
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
pagemodule.PageId = int.Parse(pageid);
pagemodule.Title = title;
pagemodule.ContainerType = containertype;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
Type moduleType = Type.GetType(ModuleState.ModuleType);
if (moduleType != null)
@ -121,8 +115,7 @@
moduleType.GetMethod("UpdateSettings").Invoke(settings, null); // method must be public in settings component
}
PageState.Reload = Constants.ReloadPage;
NavigationManager.NavigateTo(NavigateUrl());
NavigationManager.NavigateTo(NavigateUrl(Reload.Page));
}
}

View File

@ -1,151 +1,150 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Models
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Security
@namespace Oqtane.Modules.Admin.Pages
@namespace Oqtane.Modules.Admin.Pages
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@inject IThemeService ThemeService
<ModuleMessage Message="@message" />
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Path: </label>
</td>
<td>
<input class="form-control" @bind="@path" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Parent: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ParentChanged(e))">
<option value="">&lt;Site Root&gt;</option>
@foreach (Page page in pages)
{
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Insert: </label>
</td>
<td>
<select class="form-control" @bind="@insert">
<option value="<<">At Beginning</option>
@if (children != null && children.Count > 0)
{
<option value="<">Before</option>
<option value=">">After</option>
}
<option value=">>" selected>At End</option>
</select>
@if (children != null && children.Count > 0 && (insert == "<" || insert == ">"))
{
<select class="form-control" @bind="@childid">
<option value="-1">&lt;Select Page&gt;</option>
@foreach (Page page in children)
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Path: </label>
</td>
<td>
<input class="form-control" @bind="@path" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Parent: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ParentChanged(e))">
<option value="-1">&lt;Site Root&gt;</option>
@foreach (Page page in pages)
{
<option value="@(page.PageId)">@(page.Name)</option>
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
}
</select>
}
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Navigation? </label>
</td>
<td>
<select class="form-control" @bind="@isnavigation">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Edit Mode? </label>
</td>
<td>
<select class="form-control" @bind="@editmode">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
</td>
<td>
<select class="form-control" @bind="@themetype">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Insert: </label>
</td>
<td>
<select class="form-control" @bind="@insert">
<option value="<<">At Beginning</option>
@if (children != null && children.Count > 0)
{
<option value="<">Before</option>
<option value=">">After</option>
}
<option value=">>">At End</option>
</select>
@if (children != null && children.Count > 0 && (insert == "<" || insert == ">"))
{
<option value="@item.Key">@item.Value</option>
<select class="form-control" @bind="@childid">
<option value="-1">&lt;Select Page&gt;</option>
@foreach (Page page in children)
{
<option value="@(page.PageId)">@(page.Name)</option>
}
</select>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Icon: </label>
</td>
<td>
<input class="form-control" @bind="@icon" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Page" Permissions="@permissions" @ref="permissiongrid" />
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Navigation? </label>
</td>
<td>
<select class="form-control" @bind="@isnavigation">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Personalizable? </label>
</td>
<td>
<select class="form-control" @bind="@ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Mode? </label>
</td>
<td>
<select class="form-control" @bind="@mode">
<option value="view">View Mode</option>
<option value="edit">Edit Mode</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
<option value="@item.Key">@item.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Icon: </label>
</td>
<td>
<input class="form-control" @bind="@icon" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Page" Permissions="@permissions" @ref="permissiongrid" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SavePage">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string message = "";
Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>();
@ -157,7 +156,8 @@
List<Page> children;
int childid = -1;
string isnavigation = "True";
string editmode = "False";
string ispersonalizable = "False";
string mode = "view";
string themetype = "";
string layouttype = "";
string icon = "";
@ -165,7 +165,7 @@
PermissionGrid permissiongrid;
protected override void OnInitialized()
protected override async Task OnInitializedAsync()
{
try
{
@ -173,7 +173,10 @@
children = PageState.Pages.Where(item => item.ParentId == null).ToList();
themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
themetype = PageState.Site.DefaultThemeType;
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
layouttype = PageState.Site.DefaultLayoutType;
List<PermissionString> permissionstrings = new List<PermissionString>();
permissionstrings.Add(new PermissionString { PermissionName = "View", Permissions = Constants.AdminRole });
@ -182,16 +185,17 @@
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
AddModuleMessage("Error Initializing Page", MessageType.Error);
}
}
private void ParentChanged(ChangeEventArgs e)
private async void ParentChanged(ChangeEventArgs e)
{
try
{
parentid = (string)e.Value;
if (string.IsNullOrEmpty(parentid))
if (parentid == "-1")
{
children = PageState.Pages.Where(item => item.ParentId == null).ToList();
}
@ -203,87 +207,121 @@
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", parentid, ex.Message);
AddModuleMessage("Error Loading Child Pages For Parent", MessageType.Error);
}
}
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
themetype = (string)e.Value;
if (themetype != "")
{
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
}
else
{
panelayouts = new Dictionary<string, string>();
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message);
AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error);
}
}
private async Task SavePage()
{
Page page = null;
try
{
Page page = new Page();
page.SiteId = PageState.Page.SiteId;
page.Name = name;
if (path == "")
if (name != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)))
{
path = name;
}
if (path.Contains("/"))
{
path = path.Substring(path.LastIndexOf("/") + 1);
}
if (string.IsNullOrEmpty(parentid))
{
page.ParentId = null;
page.Path = Utilities.GetFriendlyUrl(path);
}
else
{
page.ParentId = Int32.Parse(parentid);
Page parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == "")
page = new Page();
page.SiteId = PageState.Page.SiteId;
page.Name = name;
if (path == "")
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(path);
path = name;
}
if (path.Contains("/"))
{
path = path.Substring(path.LastIndexOf("/") + 1);
}
if (string.IsNullOrEmpty(parentid))
{
page.ParentId = null;
page.Path = Utilities.GetFriendlyUrl(path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(path);
page.ParentId = Int32.Parse(parentid);
Page parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == "")
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(path);
}
}
}
Page child;
switch (insert)
{
case "<<":
page.Order = 0;
break;
case "<":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order - 1;
break;
case ">":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order + 1;
break;
case ">>":
page.Order = int.MaxValue;
break;
}
page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation));
page.EditMode = (editmode == null ? true : Boolean.Parse(editmode));
page.ThemeType = themetype;
page.LayoutType = (layouttype == null ? "" : layouttype);
page.Icon = (icon == null ? "" : icon);
Type type;
if (!string.IsNullOrEmpty(layouttype))
{
type = Type.GetType(layouttype);
Page child;
switch (insert)
{
case "<<":
page.Order = 0;
break;
case "<":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order - 1;
break;
case ">":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order + 1;
break;
case ">>":
page.Order = int.MaxValue;
break;
}
page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation));
page.EditMode = (mode == "edit" ? true : false);
page.ThemeType = themetype;
page.LayoutType = (layouttype == null ? "" : layouttype);
page.Icon = (icon == null ? "" : icon);
page.Permissions = permissiongrid.GetPermissions();
if (page.ThemeType == PageState.Site.DefaultThemeType)
{
page.ThemeType = "";
}
if (page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = "";
}
page.IsPersonalizable = (ispersonalizable == null ? false : Boolean.Parse(ispersonalizable));
page.UserId = null;
await PageService.AddPageAsync(page);
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
await logger.LogInformation("Page Added {Page}", page);
NavigationManager.NavigateTo(NavigateUrl(page.Path, Reload.Site));
}
else
{
type = Type.GetType(themetype);
AddModuleMessage("You Must Provide Page Name And Theme", MessageType.Warning);
}
System.Reflection.PropertyInfo property = type.GetProperty("Panes");
page.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
page.Permissions = permissiongrid.GetPermissions();
await PageService.AddPageAsync(page);
await PageService.UpdatePageOrderAsync(page.SiteId, page.ParentId);
PageState.Reload = Constants.ReloadSite;
NavigationManager.NavigateTo(NavigateUrl(page.Path));
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message);
AddModuleMessage("Error Saving Page", MessageType.Error);
}
}

View File

@ -1,197 +0,0 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Models
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Security
@namespace Oqtane.Modules.Admin.Pages
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@inject IThemeService ThemeService
<ModuleMessage Message="@message" />
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" readonly />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Path: </label>
</td>
<td>
<input class="form-control" @bind="@path" readonly />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Parent: </label>
</td>
<td>
<select class="form-control" @bind="@parentid" readonly>
<option value="">&lt;Select Parent&gt;</option>
@foreach (Page p in PageState.Pages)
{
<option value="@p.PageId">@p.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Navigation? </label>
</td>
<td>
<select class="form-control" @bind="@isnavigation" readonly>
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Edit Mode? </label>
</td>
<td>
<select class="form-control" @bind="@editmode" readonly>
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
</td>
<td>
<select class="form-control" @bind="@themetype" readonly>
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
<option value="@item.Key">@item.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype" readonly>
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Icon: </label>
</td>
<td>
<input class="form-control" @bind="@icon" readonly />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Page" Permissions="@permissions" @ref="permissiongrid" />
</td>
</tr>
</table>
<button type="button" class="btn btn-danger" @onclick="DeletePage">Delete</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string message = "";
Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>();
int PageId;
string name;
string path;
string parentid = "";
string isnavigation;
string editmode;
string themetype;
string layouttype;
string icon;
string permissions;
string createdby;
DateTime createdon;
string modifiedby;
DateTime modifiedon;
PermissionGrid permissiongrid;
protected override void OnInitialized()
{
try
{
themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
PageId = Int32.Parse(PageState.QueryString["id"]);
Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
if (page != null)
{
name = page.Name;
path = page.Path;
isnavigation = page.IsNavigation.ToString();
editmode = page.EditMode.ToString();
themetype = page.ThemeType;
layouttype = page.LayoutType;
icon = page.Icon;
permissions = page.Permissions;
createdby = page.CreatedBy;
createdon = page.CreatedOn;
modifiedby = page.ModifiedBy;
modifiedon = page.ModifiedOn;
}
}
catch (Exception ex)
{
message = ex.Message;
}
}
private async Task DeletePage()
{
try
{
await PageService.DeletePageAsync(Int32.Parse(PageState.QueryString["id"]));
PageState.Reload = Constants.ReloadSite;
if (PageState.Page.Name == "Page Management")
{
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
NavigationManager.NavigateTo(NavigateUrl(""));
}
}
catch (Exception ex)
{
message = ex.Message;
}
}
}

View File

@ -1,19 +1,9 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Models
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Security
@namespace Oqtane.Modules.Admin.Pages
@namespace Oqtane.Modules.Admin.Pages
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@inject IThemeService ThemeService
<ModuleMessage Message="@message" />
<table class="table table-borderless">
<tr>
<td>
@ -37,7 +27,7 @@
</td>
<td>
<select class="form-control" @onchange="(e => ParentChanged(e))">
<option value="">&lt;Site Root&gt;</option>
<option value="-1">&lt;Site Root&gt;</option>
@foreach (Page page in pages)
{
if (page.PageId.ToString() == parentid)
@ -60,7 +50,7 @@
<select class="form-control" @bind="@insert">
@if (parentid == currentparentid)
{
<option value="">&lt;Maintain Current Location&gt;</option>
<option value="=">&lt;Maintain Current Location&gt;</option>
}
<option value="<<">To Beginning</option>
@if (children != null && children.Count > 0)
@ -68,7 +58,7 @@
<option value="<">Before</option>
<option value=">">After</option>
}
<option value=">>" selected>To End</option>
<option value=">>">To End</option>
</select>
@if (children != null && children.Count > 0 && (insert == "<" || insert == ">"))
{
@ -95,25 +85,43 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Edit Mode? </label>
<label for="Name" class="control-label">Personalizable? </label>
</td>
<td>
<select class="form-control" @bind="@editmode">
<select class="form-control" @bind="@ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Mode? </label>
</td>
<td>
<select class="form-control" @bind="@mode">
<option value="view">View Mode</option>
<option value="edit">Edit Mode</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
</td>
<td>
<select class="form-control" @bind="@themetype">
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
<option value="@item.Key">@item.Value</option>
if (item.Key == themetype)
{
<option value="@item.Key" selected>@item.Value</option>
}
else
{
<option value="@item.Key">@item.Value</option>
}
}
</select>
</td>
@ -153,13 +161,11 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string message = "";
Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>();
@ -169,11 +175,12 @@
string path;
string currentparentid;
string parentid;
string insert = "";
string insert = "=";
List<Page> children;
int childid = -1;
string isnavigation;
string editmode;
string ispersonalizable;
string mode;
string themetype;
string layouttype;
string icon;
@ -182,10 +189,12 @@
DateTime createdon;
string modifiedby;
DateTime modifiedon;
string deletedby;
DateTime? deletedon;
PermissionGrid permissiongrid;
protected override void OnInitialized()
protected override async Task OnInitializedAsync()
{
try
{
@ -193,7 +202,6 @@
children = PageState.Pages.Where(item => item.ParentId == null).ToList();
themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
PageId = Int32.Parse(PageState.QueryString["id"]);
Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
@ -215,8 +223,10 @@
}
currentparentid = parentid;
isnavigation = page.IsNavigation.ToString();
editmode = page.EditMode.ToString();
ispersonalizable = page.IsPersonalizable.ToString();
mode = (page.EditMode) ? "edit" : "view";
themetype = page.ThemeType;
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
layouttype = page.LayoutType;
icon = page.Icon;
permissions = page.Permissions;
@ -224,20 +234,23 @@
createdon = page.CreatedOn;
modifiedby = page.ModifiedBy;
modifiedon = page.ModifiedOn;
deletedby = page.DeletedBy;
deletedon = page.DeletedOn;
}
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Loading Page {PageId} {Error}", PageId, ex.Message);
AddModuleMessage("Error Loading Page", MessageType.Error);
}
}
private void ParentChanged(ChangeEventArgs e)
private async void ParentChanged(ChangeEventArgs e)
{
try
{
parentid = (string)e.Value;
if (string.IsNullOrEmpty(parentid))
if (parentid == "-1")
{
children = PageState.Pages.Where(item => item.ParentId == null).ToList();
}
@ -247,7 +260,7 @@
}
if (parentid == currentparentid)
{
insert = "";
insert = "=";
}
else
{
@ -257,109 +270,142 @@
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", parentid, ex.Message);
AddModuleMessage("Error Loading Child Pages For Parent", MessageType.Error);
}
}
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
themetype = (string)e.Value;
if (themetype != "")
{
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
}
else
{
panelayouts = new Dictionary<string, string>();
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message);
AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error);
}
}
private async Task SavePage()
{
Page page = null;
try
{
Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
string currentpath = page.Path;
if (name != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)))
{
page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
string currentpath = page.Path;
page.Name = name;
if (path == "")
{
path = name;
}
if (path.Contains("/"))
{
path = path.Substring(path.LastIndexOf("/") + 1);
}
if (string.IsNullOrEmpty(parentid))
{
page.ParentId = null;
page.Path = Utilities.GetFriendlyUrl(path);
}
else
{
page.ParentId = Int32.Parse(parentid);
Page parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == "")
page.Name = name;
if (path == "" && name.ToLower() != "home")
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(path);
path = name;
}
if (path.Contains("/"))
{
path = path.Substring(path.LastIndexOf("/") + 1);
}
if (string.IsNullOrEmpty(parentid))
{
page.ParentId = null;
page.Path = Utilities.GetFriendlyUrl(path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(path);
page.ParentId = Int32.Parse(parentid);
Page parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == "")
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(path);
}
}
}
if (insert != "")
{
Page child;
switch (insert)
if (insert != "=")
{
case "<<":
page.Order = 0;
break;
case "<":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order - 1;
break;
case ">":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order + 1;
break;
case ">>":
page.Order = int.MaxValue;
break;
Page child;
switch (insert)
{
case "<<":
page.Order = 0;
break;
case "<":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order - 1;
break;
case ">":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = child.Order + 1;
break;
case ">>":
page.Order = int.MaxValue;
break;
}
}
}
page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation));
page.EditMode = (editmode == null ? true : Boolean.Parse(editmode));
page.ThemeType = themetype;
page.LayoutType = (layouttype == null ? "" : layouttype);
page.Icon = (icon == null ? "" : icon);
Type type;
if (!string.IsNullOrEmpty(layouttype))
{
type = Type.GetType(layouttype);
page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation));
page.EditMode = (mode == "edit" ? true : false);
page.ThemeType = themetype;
page.LayoutType = (layouttype == null ? "" : layouttype);
page.Icon = (icon == null ? "" : icon);
page.Permissions = permissiongrid.GetPermissions();
if (page.ThemeType == PageState.Site.DefaultThemeType)
{
page.ThemeType = "";
}
if (page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = "";
}
page.IsPersonalizable = (ispersonalizable == null ? false : Boolean.Parse(ispersonalizable));
page.UserId = null;
await PageService.UpdatePageAsync(page);
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
if (currentparentid == "")
{
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, null);
}
else
{
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, int.Parse(currentparentid));
}
// update child paths
if (parentid != currentparentid)
{
foreach (Page p in PageState.Pages.Where(item => item.Path.StartsWith(currentpath)))
{
p.Path = p.Path.Replace(currentpath, page.Path);
await PageService.UpdatePageAsync(p);
}
}
await logger.LogInformation("Page Saved {Page}", page);
NavigationManager.NavigateTo(NavigateUrl(page.Path, Reload.Site));
}
else
{
type = Type.GetType(themetype);
AddModuleMessage("You Must Provide Page Name And Theme", MessageType.Warning);
}
System.Reflection.PropertyInfo property = type.GetProperty("Panes");
page.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
page.Permissions = permissiongrid.GetPermissions();
await PageService.UpdatePageAsync(page);
await PageService.UpdatePageOrderAsync(page.SiteId, page.ParentId);
if (currentparentid == "")
{
await PageService.UpdatePageOrderAsync(page.SiteId, null);
}
else
{
await PageService.UpdatePageOrderAsync(page.SiteId, int.Parse(currentparentid));
}
// update child paths
if (parentid != currentparentid)
{
foreach (Page p in PageState.Pages.Where(item => item.Path.StartsWith(currentpath)))
{
p.Path = p.Path.Replace(currentpath, page.Path);
await PageService.UpdatePageAsync(p);
}
}
PageState.Reload = Constants.ReloadSite;
NavigationManager.NavigateTo(NavigateUrl(page.Path));
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message);
AddModuleMessage("Error Saving Page", MessageType.Error);
}
}
}

View File

@ -1,37 +1,42 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Shared
@namespace Oqtane.Modules.Admin.Pages
@namespace Oqtane.Modules.Admin.Pages
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@if (PageState.Pages != null)
{
<ActionLink Action="Add" Text="Add Page" />
<table class="table table-borderless">
<thead>
<tr>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (Page page in PageState.Pages)
{
<tr>
<td><ActionLink Action="Edit" Parameters="@($"id=" + page.PageId.ToString())" /></td>
<td><ActionLink Action="Delete" Parameters="@($"id=" + page.PageId.ToString())" Class="btn btn-danger" /></td>
<td>@(new string('-', page.Level * 2))@(page.Name)</td>
</tr>
}
</tbody>
</table>
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" /></td>
<td><ActionDialog Header="Delete Page" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Page?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" /></td>
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private async Task DeletePage(Page Page)
{
try
{
Page.IsDeleted = true;
await PageService.UpdatePageAsync(Page);
await logger.LogInformation("Page Deleted {Page}", Page);
NavigationManager.NavigateTo(NavigateUrl("admin/pages", Reload.Site));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Page {Page} {Error}", Page, ex.Message);
AddModuleMessage("Error Deleting Page", MessageType.Error);
}
}
}

View File

@ -0,0 +1,165 @@
@namespace Oqtane.Modules.Admin.Profiles
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IProfileService ProfileService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Title: </label>
</td>
<td>
<input class="form-control" @bind="@title" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Description: </label>
</td>
<td>
<textarea class="form-control" @bind="@description" rows="5" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Category: </label>
</td>
<td>
<input class="form-control" @bind="@category" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Order: </label>
</td>
<td>
<input class="form-control" @bind="@vieworder" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Length: </label>
</td>
<td>
<input class="form-control" @bind="@maxlength" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Value: </label>
</td>
<td>
<input class="form-control" @bind="@defaultvalue" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Required? </label>
</td>
<td>
<select class="form-control" @bind="@isrequired">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Private? </label>
</td>
<td>
<select class="form-control" @bind="@isprivate">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveProfile">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Actions { get { return "Add,Edit"; } }
int profileid = -1;
string name = "";
string title = "";
string description = "";
string category = "";
string vieworder = "0";
string maxlength = "0";
string defaultvalue = "";
string isrequired = "False";
string isprivate = "False";
protected override async Task OnInitializedAsync()
{
try
{
if (PageState.QueryString.ContainsKey("id"))
{
profileid = Int32.Parse(PageState.QueryString["id"]);
Profile profile = await ProfileService.GetProfileAsync(profileid);
if (profile != null)
{
name = profile.Name;
title = profile.Title;
description = profile.Description;
category = profile.Category;
vieworder = profile.ViewOrder.ToString();
maxlength = profile.MaxLength.ToString();
defaultvalue = profile.DefaultValue;
isrequired = profile.IsRequired.ToString();
isprivate = profile.IsPrivate.ToString();
}
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Profile {ProfileId} {Error}", profileid, ex.Message);
AddModuleMessage("Error Loading Profile", MessageType.Error);
}
}
private async Task SaveProfile()
{
try
{
Profile profile;
if (profileid != -1)
{
profile = await ProfileService.GetProfileAsync(profileid);
}
else
{
profile = new Profile();
}
profile.Name = name;
profile.Title = title;
profile.Description = description;
profile.Category = category;
profile.ViewOrder = int.Parse(vieworder);
profile.MaxLength = int.Parse(maxlength);
profile.DefaultValue = defaultvalue;
profile.IsRequired = (isrequired == null ? false : Boolean.Parse(isrequired));
profile.IsPrivate = (isprivate == null ? false : Boolean.Parse(isprivate));
profile = await ProfileService.UpdateProfileAsync(profile);
await logger.LogInformation("Profile Saved {Profile}", profile);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Profile {ProfleId} {Error}", profileid, ex.Message);
AddModuleMessage("Error Saving Profile", MessageType.Error);
}
}
}

View File

@ -0,0 +1,51 @@
@namespace Oqtane.Modules.Admin.Profiles
@inherits ModuleBase
@inject IProfileService ProfileService
@if (Profiles == null)
{
<p><em>Loading...</em></p>
}
else
{
<ActionLink Action="Add" Security="SecurityAccessLevel.Admin" Text="Add Profile" />
<Pager Items="@Profiles">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" /></td>
<td><ActionDialog Header="Delete Profile" Message="@("Are You Sure You Wish To Delete " + context.Name + "?")" Action="Delete" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" /></td>
<td>@context.Name</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<Profile> Profiles;
protected override async Task OnInitializedAsync()
{
Profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
}
private async Task DeleteProfile(int ProfileId)
{
try
{
await ProfileService.DeleteProfileAsync(ProfileId);
await logger.LogInformation("Profile Deleted {ProfileId}", ProfileId);
AddModuleMessage("Profile Deleted", MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Profile {ProfileId} {Error}", ProfileId, ex.Message);
AddModuleMessage("Error Deleting Profile", MessageType.Error);
}
}
}

View File

@ -0,0 +1,174 @@
@namespace Oqtane.Modules.Admin.RecycleBin
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageModuleService PageModuleService
@inject IModuleService ModuleService
@inject IPageService PageService
<TabControl>
<TabPanel Text="Pages">
@if (pages.Count == 0)
{
<br/>
<p>No Deleted Pages</p>
}
else
{
<Pager Items="@pages">
<Header>
<th>Name</th>
<th>Deleted By</th>
<th>Deleted On</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.DeletedBy</td>
<td>@context.DeletedOn</td>
<td><button @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td>
<td><button @onclick="@(() => DeletePage(context.PageId))" class="btn btn-danger">Delete</button></td>
</Row>
</Pager>
}
</TabPanel>
<TabPanel Text="Modules">
@if (pageModules.Count == 0)
{
<br/>
<p>No Deleted Modules</p>
}
else
{
<Pager Items="@pageModules">
<Header>
<th>Page</th>
<th>Module</th>
<th>Deleted By</th>
<th>Deleted On</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td>
<td>@context.Title</td>
<td>@context.DeletedBy</td>
<td>@context.DeletedOn</td>
<td><button @onclick="@(() => RestorePageModule(context))" class="btn btn-info" title="Restore">Restore</button></td>
<td><button @onclick="@(() => DeletePageModule(context.PageModuleId, context.ModuleId))" class="btn btn-danger">Delete</button></td>
</Row>
</Pager>
}
</TabPanel>
</TabControl>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<Page> pages { get; set; }
List<PageModule> pageModules { get; set; }
protected override async Task OnInitializedAsync()
{
try
{
pages = new List<Page>();
pageModules = new List<PageModule>();
await LoadEntities();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Deleted Pages Or Modules {Error}", ex.Message);
AddModuleMessage("Error Loading Deleted Pages Or Modules", MessageType.Error);
}
}
protected override void OnParametersSet()
{
pages = PageState.Pages.Where(item => item.IsDeleted).ToList();
}
private async Task LoadEntities()
{
pageModules.Clear();
foreach (var module in PageState.Modules.Where(item => item.IsDeleted))
{
var pageModule = await PageModuleService.GetPageModuleAsync(module.PageModuleId);
pageModules.Add(pageModule);
}
}
private async Task RestorePage(Page Page)
{
try
{
Page.IsDeleted = false;
await PageService.UpdatePageAsync(Page);
await logger.LogInformation("Page Restored {Page}", Page);
NavigationManager.NavigateTo(NavigateUrl(Reload.Site));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Restoring Deleted Page {Page} {Error}", Page, ex.Message);
AddModuleMessage("Error Restoring Deleted Page", MessageType.Error);
}
}
private async Task DeletePage(int PageId)
{
try
{
var deletedPageModules = PageState.Modules.Where(item => item.PageId == PageId);
await PageService.DeletePageAsync(PageId);
foreach (var module in deletedPageModules)
{
await ModuleService.DeleteModuleAsync(module.ModuleId);
}
await logger.LogInformation("Page Permanently Deleted {PageId}", PageId);
NavigationManager.NavigateTo(NavigateUrl(Reload.Site));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Permanently Deleting Page {PageId} {Error}", PageId, ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
private async Task RestorePageModule(PageModule PageModule)
{
try
{
PageModule.IsDeleted = false;
await PageModuleService.UpdatePageModuleAsync(PageModule);
await LoadEntities();
await logger.LogInformation("Page Module Restored {PageModule}", PageModule);
NavigationManager.NavigateTo(NavigateUrl(Reload.Site));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Restoring Deleted Page Module {PageModule} {Error}", PageModule, ex.Message);
AddModuleMessage("Error Restoring Deleted Page Module", MessageType.Error);
}
}
private async Task DeletePageModule(int PageModuleId, int ModuleId)
{
try
{
await PageModuleService.DeletePageModuleAsync(PageModuleId);
if (PageState.Modules.Count(item => item.ModuleId == ModuleId) == 1)
{
await ModuleService.DeleteModuleAsync(ModuleId);
}
PageState.Modules.RemoveAt(PageState.Modules.FindIndex(item => item.ModuleId == ModuleId));
await LoadEntities();
await logger.LogInformation("Page Module Permanently Deleted {PageModuleId}", PageModuleId);
NavigationManager.NavigateTo(NavigateUrl(Reload.Site));
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Permanently Deleting Page Module {PageModuleId} {Error}", PageModuleId, ex.Message);
AddModuleMessage("Error Permanently Deleting Page Module", MessageType.Error);
}
}
}

View File

@ -1,21 +1,20 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Services
@namespace Oqtane.Modules.Admin.Register
@namespace Oqtane.Modules.Admin.Register
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
<div class="container">
<div class="form-group">
<label for="Username" class="control-label">Email: </label>
<input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Email" />
<label for="Username" class="control-label">Username: </label>
<input type="text" class="form-control" placeholder="Username" @bind="@Username" />
</div>
<div class="form-group">
<label for="Password" class="control-label">Password: </label>
<input type="password" name="Password" class="form-control" placeholder="Password" @bind="@Password" />
<input type="password" class="form-control" placeholder="Password" @bind="@Password" />
</div>
<div class="form-group">
<label for="Username" class="control-label">Email: </label>
<input type="text" class="form-control" placeholder="Username" @bind="@Email" />
</div>
<button type="button" class="btn btn-primary" @onclick="RegisterUser">Register</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
@ -24,24 +23,49 @@
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
public string Email { get; set; } = "";
public string Password { get; set; } = "";
string Username = "";
string Password = "";
string Email = "";
private async Task RegisterUser()
{
User user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = Email;
user.DisplayName = Email;
user.Email = Email;
user.IsHost = false;
user.Password = Password;
await UserService.AddUserAsync(user);
NavigationManager.NavigateTo("");
try
{
if (Username != "" && Password != "" && Email != "")
{
User user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = Username;
user.DisplayName = Username;
user.Email = Email;
user.Password = Password;
user = await UserService.AddUserAsync(user);
if (user != null)
{
await logger.LogInformation("User Created {Username} {Email}", Username, Email);
NavigationManager.NavigateTo(NavigateUrl(""));
}
else
{
await logger.LogError("Error Adding User {Username} {Email}", Username, Email);
AddModuleMessage("Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Provide A Username, Password, and Email Address", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", Username, Email, ex.Message);
AddModuleMessage("Error Adding User", MessageType.Error);
}
}
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl("")); // navigate to home
NavigationManager.NavigateTo(NavigateUrl(""));
}
}

View File

@ -0,0 +1,79 @@
@namespace Oqtane.Modules.Admin.Roles
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IRoleService RoleService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Description: </label>
</td>
<td>
<textarea class="form-control" @bind="@description" rows="5" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Auto Assigned? </label>
</td>
<td>
<select class="form-control" @bind="@isautoassigned">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">System Role? </label>
</td>
<td>
<select class="form-control" @bind="@issystem">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveRole">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string name = "";
string description = "";
string isautoassigned = "False";
string issystem = "False";
private async Task SaveRole()
{
try
{
Role role = new Role();
role.SiteId = PageState.Page.SiteId;
role.Name = name;
role.Description = description;
role.IsAutoAssigned = (isautoassigned == null ? false : Boolean.Parse(isautoassigned));
role.IsSystem = (issystem == null ? false : Boolean.Parse(issystem));
role = await RoleService.AddRoleAsync(role);
await logger.LogInformation("Role Added {Role}", role);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Adding Role", ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -0,0 +1,98 @@
@namespace Oqtane.Modules.Admin.Roles
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IRoleService RoleService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Description: </label>
</td>
<td>
<textarea class="form-control" @bind="@description" rows="5" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Auto Assigned? </label>
</td>
<td>
<select class="form-control" @bind="@isautoassigned">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">System Role? </label>
</td>
<td>
<select class="form-control" @bind="@issystem">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveRole">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
int roleid;
string name = "";
string description = "";
string isautoassigned = "False";
string issystem = "False";
protected override async Task OnInitializedAsync()
{
try
{
roleid = Int32.Parse(PageState.QueryString["id"]);
Role role = await RoleService.GetRoleAsync(roleid);
if (role != null)
{
name = role.Name;
description = role.Description;
isautoassigned = role.IsAutoAssigned.ToString();
issystem = role.IsSystem.ToString();
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Role {RoleId} {Error}", roleid, ex.Message);
AddModuleMessage("Error Loading Role", MessageType.Error);
}
}
private async Task SaveRole()
{
try
{
Role role = await RoleService.GetRoleAsync(roleid);
role.Name = name;
role.Description = description;
role.IsAutoAssigned = (isautoassigned == null ? false : Boolean.Parse(isautoassigned));
role.IsSystem = (issystem == null ? false : Boolean.Parse(issystem));
role = await RoleService.UpdateRoleAsync(role);
await logger.LogInformation("Role Saved {Role}", role);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Role {RoleId} {Error}", roleid, ex.Message);
AddModuleMessage("Error Saving Role", MessageType.Error);
}
}
}

View File

@ -1,9 +1,4 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.Roles
@namespace Oqtane.Modules.Admin.Roles
@inherits ModuleBase
@inject IRoleService RoleService
@ -13,21 +8,20 @@
}
else
{
<table class="table table-borderless">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (var Role in Roles)
{
<tr>
<td>@Role.Name</td>
</tr>
}
</tbody>
</table>
<ActionLink Action="Add" Text="Add Role" />
<Pager Items="@Roles">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" /></td>
<td><ActionDialog Header="Delete Role" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Role?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" /></td>
<td>@context.Name</td>
</Row>
</Pager>
}
@code {
@ -35,8 +29,23 @@ else
List<Role> Roles;
protected override async Task OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
Roles = await RoleService.GetRolesAsync(PageState.Site.SiteId);
}
private async Task DeleteRole(Role Role)
{
try
{
await RoleService.DeleteRoleAsync(Role.RoleId);
await logger.LogInformation("Role Deleted {Role}", Role);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Role {Role} {Error}", Role, ex.Message);
AddModuleMessage("Error Deleting Role", MessageType.Error);
}
}
}

View File

@ -1,17 +1,11 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Models
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Security
@namespace Oqtane.Modules.Admin.Sites
@namespace Oqtane.Modules.Admin.Sites
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ITenantService TenantService
@inject IAliasService AliasService
@inject ISiteService SiteService
@inject IPageService PageService
@inject IThemeService ThemeService
@inject IUserService UserService
@if (tenants == null)
{
@ -19,46 +13,107 @@
}
else
{
<table class="table table-borderless">
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Tenant: </label>
</td>
<td>
<select class="form-control" @onchange="(e => TenantChanged(e))">
<option value="-1">&lt;Select Tenant&gt;</option>
@foreach (Tenant tenant in tenants)
{
<option value="@tenant.TenantId">@tenant.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Aliases: </label>
</td>
<td>
<textarea class="form-control" @bind="@urls" rows="3" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Logo: </label>
</td>
<td>
<input class="form-control" @bind="@logo" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Theme: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
<option value="@item.Key">@item.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Container: </label>
</td>
<td>
<select class="form-control" @bind="@containertype">
<option value="">&lt;Select Container&gt;</option>
@foreach (KeyValuePair<string, string>container in containers)
{
<option value="@container.Key">@container.Value</option>
}
</select>
</td>
</tr>
@if (!isinitialized)
{
<tr>
<td>
<label for="Name" class="control-label">Tenant: </label>
<label for="Name" class="control-label">Host Username:</label>
</td>
<td>
<select class="form-control" @bind="@tenantid">
<option value="">&lt;Select Tenant&gt;</option>
@foreach (Tenant tenant in tenants)
{
<option value="@tenant.TenantId">@tenant.Name</option>
}
</select>
<input class="form-control" @bind="@username" disabled />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
<label for="Name" class="control-label">Host Password:</label>
</td>
<td>
<input class="form-control" @bind="@name" />
<input type="password" class="form-control" @bind="@password" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Alias: </label>
</td>
<td>
<input class="form-control" @bind="@url" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Logo: </label>
</td>
<td>
<input class="form-control" @bind="@logo" />
</td>
</tr>
</table>
}
</table>
<button type="button" class="btn btn-success" @onclick="SaveSite">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
@ -66,54 +121,152 @@ else
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>();
Dictionary<string, string> containers = new Dictionary<string, string>();
List<Tenant> tenants;
string tenantid = "";
string tenantid = "-1";
string name = "";
string url = "";
string urls = "";
string logo = "";
string themetype = "";
string layouttype = "";
string containertype = "";
bool isinitialized = true;
string username = "";
string password = "";
protected override async Task OnInitializedAsync()
{
tenants = await TenantService.GetTenantsAsync();
urls = PageState.Alias.Name;
themes = ThemeService.GetThemeTypes(PageState.Themes);
containers = ThemeService.GetContainerTypes(PageState.Themes);
username = PageState.User.Username;
}
private async void TenantChanged(ChangeEventArgs e)
{
try
{
tenantid = (string)e.Value;
if (tenantid != "-1")
{
Tenant tenant = tenants.Where(item => item.TenantId == int.Parse(tenantid)).FirstOrDefault();
if (tenant != null)
{
isinitialized = tenant.IsInitialized;
StateHasChanged();
}
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", tenantid, ex.Message);
AddModuleMessage("Error Loading Tenant", MessageType.Error);
}
}
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
themetype = (string)e.Value;
if (themetype != "")
{
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
}
else
{
panelayouts = new Dictionary<string, string>();
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message);
AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error);
}
}
private async Task SaveSite()
{
Site site = new Site();
site.Name = name;
site.Logo = (logo == null ? "" : logo);
await SiteService.AddSiteAsync(site);
List<Site> sites = await SiteService.GetSitesAsync();
site = sites.Where(item => item.Name == name).FirstOrDefault();
if (tenantid != "-1" && name != "" && urls != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)) && !string.IsNullOrEmpty(containertype))
{
bool isvalid = true;
Alias alias = new Alias();
alias.Name = url;
alias.TenantId = int.Parse(tenantid);
alias.SiteId = site.SiteId;
await AliasService.AddAliasAsync(alias);
if (!isinitialized)
{
User user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
user = await UserService.LoginUserAsync(user, false, false);
isvalid = user.IsAuthenticated;
}
// need to add a home page and admin pages
Page p = new Page();
p.SiteId = site.SiteId;
p.ParentId = null;
p.Name = "Home";
p.Path = "";
p.Order = 1;
p.IsNavigation = true;
p.ThemeType = PageState.Site.DefaultThemeType;
p.LayoutType = "";
p.Icon = "";
Type type = Type.GetType(p.ThemeType);
System.Reflection.PropertyInfo property = type.GetProperty("Panes");
p.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
if (isvalid)
{
List<Alias> aliases = new List<Alias>();
urls = urls.Replace("\n", ",");
foreach (string name in urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
Alias alias = new Alias();
alias.Name = name;
alias.TenantId = int.Parse(tenantid);
alias.SiteId = -1;
alias = await AliasService.AddAliasAsync(alias);
aliases.Add(alias);
}
List<PermissionString> permissionstrings = new List<PermissionString>();
permissionstrings.Add(new PermissionString { PermissionName = "View", Permissions = Constants.AllUsersRole });
permissionstrings.Add(new PermissionString { PermissionName = "Edit", Permissions = Constants.AdminRole });
p.Permissions = UserSecurity.SetPermissionStrings(permissionstrings);
Site site = new Site();
site.TenantId = int.Parse(tenantid);
site.Name = name;
site.Logo = (logo == null ? "" : logo);
site.DefaultThemeType = themetype;
site.DefaultLayoutType = (layouttype == null ? "" : layouttype);
site.DefaultContainerType = containertype;
site = await SiteService.AddSiteAsync(site, aliases[0]);
await PageService.AddPageAsync(p);
foreach(Alias alias in aliases)
{
alias.SiteId = site.SiteId;
await AliasService.UpdateAliasAsync(alias);
}
if (!isinitialized)
{
User user = new User();
user.SiteId = site.SiteId;
user.Username = username;
user.Password = password;
user.Email = PageState.User.Email;
user.DisplayName = PageState.User.DisplayName;
user = await UserService.AddUserAsync(user, aliases[0]);
if (user != null)
{
Tenant tenant = tenants.Where(item => item.TenantId == int.Parse(tenantid)).FirstOrDefault();
tenant.IsInitialized = true;
await TenantService.UpdateTenantAsync(tenant);
}
}
await logger.LogInformation("Site Created {Site}", site);
Uri uri = new Uri(NavigationManager.Uri);
NavigationManager.NavigateTo(uri.Scheme + "://" + aliases[0].Name, true);
}
else
{
await logger.LogError("Invalid Password Entered For Host {Username}", username);
AddModuleMessage("Invalid Host Password", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, And Default Theme/Container", MessageType.Warning);
}
NavigationManager.NavigateTo(url, true);
}
}

View File

@ -0,0 +1,248 @@
@namespace Oqtane.Modules.Admin.Sites
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ISiteService SiteService
@inject IAliasService AliasService
@inject IThemeService ThemeService
@if (themes == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Aliases: </label>
</td>
<td>
<textarea class="form-control" @bind="@urls" rows="3" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Logo: </label>
</td>
<td>
<input class="form-control" @bind="@logo" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Theme: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
if (item.Key == themetype)
{
<option value="@item.Key" selected>@item.Value</option>
}
else
{
<option value="@item.Key">@item.Value</option>
}
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Container: </label>
</td>
<td>
<select class="form-control" @bind="@containertype">
<option value="">&lt;Select Container&gt;</option>
@foreach (KeyValuePair<string, string> container in containers)
{
<option value="@container.Key">@container.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveSite">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>();
Dictionary<string, string> containers = new Dictionary<string, string>();
Alias Alias;
int siteid;
string name = "";
List<Alias> aliases;
string urls = "";
string logo = "";
string themetype;
string layouttype;
string containertype;
string createdby;
DateTime createdon;
string modifiedby;
DateTime modifiedon;
string deletedby;
DateTime? deletedon;
string isdeleted;
protected override async Task OnInitializedAsync()
{
try
{
themes = ThemeService.GetThemeTypes(PageState.Themes);
containers = ThemeService.GetContainerTypes(PageState.Themes);
Alias = PageState.Aliases.Where(item => item.AliasId == Int32.Parse(PageState.QueryString["id"])).FirstOrDefault();
siteid = Alias.SiteId;
Site site = await SiteService.GetSiteAsync(siteid, Alias);
if (site != null)
{
name = site.Name;
aliases = PageState.Aliases.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList();
foreach (Alias alias in aliases)
{
urls += alias.Name + "\n";
}
logo = site.Logo;
themetype = site.DefaultThemeType;
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
layouttype = site.DefaultLayoutType;
containertype = site.DefaultContainerType;
createdby = site.CreatedBy;
createdon = site.CreatedOn;
modifiedby = site.ModifiedBy;
modifiedon = site.ModifiedOn;
deletedby = site.DeletedBy;
deletedon = site.DeletedOn;
isdeleted = site.IsDeleted.ToString();
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", siteid, ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
themetype = (string)e.Value;
if (themetype != "")
{
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
}
else
{
panelayouts = new Dictionary<string, string>();
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message);
AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error);
}
}
private async Task SaveSite()
{
try
{
if (name != "" && urls != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)) && !string.IsNullOrEmpty(containertype))
{
Site site = await SiteService.GetSiteAsync(siteid, Alias);
if (site != null)
{
site.Name = name;
site.Logo = (logo == null ? "" : logo);
site.DefaultThemeType = themetype;
site.DefaultLayoutType = (layouttype == null ? "" : layouttype);
site.DefaultContainerType = containertype;
site.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
site = await SiteService.UpdateSiteAsync(site, Alias);
urls = urls.Replace("\n", ",");
string[] names = urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (Alias alias in aliases)
{
if (!names.Contains(alias.Name))
{
await AliasService.DeleteAliasAsync(alias.AliasId);
}
}
foreach (string name in names)
{
if (!aliases.Exists(item => item.Name == name))
{
Alias alias = new Alias();
alias.Name = name;
alias.TenantId = site.TenantId;
alias.SiteId = site.SiteId;
await AliasService.AddAliasAsync(alias);
}
}
await logger.LogInformation("Site Saved {Site}", site);
NavigationManager.NavigateTo(NavigateUrl(Reload.Site));
}
}
else
{
AddModuleMessage("You Must Provide A Site Name, Alias, And Default Theme/Container", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", siteid, ex.Message);
AddModuleMessage("Error Saving Site", MessageType.Error);
}
}
}

View File

@ -1,11 +1,7 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.Sites
@namespace Oqtane.Modules.Admin.Sites
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IAliasService AliasService
@inject ISiteService SiteService
@if (sites == null)
@ -14,31 +10,55 @@
}
else
{
<table class="table table-borderless">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (var site in sites)
{
<tr>
<td>@site.Name</td>
</tr>
}
</tbody>
</table>
<ActionLink Action="Add" Text="Add Site" />
<Pager Items="@sites">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.AliasId.ToString())" /></td>
<td><ActionDialog Header="Delete Site" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Site?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteSite(context))" /></td>
<td><a href="@(scheme + context.Name)">@context.Name</a></td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
List<Site> sites;
List<Alias> sites;
string scheme;
protected override async Task OnInitializedAsync()
protected override void OnParametersSet()
{
sites = await SiteService.GetSitesAsync();
Uri uri = new Uri(NavigationManager.Uri);
scheme = uri.Scheme + "://";
sites = new List<Alias>();
foreach (Alias alias in PageState.Aliases.OrderBy(item => item.Name))
{
if (!sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId))
{
sites.Add(alias);
}
}
}
private async Task DeleteSite(Alias Alias)
{
try
{
await SiteService.DeleteSiteAsync(Alias.SiteId, Alias);
await logger.LogInformation("Sited Deleted {Alias}", Alias);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Site {Error}", ex.Message);
AddModuleMessage("Error Deleting Site", MessageType.Error);
}
}
}

View File

@ -0,0 +1,82 @@
@namespace Oqtane.Modules.Admin.Tenants
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ITenantService TenantService
@inject IInstallationService InstallationService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Connection String: </label>
</td>
<td>
<input class="form-control" @bind="@connectionstring" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Schema: </label>
</td>
<td>
<input class="form-control" @bind="@schema" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveTenant">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
string name = "";
string connectionstring = "";
string schema = "";
protected override async Task OnInitializedAsync()
{
try
{
List<Tenant> tenants = await TenantService.GetTenantsAsync();
connectionstring = tenants.FirstOrDefault().DBConnectionString;
schema = tenants.FirstOrDefault().DBSchema;
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
AddModuleMessage("Error Loading Tenants", MessageType.Error);
}
}
private async Task SaveTenant()
{
ShowProgressIndicator();
connectionstring = connectionstring.Replace("\\\\", "\\");
GenericResponse response = await InstallationService.Install(connectionstring);
if (response.Success)
{
Tenant tenant = new Tenant();
tenant.Name = name;
tenant.DBConnectionString = connectionstring;
tenant.DBSchema = schema;
tenant.IsInitialized = false;
await TenantService.AddTenantAsync(tenant);
await logger.LogInformation("Tenant Created {Tenant}", tenant);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
await logger.LogError("Error Creating Tenant {Error}", response.Message);
AddModuleMessage(response.Message, MessageType.Error);
}
}
}

View File

@ -0,0 +1,86 @@
@namespace Oqtane.Modules.Admin.Tenants
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ITenantService TenantService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Connection String: </label>
</td>
<td>
<input class="form-control" @bind="@connectionstring" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Schema: </label>
</td>
<td>
<input class="form-control" @bind="@schema" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveTenant">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
int tenantid;
string name = "";
string connectionstring = "";
string schema = "";
protected override async Task OnInitializedAsync()
{
try
{
tenantid = Int32.Parse(PageState.QueryString["id"]);
Tenant tenant = await TenantService.GetTenantAsync(tenantid);
if (tenant != null)
{
name = tenant.Name;
connectionstring = tenant.DBConnectionString;
schema = tenant.DBSchema;
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", tenantid, ex.Message);
AddModuleMessage("Error Loading Tenant", MessageType.Error);
}
}
private async Task SaveTenant()
{
try
{
connectionstring = connectionstring.Replace("\\\\", "\\");
Tenant tenant = await TenantService.GetTenantAsync(tenantid);
if (tenant != null)
{
tenant.Name = name;
tenant.DBConnectionString = connectionstring;
tenant.DBSchema = schema;
await TenantService.UpdateTenantAsync(tenant);
await logger.LogInformation("Tenant Saved {TenantId}", tenantid);
NavigationManager.NavigateTo(NavigateUrl());
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Tenant {TenantId} {Error}", tenantid, ex.Message);
AddModuleMessage("Error Saving Tenant", MessageType.Error);
}
}
}

View File

@ -0,0 +1,52 @@
@namespace Oqtane.Modules.Admin.Tenants
@inherits ModuleBase
@inject ITenantService TenantService
@if (tenants == null)
{
<p><em>Loading...</em></p>
}
else
{
<ActionLink Action="Add" Text="Add Tenant" />
<Pager Items="@tenants">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.TenantId.ToString())" /></td>
<td><ActionDialog Header="Delete Tenant" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Tenant?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTenant(context))" /></td>
<td>@context.Name</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
List<Tenant> tenants;
protected override async Task OnParametersSetAsync()
{
tenants = await TenantService.GetTenantsAsync();
}
private async Task DeleteTenant(Tenant Tenant)
{
try
{
await TenantService.DeleteTenantAsync(Tenant.TenantId);
await logger.LogInformation("Tenant Deleted {Tenant}", Tenant);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Tenant {Tenant} {Error}", Tenant, ex.Message);
AddModuleMessage("Error Deleting Tenant", MessageType.Error);
}
}
}

View File

@ -0,0 +1,121 @@
@namespace Oqtane.Modules.Admin.Themes
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IFileService FileService
@inject IThemeService ThemeService
@inject IPackageService PackageService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
</td>
<td>
<FileUpload Filter=".nupkg" @ref="fileupload"></FileUpload>
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="UploadTheme">Upload Theme</button>
@if (packages != null)
{
<hr class="app-rule" />
<div class="mx-auto text-center"><h2>Available Themes</h2></div>
<Pager Items="@packages">
<Header>
<th>Name</th>
<th>Version</th>
<th></th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadTheme(context.PackageId, context.Version))>Download Theme</button>
</td>
</Row>
</Pager>
}
@if (uploaded)
{
<button type="button" class="btn btn-success" @onclick="InstallThemes">Install</button>
}
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
bool uploaded = false;
List<Package> packages;
FileUpload fileupload;
protected override async Task OnInitializedAsync()
{
List<Theme> themes = await ThemeService.GetThemesAsync();
packages = await PackageService.GetPackagesAsync("theme");
foreach(Package package in packages.ToArray())
{
if (themes.Exists(item => Utilities.GetTypeName(item.ThemeName) == package.PackageId))
{
packages.Remove(package);
}
}
}
private async Task UploadTheme()
{
string[] files = await fileupload.GetFiles();
if (files.Length > 0)
{
if (files[0].Contains(".Theme."))
{
try
{
string result = await FileService.UploadFilesAsync("Themes", files, "");
if (result == "")
{
await logger.LogInformation("Theme Uploaded {Package}", files[0]);
AddModuleMessage("Theme Uploaded Successfully. Click Install To Complete Installation.", MessageType.Success);
uploaded = true;
StateHasChanged();
}
else
{
await logger.LogInformation("Theme Upload Failed For {Package}", result.Replace(",",", "));
AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Theme Upload Failed {Package} {Error}", files[0], ex.Message);
AddModuleMessage("Theme Upload Failed", MessageType.Error);
}
}
else
{
await logger.LogError("Invalid Theme Package {Package}", files[0]);
AddModuleMessage("Invalid Theme Package", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Select A Theme To Upload", MessageType.Warning);
}
}
private async Task InstallThemes()
{
await ThemeService.InstallThemesAsync();
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
private async Task DownloadTheme(string packageid, string version)
{
await PackageService.DownloadPackageAsync(packageid, version, "Themes");
AddModuleMessage("Theme Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
uploaded = true;
StateHasChanged();
}
}

View File

@ -1,42 +1,78 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@namespace Oqtane.Modules.Admin.Themes
@namespace Oqtane.Modules.Admin.Themes
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService
@inject IPackageService PackageService
@if (Themes == null)
@if (themes == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-borderless">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (var theme in Themes)
{
<tr>
<td>@theme.Name</td>
</tr>
}
</tbody>
</table>
<ActionLink Action="Add" Text="Install Theme" />
<Pager Items="@themes">
<Header>
<th>&nbsp;</th>
<th>Name</th>
<th>Version</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>
@if (context.AssemblyName != "Oqtane.Client")
{
<ActionDialog Header="Delete Theme" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Theme?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTheme(context))" />
}
</td>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
@if (UpgradeAvailable(context.ThemeName, context.Version))
{
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.ThemeName, context.Version))>Upgrade</button>
}
</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
List<Theme> Themes;
List<Theme> themes;
List<Package> packages;
protected override async Task OnInitializedAsync()
{
Themes = await ThemeService.GetThemesAsync();
themes = await ThemeService.GetThemesAsync();
packages = await PackageService.GetPackagesAsync("module");
}
private bool UpgradeAvailable(string themename, string version)
{
bool upgradeavailable = false;
Package package = packages.Where(item => item.PackageId == Utilities.GetTypeName(themename)).FirstOrDefault();
if (package != null)
{
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
}
return upgradeavailable;
}
private async Task DownloadTheme(string themename, string version)
{
await PackageService.DownloadPackageAsync(themename, version, "Themes");
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", themename, version);
await ThemeService.InstallThemesAsync();
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
private async Task DeleteTheme(Theme Theme)
{
await ThemeService.DeleteThemeAsync(Theme.ThemeName);
await logger.LogInformation("Theme Deleted {Theme}", Theme);
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
}

View File

@ -0,0 +1,109 @@
@namespace Oqtane.Modules.Admin.Upgrade
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IFileService FileService
@inject IPackageService PackageService
@inject IInstallationService InstallationService
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Framework: </label>
</td>
<td>
<FileUpload Filter=".nupkg" @ref="fileupload"></FileUpload>
</td>
</tr>
</table>
@if (uploaded)
{
<button type="button" class="btn btn-success" @onclick="Upgrade">Upgrade</button>
}
else
{
<button type="button" class="btn btn-primary" @onclick="UploadFile">Upload</button>
}
@if (upgradeavailable)
{
<hr class="app-rule" />
<div class="mx-auto text-center"><h2>Upgrade Available</h2></div>
<button type="button" class="btn btn-success" @onclick=@(async () => await Download(Constants.PackageId, Constants.Version))>Upgrade Framework</button>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
bool uploaded = false;
bool upgradeavailable = false;
FileUpload fileupload;
protected override async Task OnInitializedAsync()
{
List<Package> packages = await PackageService.GetPackagesAsync("framework");
Package package = packages.FirstOrDefault();
if (package != null)
{
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
}
if (!upgradeavailable)
{
AddModuleMessage("Framework Is Up To Date", MessageType.Info);
}
}
private async Task UploadFile()
{
string[] files = await fileupload.GetFiles();
if (files.Length > 0)
{
if (files[0].Contains(".Framework."))
{
try
{
string result = await FileService.UploadFilesAsync("Framework", files, "");
if (result == "")
{
await logger.LogInformation("Framework Uploaded {Package}", files[0]);
AddModuleMessage("Framework Uploaded Successfully. Click Upgrade To Complete Installation.", MessageType.Success);
uploaded = true;
StateHasChanged();
}
else
{
await logger.LogInformation("Framework Upload Failed For {Package}", result.Replace(",",", "));
AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Framework Upload Failed {Package} {Error}", files[0], ex.Message);
AddModuleMessage("Framework Upload Failed. " + ex.Message, MessageType.Error);
}
}
else
{
await logger.LogError("Invalid Framework Package {Package}", files[0]);
AddModuleMessage("Invalid Framework Package", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Select A Framework Package To Upload", MessageType.Warning);
}
}
private async Task Upgrade()
{
await InstallationService.Upgrade();
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
private async Task Download(string packageid, string version)
{
await PackageService.DownloadPackageAsync(packageid, version, "Framework");
await InstallationService.Upgrade();
NavigationManager.NavigateTo(NavigateUrl(Reload.Application));
}
}

View File

@ -1,27 +1,27 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Services
@namespace Oqtane.Modules.Admin.Profile
@namespace Oqtane.Modules.Admin.UserProfile
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IProfileService ProfileService
@inject ISettingService SettingService
<ModuleMessage Message="@message" />
@if (PageState.User != null && profiles != null)
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
<label for="Name" class="control-label">Username: </label>
</td>
<td>
<input class="form-control" @bind="@displayname" />
<input class="form-control" @bind="@username" readonly />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Password: </label>
</td>
<td>
<input type="password" class="form-control" @bind="@password" />
</td>
</tr>
<tr>
@ -32,6 +32,14 @@
<input class="form-control" @bind="@email" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Full Name: </label>
</td>
<td>
<input class="form-control" @bind="@displayname" />
</td>
</tr>
@foreach (Profile profile in profiles)
{
@ -64,9 +72,10 @@
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } }
string message = "";
string displayname = "";
string username = "";
string password = "";
string email = "";
string displayname = "";
List<Profile> profiles;
Dictionary<string, string> settings;
string category = "";
@ -77,19 +86,21 @@
{
if (PageState.User != null)
{
displayname = PageState.User.DisplayName;
username = PageState.User.Username;
email = PageState.User.Email;
displayname = PageState.User.DisplayName;
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
}
else
{
message = "Current User Is Not Logged In";
AddModuleMessage("Current User Is Not Logged In", MessageType.Warning);
}
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
AddModuleMessage("Error Loading User Profile", MessageType.Error);
}
}
@ -103,16 +114,20 @@
try
{
User user = PageState.User;
user.DisplayName = displayname;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = displayname;
await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
NavigationManager.NavigateTo("");
NavigationManager.NavigateTo(NavigateUrl(""));
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Saving User Profile {Error}", ex.Message);
AddModuleMessage("Error Saving User Profile", MessageType.Error);
}
}

View File

@ -0,0 +1,133 @@
@namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IProfileService ProfileService
@inject ISettingService SettingService
@if (profiles != null)
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Username: </label>
</td>
<td>
<input class="form-control" @bind="@username" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Password: </label>
</td>
<td>
<input type="password" class="form-control" @bind="@password" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Email: </label>
</td>
<td>
<input class="form-control" @bind="@email" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Full Name: </label>
</td>
<td>
<input class="form-control" @bind="@displayname" />
</td>
</tr>
@foreach (Profile profile in profiles)
{
var p = profile;
if (p.Category != category)
{
<tr>
<th colspan="2" style="text-align: center;">
@p.Category
</th>
</tr>
category = p.Category;
}
<tr>
<td>
<label for="@p.Name" class="control-label">@p.Title: </label>
</td>
<td>
<input class="form-control" maxlength="@p.MaxLength" placeholder="@p.Description" @onchange="(e => ProfileChanged(e, p.Name))" />
</td>
</tr>
}
</table>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string username = "";
string password = "";
string email = "";
string displayname = "";
List<Profile> profiles;
Dictionary<string, string> settings;
string category = "";
protected override async Task OnInitializedAsync()
{
try
{
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
settings = new Dictionary<string, string>();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
AddModuleMessage("Error Loading User Profile", MessageType.Error);
}
}
private async Task SaveUser()
{
try
{
User user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(user.DisplayName) ? user.Username : user.DisplayName;
user = await UserService.AddUserAsync(user);
if (user != null)
{
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
await logger.LogInformation("User Created {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
await logger.LogError("Error Adding User {Username} {Email}", username, email);
AddModuleMessage("Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.", MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", username, email, ex.Message);
AddModuleMessage("Error Adding User", MessageType.Error);
}
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
string value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
}
}

View File

@ -0,0 +1,169 @@
@namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IProfileService ProfileService
@inject ISettingService SettingService
@if (profiles != null)
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Username: </label>
</td>
<td>
<input class="form-control" @bind="@username" readonly />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Password: </label>
</td>
<td>
<input type="password" class="form-control" @bind="@password" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Email: </label>
</td>
<td>
<input class="form-control" @bind="@email" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Full Name: </label>
</td>
<td>
<input class="form-control" @bind="@displayname" />
</td>
</tr>
@foreach (Profile profile in profiles)
{
var p = profile;
if (p.Category != category)
{
<tr>
<th colspan="2" style="text-align: center;">
@p.Category
</th>
</tr>
category = p.Category;
}
<tr>
<td>
<label for="@p.Name" class="control-label">@p.Title: </label>
</td>
<td>
<input class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" placeholder="@p.Description" @onchange="(e => ProfileChanged(e, p.Name))" />
</td>
</tr>
}
<tr>
<td>
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
int userid;
string username = "";
string password = "";
string email = "";
string displayname = "";
List<Profile> profiles;
Dictionary<string, string> settings;
string category = "";
string createdby;
DateTime createdon;
string modifiedby;
DateTime modifiedon;
string deletedby;
DateTime? deletedon;
string isdeleted;
protected override async Task OnInitializedAsync()
{
try
{
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
userid = Int32.Parse(PageState.QueryString["id"]);
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
if (user != null)
{
username = user.Username;
email = user.Email;
displayname = user.DisplayName;
settings = await SettingService.GetUserSettingsAsync(user.UserId);
createdby = user.CreatedBy;
createdon = user.CreatedOn;
modifiedby = user.ModifiedBy;
modifiedon = user.ModifiedOn;
deletedby = user.DeletedBy;
deletedon = user.DeletedOn;
isdeleted = user.IsDeleted.ToString();
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
AddModuleMessage("Error Loading User", MessageType.Error);
}
}
private string GetProfileValue(string SettingName, string DefaultValue)
{
return SettingService.GetSetting(settings, SettingName, DefaultValue);
}
private async Task SaveUser()
{
try
{
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(user.DisplayName) ? user.Username : user.DisplayName;
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
user = await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
await logger.LogInformation("User Saved {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving User {Username} {Email} {Error}", username, email, ex.Message);
AddModuleMessage("Error Saving User", MessageType.Error);
}
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
string value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
}
}

View File

@ -1,43 +1,59 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.Users
@namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase
@inject IUserRoleService UserRoleService
@inject IUserService UserService
@if (Users == null)
@if (userroles == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (var User in Users)
{
<tr>
<td>@User.Username</td>
</tr>
}
</tbody>
</table>
<ActionLink Action="Add" Text="Add User" />
<Pager Items="@userroles">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" /></td>
<td><ActionDialog Header="Delete User" Message="@("Are You Sure You Wish To Delete " + context.User.DisplayName + "?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" /></td>
<td><ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" /></td>
<td>@context.User.DisplayName</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<User> Users;
List<UserRole> userroles;
protected override async Task OnInitializedAsync()
{
Users = await UserService.GetUsersAsync(PageState.Site.SiteId);
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.Role.Name == Constants.RegisteredRole).ToList();
}
private async Task DeleteUser(UserRole UserRole)
{
try
{
User user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
if (user != null)
{
await UserService.DeleteUserAsync(user.UserId);
await logger.LogInformation("User Deleted {User}", UserRole.User);
StateHasChanged();
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting User {User} {Error}", UserRole.User, ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -0,0 +1,187 @@
@namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase
@inject IRoleService RoleService
@inject IUserRoleService UserRoleService
@if (userroles == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Role: </label>
</td>
<td>
<select class="form-control" @bind="@roleid">
<option value="-1">&lt;Select Role&gt;</option>
@foreach (Role role in roles)
{
<option value="@(role.RoleId)">@role.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Effective Date: </label>
</td>
<td>
<input class="form-control" @bind="@effectivedate" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Expiry Date: </label>
</td>
<td>
<input class="form-control" @bind="@expirydate" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveUserRole">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<hr class="app-rule" />
<p align="center">
<Pager Items="@userroles">
<Header>
<th>Role</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.Role.Name</td>
<td>
@if (!context.Role.IsSystem)
{
<button type="button" class="btn btn-danger" @onclick=@(async () => await DeleteUserRole(context.UserRoleId))>Delete</button>
}
</td>
</Row>
</Pager>
</p>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
int userid;
List<Role> roles;
int roleid = -1;
string effectivedate = "";
string expirydate = "";
List<UserRole> userroles;
protected override async Task OnInitializedAsync()
{
try
{
userid = Int32.Parse(PageState.QueryString["id"]);
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId);
await GetUserRoles();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Roles {Error}", ex.Message);
AddModuleMessage("Error Loading Roles", MessageType.Error);
}
}
private async Task GetUserRoles()
{
try
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.UserId == userid).ToList();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading User Roles {UserId} {Error}", userid, ex.Message);
AddModuleMessage("Error Loading User Roles", MessageType.Error);
}
}
private async Task SaveUserRole()
{
try
{
if (roleid != -1)
{
UserRole userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
if (userrole != null)
{
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.UpdateUserRoleAsync(userrole);
}
else
{
userrole = new UserRole();
userrole.UserId = userid;
userrole.RoleId = roleid;
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.AddUserRoleAsync(userrole);
}
await GetUserRoles();
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
AddModuleMessage("User Assigned To Role", MessageType.Success);
}
else
{
AddModuleMessage("You Must Select A Role", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving User Roles {UserId} {Error}", userid, ex.Message);
AddModuleMessage("Error Saving User Roles", MessageType.Error);
}
}
private async Task DeleteUserRole(int UserRoleId)
{
try
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await GetUserRoles();
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
AddModuleMessage("User Removed From Role", MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
AddModuleMessage("Error Removing User From Role", MessageType.Error);
}
}
}

View File

@ -0,0 +1,130 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@if (visible)
{
<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">@Header</h5>
<button type="button" class="close" @onclick="DisplayModal" aria-label="Close">&times;</button>
</div>
<div class="modal-body">
<p>@Message</p>
</div>
<div class="modal-footer">
<button type="button" class="@Class" @onclick="Confirm">@Action</button>
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">Cancel</button>
</div>
</div>
</div>
</div>
</div>
}
@if (authorized)
{
<button class="@Class" @onclick="DisplayModal">@Text</button>
}
@code {
[Parameter]
public string Header { get; set; } // required
[Parameter]
public string Message { get; set; } // required
[Parameter]
public string Action { get; set; } // defaults to Ok if not specified
[Parameter]
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
[Parameter]
public string Text { get; set; } // optional - defaults to Action if not specified
[Parameter]
public string Class { get; set; } // optional
[Parameter]
public Action OnClick { get; set; } // required - executes a method in the calling component
bool visible = false;
bool authorized = false;
protected override void OnParametersSet()
{
if (string.IsNullOrEmpty(Action))
{
Action = "Ok";
}
if (string.IsNullOrEmpty(Text))
{
Text = Action;
}
if (string.IsNullOrEmpty(Class))
{
Class = "btn btn-success";
}
authorized = IsAuthorized();
}
private bool IsAuthorized()
{
bool authorized = false;
if (PageState.EditMode)
{
SecurityAccessLevel security = SecurityAccessLevel.Host;
if (Security == null)
{
string typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0) + ",", Action + ",");
Type moduleType = Type.GetType(typename);
if (moduleType != null)
{
var moduleobject = Activator.CreateInstance(moduleType);
security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
}
else
{
security = SecurityAccessLevel.Anonymous; // occurs when an action does not have a corresponding module control
}
}
else
{
security = Security.Value;
}
switch (security)
{
case SecurityAccessLevel.Anonymous:
authorized = true;
break;
case SecurityAccessLevel.View:
authorized = UserSecurity.IsAuthorized(PageState.User, "View", ModuleState.Permissions);
break;
case SecurityAccessLevel.Edit:
authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", ModuleState.Permissions);
break;
case SecurityAccessLevel.Admin:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole);
break;
case SecurityAccessLevel.Host:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole);
break;
}
}
return authorized;
}
private void DisplayModal()
{
visible = !visible;
StateHasChanged();
}
private void Confirm()
{
DisplayModal();
OnClick();
}
}

View File

@ -1,10 +1,4 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Services
@using Oqtane.Shared
@using Oqtane.Security
@namespace Oqtane.Modules.Controls
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@inject IUserService UserService
@ -15,16 +9,19 @@
@code {
[Parameter]
public string Action { get; set; }
public string Action { get; set; } // required
[Parameter]
public string Text { get; set; } // optional
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
[Parameter]
public string Parameters { get; set; } // optional
public string Text { get; set; } // optional - defaults to Action if not specified
[Parameter]
public string Class { get; set; } // optional
public string Parameters { get; set; } // optional - querystring parameter should be in the form of "id=x&name=y"
[Parameter]
public string Class { get; set; } // optional - defaults to primary if not specified
[Parameter]
public string Style { get; set; } // optional
@ -39,12 +36,12 @@
protected override void OnParametersSet()
{
text = Action;
if (!String.IsNullOrEmpty(Text))
if (!string.IsNullOrEmpty(Text))
{
text = Text;
}
if (!String.IsNullOrEmpty(Parameters))
if (!string.IsNullOrEmpty(Parameters))
{
parameters = Parameters;
}
@ -60,34 +57,53 @@
}
url = EditUrl(Action, parameters);
authorized = IsAuthorized();
}
private bool IsAuthorized()
{
bool authorized = false;
if (PageState.EditMode)
{
string typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameClass(ModuleState.ModuleType) + ",", Action + ",");
Type moduleType = Type.GetType(typename);
if (moduleType != null)
SecurityAccessLevel security = SecurityAccessLevel.Host;
if (Security == null)
{
var moduleobject = Activator.CreateInstance(moduleType);
SecurityAccessLevel SecurityAccessLevel = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
switch (SecurityAccessLevel)
string typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0) + ",", Action + ",");
Type moduleType = Type.GetType(typename);
if (moduleType != null)
{
case SecurityAccessLevel.Anonymous:
authorized = true;
break;
case SecurityAccessLevel.View:
authorized = UserSecurity.IsAuthorized(PageState.User, "View", ModuleState.Permissions);
break;
case SecurityAccessLevel.Edit:
authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", ModuleState.Permissions);
break;
case SecurityAccessLevel.Admin:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole);
break;
case SecurityAccessLevel.Host:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole);
break;
var moduleobject = Activator.CreateInstance(moduleType);
security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
}
else
{
security = SecurityAccessLevel.Anonymous; // occurs when an action does not have a corresponding module control
Class = "btn btn-warning"; // alert developer of missing module comtrol
}
}
else
{
security = Security.Value;
}
switch (security)
{
case SecurityAccessLevel.Anonymous:
authorized = true;
break;
case SecurityAccessLevel.View:
authorized = UserSecurity.IsAuthorized(PageState.User, "View", ModuleState.Permissions);
break;
case SecurityAccessLevel.Edit:
authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", ModuleState.Permissions);
break;
case SecurityAccessLevel.Admin:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole);
break;
case SecurityAccessLevel.Host:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole);
break;
}
}
return authorized;
}
}

View File

@ -1,6 +1,4 @@
@using Oqtane.Modules
@using Microsoft.AspNetCore.Components.Web
@namespace Oqtane.Modules.Controls
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@if (text != "")
@ -20,6 +18,15 @@
[Parameter]
public DateTime ModifiedOn { get; set; }
[Parameter]
public string DeletedBy { get; set; }
[Parameter]
public DateTime? DeletedOn { get; set; }
[Parameter]
public bool IsDeleted { get; set; }
[Parameter]
public string Style { get; set; }
@ -56,5 +63,19 @@
}
text += "</p>";
}
if (!String.IsNullOrEmpty(DeletedBy) || DeletedOn.HasValue)
{
text += "<p style=\"" + Style + "\">Deleted ";
if (!String.IsNullOrEmpty(DeletedBy))
{
text += " by <b>" + DeletedBy + "</b>";
}
if (DeletedOn != null)
{
text += " on <b>" + DeletedOn.Value.ToString("MMM dd yyyy HH:mm:ss") + "</b>";
}
text += "</p>";
}
}
}

View File

@ -1,13 +1,13 @@
@using Microsoft.AspNetCore.Components.Web
@namespace Oqtane.Modules.Controls
@namespace Oqtane.Modules.Controls
@inject IJSRuntime jsRuntime
@if (multiple)
{
<input type="file" id="@fileid" name="file" accept="@filter" multiple />
<input type="file" id="@fileid" name="file" accept="@filter" value="@files" multiple />
}
else
{
<input type="file" id="@fileid" name="file" accept="@filter" />
<input type="file" id="@fileid" name="file" accept="@filter" value="@files" />
}
<span id="@progressinfoid"></span> <progress id="@progressbarid" style="visibility: hidden;"></progress>
@ -25,6 +25,7 @@ else
string progressinfoid = "";
string progressbarid = "";
string filter = "*";
string files = "";
bool multiple = false;
protected override void OnInitialized()
@ -43,4 +44,11 @@ else
multiple = bool.Parse(Multiple);
}
}
public async Task<string[]> GetFiles()
{
var interop = new Interop(jsRuntime);
string[] files = await interop.GetFiles(fileid);
return files;
}
}

View File

@ -1,12 +1,9 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@namespace Oqtane.Modules.Controls
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@if (Message != "")
@if (!string.IsNullOrEmpty(message))
{
<div class="@type">@Message</div>
<br />
<div class="@classname" role="alert">@message</div>
<br />
}
@ -17,24 +14,40 @@
[Parameter]
public MessageType Type { get; set; }
string type = "alert alert-danger";
string message = "";
string classname = "alert alert-danger";
protected override void OnInitialized()
protected override void OnParametersSet()
{
switch (Type)
message = Message;
classname = GetMessageType(Type);
}
public void SetModuleMessage(string message, MessageType type)
{
this.message = message;
classname = GetMessageType(type);
StateHasChanged();
}
private string GetMessageType(MessageType type)
{
string classname = "";
switch (type)
{
case MessageType.Success:
type = "alert alert-success";
classname = "alert alert-success";
break;
case MessageType.Info:
type = "alert alert-info";
classname = "alert alert-info";
break;
case MessageType.Warning:
type = "alert alert-warning";
classname = "alert alert-warning";
break;
case MessageType.Error:
type = "alert alert-danger";
classname = "alert alert-danger";
break;
}
return classname;
}
}

View File

@ -0,0 +1,195 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@typeparam TableItem
<p>
@if(Format == "Table")
{
<table class="@Class">
<thead>
<tr>@Header</tr>
</thead>
<tbody>
@foreach (var item in ItemList)
{
<tr>@Row(item)</tr>
}
</tbody>
</table>
}
@if(Format == "Grid")
{
<div class="@Class">
<div class="row">@Header</div>
@foreach (var item in ItemList)
{
<div class="row">@Row(item)</div>
}
</div>
}
<div class="mx-auto text-center">
@if (Page > MaxPages)
{
<button class="btn btn-secondary" @onclick=@(async () => SetPagerSize("back"))><span class="oi oi-media-skip-backward" title="back" aria-hidden="true"></span></button>
}
@if (EndPage > 1)
{
<button class="btn btn-secondary" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></button>
@for (int i = StartPage; i <= EndPage; i++)
{
var pager = i;
<button class="btn @((pager == Page) ? "btn-primary" : "btn-link")" @onclick=@(async () => UpdateList(pager))>
@pager
</button>
}
<button class="btn btn-secondary" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></button>
}
@if (EndPage < Pages)
{
<button class="btn btn-secondary" @onclick=@(async () => SetPagerSize("forward"))><span class="oi oi-media-skip-forward" title="forward" aria-hidden="true"></span></button>
}
@if (EndPage > 1)
{
<span class="btn btn-link disabled">Page @Page of @Pages</span>
}
</div>
</p>
@code {
int Pages = 0;
int Page = 1;
int MaxItems;
int MaxPages;
int StartPage;
int EndPage;
[Parameter]
public string Format { get; set; }
[Parameter]
public RenderFragment Header { get; set; }
[Parameter]
public RenderFragment<TableItem> Row { get; set; }
[Parameter]
public IEnumerable<TableItem> Items { get; set; }
[Parameter]
public string PageSize { get; set; }
[Parameter]
public string DisplayPages { get; set; }
[Parameter]
public string Class { get; set; }
IEnumerable<TableItem> ItemList { get; set; }
protected override void OnParametersSet()
{
if (string.IsNullOrEmpty(Format))
{
Format = "Table";
}
if (string.IsNullOrEmpty(Class))
{
if (Format == "Table")
{
Class = "table table-borderless";
}
else
{
Class = "container";
}
}
if (string.IsNullOrEmpty(PageSize))
{
MaxItems = 10;
}
else
{
MaxItems = int.Parse(PageSize);
}
if (string.IsNullOrEmpty(DisplayPages))
{
MaxPages = 5;
}
else
{
MaxPages = int.Parse(DisplayPages);
}
if (Items != null)
{
ItemList = Items.Skip((Page - 1) * MaxItems).Take(MaxItems);
Pages = (int)Math.Ceiling(Items.Count() / (decimal)MaxItems);
}
SetPagerSize("forward");
}
public void UpdateList(int CurrentPage)
{
ItemList = Items.Skip((CurrentPage - 1) * MaxItems).Take(MaxItems);
Page = CurrentPage;
StateHasChanged();
}
public void SetPagerSize(string direction)
{
if (direction == "forward")
{
if (EndPage + 1 < Pages)
{
StartPage = EndPage + 1;
}
else
{
StartPage = 1;
}
if (EndPage + MaxPages < Pages)
{
EndPage = StartPage + MaxPages - 1;
}
else
{
EndPage = Pages;
}
StateHasChanged();
}
else if (direction == "back")
{
EndPage = StartPage - 1;
StartPage = StartPage - MaxPages;
}
}
public void NavigateToPage(string direction)
{
if (direction == "next")
{
if (Page < Pages)
{
if (Page == EndPage)
{
SetPagerSize("forward");
}
Page += 1;
}
}
else if (direction == "previous")
{
if (Page > 1)
{
if (Page == StartPage)
{
SetPagerSize("back");
}
Page -= 1;
}
}
UpdateList(Page);
}
}

View File

@ -1,10 +1,4 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Security
@using Oqtane.Shared
@namespace Oqtane.Modules.Controls
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@inject IRoleService RoleService
@inject IUserService UserService
@ -83,6 +77,9 @@
[Parameter]
public string EntityName { get; set; }
[Parameter]
public string PermissionNames { get; set; }
[Parameter]
public string Permissions { get; set; }
@ -95,11 +92,14 @@
protected override async Task OnInitializedAsync()
{
permissionnames = PageState.ModuleDefinitions.Find(item => item.ModuleDefinitionName == ModuleState.ModuleDefinitionName).Permissions;
if (string.IsNullOrEmpty(permissionnames))
if (string.IsNullOrEmpty(PermissionNames))
{
permissionnames = "View,Edit";
}
else
{
permissionnames = PermissionNames;
}
roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
roles.Insert(0, new Role { Name = Constants.AllUsersRole });

View File

@ -0,0 +1,43 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
<CascadingValue Value="this">
<div>
@foreach (TabPanel tabPanel in TabPanels)
{
<button type="button"
class="btn @GetButtonClass(tabPanel)"
@onclick=@( () => ActivateTabPanel(tabPanel) )>
@tabPanel.Text
</button>
}
</div>
@ChildContent
</CascadingValue>
@code {
// Next line is needed so we are able to add <TabPanel> components inside
[Parameter]
public RenderFragment ChildContent { get; set; }
public TabPanel ActiveTabPanel { get; set; }
List<TabPanel> TabPanels = new List<TabPanel>();
internal void AddTabPanel(TabPanel tabPanel)
{
TabPanels.Add(tabPanel);
if (TabPanels.Count == 1)
ActiveTabPanel = tabPanel;
StateHasChanged();
}
string GetButtonClass(TabPanel tabPanel)
{
return tabPanel == ActiveTabPanel ? "btn-primary" : "btn-secondary";
}
void ActivateTabPanel(TabPanel tabPanel)
{
ActiveTabPanel = tabPanel;
}
}

View File

@ -0,0 +1,27 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@if (Parent.ActiveTabPanel == (TabPanel)(object)this)
{
@ChildContent
}
@code {
[CascadingParameter]
private TabControl Parent { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Text { get; set; }
protected override void OnInitialized()
{
if (Parent == null)
throw new ArgumentNullException(nameof(Parent), "TabPanel must exist within a TabControl");
base.OnInitialized();
Parent.AddTabPanel((TabPanel)(object)this);
}
}

View File

@ -1,5 +1,4 @@
@using Microsoft.AspNetCore.Components.Web
@namespace Oqtane.Modules.Controls
@namespace Oqtane.Modules.Controls
<img src="@src" title="@title" disabled=@Disabled @onclick="SetValue" />

View File

@ -1,5 +1,3 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@namespace Oqtane.Modules.Counter
@inherits ModuleBase
Current count: @currentCount

View File

@ -1,5 +1,4 @@
using Oqtane.Modules;
using System.Collections.Generic;
using System.Collections.Generic;
namespace Oqtane.Modules.Counter
{

View File

@ -1,26 +1,18 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@using Oqtane.Modules.HtmlText.Services
@using Oqtane.Modules.HtmlText.Services
@using Oqtane.Modules.HtmlText.Models
@using System.Net.Http;
@using Oqtane.Shared;
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject HttpClient http
@inject SiteState sitestate
<ModuleMessage Message="@message" />
<table class="form-group">
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Content: </label>
</td>
<td>
<textarea class="form-control" @bind="@content" rows="5" style="width:400px;" />
<textarea class="form-control" @bind="@content" rows="5" />
</td>
</tr>
</table>
@ -34,7 +26,6 @@
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Edit; } }
public override string Title { get { return "Edit Html/Text"; } }
string message = "";
string content;
string createdby;
DateTime createdon;
@ -58,7 +49,8 @@
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "An Error Occurred Loading Html/Text Content. " + ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
@ -80,12 +72,13 @@
htmltext.Content = content;
await htmltextservice.AddHtmlTextAsync(htmltext);
}
PageState.Reload = Constants.ReloadPage;
NavigationManager.NavigateTo(NavigateUrl());
await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
NavigationManager.NavigateTo(NavigateUrl(Reload.Page));
}
catch (Exception ex)
{
message = ex.Message;
await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
AddModuleMessage("Error Saving Content", MessageType.Error);
}
}
}

View File

@ -1,27 +1,18 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.HtmlText.Services
@using Oqtane.Modules
@using Oqtane.Modules.HtmlText.Services
@using Oqtane.Modules.HtmlText.Models
@using System.Net.Http;
@using Oqtane.Modules.Controls
@using Oqtane.Shared;
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject HttpClient http
@inject SiteState sitestate
<ModuleMessage Message="@message" />
@((MarkupString)content)
<br />
<ActionLink Action="Edit" />
<br />
<br />
<br /><br />
@code {
string message = "";
string content;
protected override async Task OnParametersSetAsync()
@ -37,7 +28,7 @@
}
catch (Exception ex)
{
message = ex.Message;
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -1,9 +1,8 @@
using Oqtane.Modules;
using System.Collections.Generic;
using System.Collections.Generic;
namespace Oqtane.Modules.HtmlText
{
public class Module : IModule
public class ModuleInfo : IModule
{
public Dictionary<string, string> Properties
{
@ -13,7 +12,8 @@ namespace Oqtane.Modules.HtmlText
{
{ "Name", "HtmlText" },
{ "Description", "Renders HTML or Text" },
{ "Version", "1.0.0" }
{ "Version", "1.0.0" },
{ "ServerAssemblyName", "Oqtane.Server" }
};
return properties;
}

View File

@ -1,11 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
using Oqtane.Services;
using Oqtane.Modules.HtmlText.Models;
using Oqtane.Shared;
using Oqtane.Models;
namespace Oqtane.Modules.HtmlText.Services
{
@ -29,7 +28,17 @@ namespace Oqtane.Modules.HtmlText.Services
public async Task<HtmlTextInfo> GetHtmlTextAsync(int ModuleId)
{
return await http.GetJsonAsync<HtmlTextInfo>(apiurl + "/" + ModuleId.ToString() + "?entityid=" + ModuleId.ToString());
HtmlTextInfo htmltext;
try
{
// exception handling is required because GetJsonAsync() returns an error if no content exists for the ModuleId ( https://github.com/aspnet/AspNetCore/issues/14041 )
htmltext = await http.GetJsonAsync<HtmlTextInfo>(apiurl + "/" + ModuleId.ToString() + "?entityid=" + ModuleId.ToString());
}
catch
{
htmltext = null;
}
return htmltext;
}
public async Task AddHtmlTextAsync(HtmlTextInfo htmltext)
@ -46,5 +55,6 @@ namespace Oqtane.Modules.HtmlText.Services
{
await http.DeleteAsync(apiurl + "/" + ModuleId.ToString() + "?entityid=" + ModuleId.ToString());
}
}
}

View File

@ -1,4 +1,6 @@
namespace Oqtane.Modules
using Oqtane.Shared;
namespace Oqtane.Modules
{
public interface IModuleControl
{

View File

@ -1,17 +1,43 @@
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Linq;
using Oqtane.Services;
using System;
namespace Oqtane.Modules
{
public class ModuleBase : ComponentBase, IModuleControl
{
public Logger logger { get; set; }
public ModuleBase()
{
this.logger = new Logger(this);
}
[Inject]
protected ILogService LoggingService { get; set; }
[CascadingParameter]
protected PageState PageState { get; set; }
[CascadingParameter]
protected Module ModuleState { get; set; }
[CascadingParameter]
protected ModuleInstance ModuleInstance { get; set; }
protected ModuleDefinition ModuleDefinition
{
get
{
return PageState.ModuleDefinitions.Where(item => item.ModuleDefinitionName == ModuleState.ModuleDefinitionName).FirstOrDefault();
}
}
// optional interface properties
public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security
public virtual string Title { get { return ""; } }
@ -20,19 +46,42 @@ namespace Oqtane.Modules
public virtual bool UseAdminContainer { get { return true; } }
// path method
public string ModulePath()
{
return "Modules/" + this.GetType().Namespace + "/";
}
// url methods
public string NavigateUrl()
{
return NavigateUrl(PageState.Page.Path);
}
public string NavigateUrl(Reload reload)
{
return NavigateUrl(PageState.Page.Path, reload);
}
public string NavigateUrl(string path)
{
return NavigateUrl(path, "");
return NavigateUrl(path, "", Reload.None);
}
public string NavigateUrl(string path, Reload reload)
{
return NavigateUrl(path, "", reload);
}
public string NavigateUrl(string path, string parameters)
{
return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters);
return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters, Reload.None);
}
public string NavigateUrl(string path, string parameters, Reload reload)
{
return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters, reload);
}
public string EditUrl(string action)
@ -59,5 +108,126 @@ namespace Oqtane.Modules
{
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters);
}
// user feedback methods
public void AddModuleMessage(string message, MessageType type)
{
ModuleInstance.AddModuleMessage(message, type);
}
public void ShowProgressIndicator()
{
ModuleInstance.ShowProgressIndicator();
}
public void HideProgressIndicator()
{
ModuleInstance.HideProgressIndicator();
}
// logging methods
public async Task Log(LogLevel level, Exception exception, string message, params object[] args)
{
int PageId = PageState.Page.PageId;
int ModuleId = ModuleState.ModuleId;
int? UserId = null;
if (PageState.User != null)
{
UserId = PageState.User.UserId;
}
string category = this.GetType().AssemblyQualifiedName;
string feature = Utilities.GetTypeNameLastSegment(category, 1);
LogFunction function;
switch (PageState.Action)
{
case "Add":
function = LogFunction.Create;
break;
case "Edit":
function = LogFunction.Update;
break;
case "Delete":
function = LogFunction.Delete;
break;
default:
function = LogFunction.Read;
break;
}
if (feature == "Login")
{
function = LogFunction.Security;
}
await LoggingService.Log(PageId, ModuleId, UserId, category, feature, function, level, exception, message, args);
}
public class Logger
{
private ModuleBase modulebase;
public Logger(ModuleBase modulebase)
{
this.modulebase = modulebase;
}
public async Task LogTrace(string message, params object[] args)
{
await modulebase.Log(LogLevel.Trace, null, message, args);
}
public async Task LogTrace(Exception exception, string message, params object[] args)
{
await modulebase.Log(LogLevel.Trace, exception, message, args);
}
public async Task LogDebug(string message, params object[] args)
{
await modulebase.Log(LogLevel.Debug, null, message, args);
}
public async Task LogDebug(Exception exception, string message, params object[] args)
{
await modulebase.Log(LogLevel.Debug, exception, message, args);
}
public async Task LogInformation(string message, params object[] args)
{
await modulebase.Log(LogLevel.Information, null, message, args);
}
public async Task LogInformation(Exception exception, string message, params object[] args)
{
await modulebase.Log(LogLevel.Information, exception, message, args);
}
public async Task LogWarning(string message, params object[] args)
{
await modulebase.Log(LogLevel.Warning, null, message, args);
}
public async Task LogWarning(Exception exception, string message, params object[] args)
{
await modulebase.Log(LogLevel.Warning, exception, message, args);
}
public async Task LogError(string message, params object[] args)
{
await modulebase.Log(LogLevel.Error, null, message, args);
}
public async Task LogError(Exception exception, string message, params object[] args)
{
await modulebase.Log(LogLevel.Error, exception, message, args);
}
public async Task LogCritical(string message, params object[] args)
{
await modulebase.Log(LogLevel.Critical, null, message, args);
}
public async Task LogCritical(Exception exception, string message, params object[] args)
{
await modulebase.Log(LogLevel.Critical, exception, message, args);
}
}
}
}

View File

@ -1,5 +1,3 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Modules.Weather.Services
@namespace Oqtane.Modules.Weather
@inherits ModuleBase

View File

@ -1,5 +1,4 @@
using Oqtane.Modules;
using System.Collections.Generic;
using System.Collections.Generic;
namespace Oqtane.Modules.Weather
{

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Exe</OutputType>
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
<RestoreAdditionalProjectSources>
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;
@ -27,10 +28,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Blazor" Version="3.0.0-preview9.19424.4" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="3.0.0-preview9.19424.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview9.19424.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.0.0-preview9.19424.4" />
<PackageReference Include="Microsoft.AspNetCore.Blazor" Version="3.0.0-preview9.19465.2" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="3.0.0-preview9.19465.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview9.19465.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -1,4 +1,7 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Oqtane.Shared;
@ -7,12 +10,14 @@ namespace Oqtane.Services
{
public class FileService : ServiceBase, IFileService
{
private readonly HttpClient http;
private readonly SiteState sitestate;
private readonly NavigationManager NavigationManager;
private readonly IJSRuntime jsRuntime;
public FileService(SiteState sitestate, NavigationManager NavigationManager, IJSRuntime jsRuntime)
public FileService(HttpClient http, SiteState sitestate, NavigationManager NavigationManager, IJSRuntime jsRuntime)
{
this.http = http;
this.sitestate = sitestate;
this.NavigationManager = NavigationManager;
this.jsRuntime = jsRuntime;
@ -23,15 +28,52 @@ namespace Oqtane.Services
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "File"); }
}
public async Task UploadFilesAsync(string Folder)
public async Task<List<string>> GetFilesAsync(string Folder)
{
await UploadFilesAsync(Folder, "");
return await http.GetJsonAsync<List<string>>(apiurl + "?folder=" + Folder);
}
public async Task UploadFilesAsync(string Folder, string FileUploadName)
public async Task<string> UploadFilesAsync(string Folder, string[] Files, string FileUploadName)
{
string result = "";
var interop = new Interop(jsRuntime);
await interop.UploadFiles(apiurl + "/upload", Folder, FileUploadName);
// uploading files is asynchronous so we need to wait for the upload to complete
bool success = false;
int attempts = 0;
while (attempts < 5 && success == false)
{
Thread.Sleep(2000); // wait 2 seconds
result = "";
List<string> files = await GetFilesAsync(Folder);
if (files.Count > 0)
{
success = true;
foreach (string file in Files)
{
if (!files.Contains(file))
{
success = false;
result += file + ",";
}
}
}
attempts += 1;
}
if (!success)
{
result = result.Substring(0, result.Length - 1);
}
return result;
}
public async Task DeleteFileAsync(string Folder, string File)
{
await http.DeleteAsync(apiurl + "?folder=" + Folder + "&file=" + File);
}
}
}

View File

@ -35,5 +35,10 @@ namespace Oqtane.Services
{
return await http.PostJsonAsync<GenericResponse>(apiurl, connectionstring);
}
public async Task<GenericResponse> Upgrade()
{
return await http.GetJsonAsync<GenericResponse>(apiurl + "/upgrade");
}
}
}

View File

@ -6,7 +6,8 @@ namespace Oqtane.Services
{
public interface IFileService
{
Task UploadFilesAsync(string Folder);
Task UploadFilesAsync(string Folder, string FileUploadName);
Task<List<string>> GetFilesAsync(string Folder);
Task<string> UploadFilesAsync(string Folder, string[] Files, string FileUploadName);
Task DeleteFileAsync(string Folder, string File);
}
}

View File

@ -1,5 +1,4 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
@ -8,5 +7,6 @@ namespace Oqtane.Services
{
Task<GenericResponse> IsInstalled();
Task<GenericResponse> Install(string connectionstring);
Task<GenericResponse> Upgrade();
}
}

View File

@ -0,0 +1,15 @@
using Oqtane.Models;
using Oqtane.Shared;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface ILogService
{
Task<List<Log>> GetLogsAsync(int SiteId, string Level, string Function, int Rows);
Task<Log> GetLogAsync(int LogId);
Task Log(int? PageId, int? ModuleId, int? UserId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args);
}
}

View File

@ -6,7 +6,9 @@ namespace Oqtane.Services
{
public interface IModuleDefinitionService
{
Task<List<ModuleDefinition>> GetModuleDefinitionsAsync();
Task InstallModulesAsync();
}
Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int SiteId);
Task UpdateModuleDefinitionAsync(ModuleDefinition ModuleDefinition);
Task InstallModuleDefinitionsAsync();
Task DeleteModuleDefinitionAsync(int ModuleDefinitionId, int SiteId);
}
}

View File

@ -6,11 +6,12 @@ namespace Oqtane.Services
{
public interface IModuleService
{
Task<List<Module>> GetModulesAsync(int PageId);
Task<List<Module>> GetModulesAsync(int SiteId, string ModuleDefinitionName);
Task<List<Module>> GetModulesAsync(int SiteId);
Task<Module> GetModuleAsync(int ModuleId);
Task<Module> AddModuleAsync(Module Module);
Task<Module> UpdateModuleAsync(Module Module);
Task DeleteModuleAsync(int ModuleId);
Task<bool> ImportModuleAsync(int ModuleId, string Content);
Task<string> ExportModuleAsync(int ModuleId);
}
}

View File

@ -0,0 +1,12 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface IPackageService
{
Task<List<Package>> GetPackagesAsync(string Tag);
Task DownloadPackageAsync(string PackageId, string Version, string Folder);
}
}

View File

@ -8,6 +8,7 @@ namespace Oqtane.Services
{
Task<List<PageModule>> GetPageModulesAsync();
Task<PageModule> GetPageModuleAsync(int PageModuleId);
Task<PageModule> GetPageModuleAsync(int PageId, int ModuleId);
Task<PageModule> AddPageModuleAsync(PageModule PageModule);
Task<PageModule> UpdatePageModuleAsync(PageModule PageModule);
Task UpdatePageModuleOrderAsync(int PageId, string Pane);

View File

@ -8,9 +8,10 @@ namespace Oqtane.Services
{
Task<List<Page>> GetPagesAsync(int SiteId);
Task<Page> GetPageAsync(int PageId);
Task<Page> GetPageAsync(int PageId, int UserId);
Task<Page> AddPageAsync(Page Page);
Task<Page> UpdatePageAsync(Page Page);
Task UpdatePageOrderAsync(int SiteId, int? ParentId);
Task UpdatePageOrderAsync(int SiteId, int PageId, int? ParentId);
Task DeletePageAsync(int PageId);
}
}

View File

@ -0,0 +1,19 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface IScheduleLogService
{
Task<List<ScheduleLog>> GetScheduleLogsAsync();
Task<ScheduleLog> GetScheduleLogAsync(int ScheduleLogId);
Task<ScheduleLog> AddScheduleLogAsync(ScheduleLog ScheduleLog);
Task<ScheduleLog> UpdateScheduleLogAsync(ScheduleLog ScheduleLog);
Task DeleteScheduleLogAsync(int ScheduleLogId);
}
}

View File

@ -0,0 +1,19 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface IScheduleService
{
Task<List<Schedule>> GetSchedulesAsync();
Task<Schedule> GetScheduleAsync(int ScheduleId);
Task<Schedule> AddScheduleAsync(Schedule Schedule);
Task<Schedule> UpdateScheduleAsync(Schedule Schedule);
Task DeleteScheduleAsync(int ScheduleId);
}
}

View File

@ -7,13 +7,18 @@ namespace Oqtane.Services
public interface ISiteService
{
Task<List<Site>> GetSitesAsync();
Task<List<Site>> GetSitesAsync(Alias Alias);
Task<Site> GetSiteAsync(int SiteId);
Task<Site> GetSiteAsync(int SiteId, Alias Alias);
Task<Site> AddSiteAsync(Site Site);
Task<Site> AddSiteAsync(Site Site, Alias Alias);
Task<Site> UpdateSiteAsync(Site Site);
Task<Site> UpdateSiteAsync(Site Site, Alias Alias);
Task DeleteSiteAsync(int SiteId);
Task DeleteSiteAsync(int SiteId, Alias Alias);
}
}

View File

@ -8,6 +8,12 @@ namespace Oqtane.Services
{
Task<List<Tenant>> GetTenantsAsync();
Task<Tenant> GetTenantAsync();
Task<Tenant> GetTenantAsync(int TenantId);
Task<Tenant> AddTenantAsync(Tenant Tenant);
Task<Tenant> UpdateTenantAsync(Tenant Tenant);
Task DeleteTenantAsync(int TenantId);
}
}

View File

@ -7,8 +7,10 @@ namespace Oqtane.Services
public interface IThemeService
{
Task<List<Theme>> GetThemesAsync();
Dictionary<string, string> GetThemeTypes(List<Theme> themes);
Dictionary<string, string> GetPaneLayoutTypes(List<Theme> themes);
Dictionary<string, string> GetContainerTypes(List<Theme> themes);
Dictionary<string, string> GetThemeTypes(List<Theme> Themes);
Dictionary<string, string> GetPaneLayoutTypes(List<Theme> Themes, string ThemeName);
Dictionary<string, string> GetContainerTypes(List<Theme> Themes);
Task InstallThemesAsync();
Task DeleteThemeAsync(string ThemeName);
}
}

View File

@ -7,7 +7,7 @@ namespace Oqtane.Services
public interface IUserRoleService
{
Task<List<UserRole>> GetUserRolesAsync();
Task<List<UserRole>> GetUserRolesAsync(int UserId);
Task<List<UserRole>> GetUserRolesAsync(int SiteId);
Task<UserRole> GetUserRoleAsync(int UserRoleId);
Task<UserRole> AddUserRoleAsync(UserRole UserRole);
Task<UserRole> UpdateUserRoleAsync(UserRole UserRole);

View File

@ -6,7 +6,7 @@ namespace Oqtane.Services
{
public interface IUserService
{
Task<List<User>> GetUsersAsync(int SiteId);
Task<List<User>> GetUsersAsync();
Task<User> GetUserAsync(int UserId, int SiteId);
@ -14,12 +14,14 @@ namespace Oqtane.Services
Task<User> AddUserAsync(User User);
Task<User> AddUserAsync(User User, Alias alias);
Task<User> UpdateUserAsync(User User);
Task DeleteUserAsync(int UserId);
Task<User> LoginUserAsync(User User, bool SetCookie, bool IsPersistent);
Task LogoutUserAsync();
Task LogoutUserAsync(User User);
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class LogService : ServiceBase, ILogService
{
private readonly HttpClient http;
private readonly SiteState sitestate;
private readonly NavigationManager NavigationManager;
public LogService(HttpClient http, SiteState sitestate, NavigationManager NavigationManager)
{
this.http = http;
this.sitestate = sitestate;
this.NavigationManager = NavigationManager;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "Log"); }
}
public async Task<List<Log>> GetLogsAsync(int SiteId, string Level, string Function, int Rows)
{
return await http.GetJsonAsync<List<Log>>(apiurl + "?siteid=" + SiteId.ToString() + "&level=" + Level + "&function=" + Function + "&rows=" + Rows.ToString());
}
public async Task<Log> GetLogAsync(int LogId)
{
return await http.GetJsonAsync<Log>(apiurl + "/" + LogId.ToString());
}
public async Task Log(int? PageId, int? ModuleId, int? UserId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args)
{
Log log = new Log();
log.SiteId = sitestate.Alias.SiteId;
log.PageId = PageId;
log.ModuleId = ModuleId;
log.UserId = UserId;
log.Url = NavigationManager.Uri;
log.Category = category;
log.Feature = feature;
log.Function = Enum.GetName(typeof(LogFunction), function);
log.Level = Enum.GetName(typeof(LogLevel), level);
if (exception != null)
{
log.Exception = JsonSerializer.Serialize(exception);
}
log.Message = message;
log.MessageTemplate = "";
log.Properties = JsonSerializer.Serialize(args);
await http.PostJsonAsync(apiurl, log);
}
}
}

View File

@ -28,10 +28,10 @@ namespace Oqtane.Services
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "ModuleDefinition"); }
}
public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync()
public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int SiteId)
{
// get list of modules from the server
List<ModuleDefinition> moduledefinitions = await http.GetJsonAsync<List<ModuleDefinition>>(apiurl);
List<ModuleDefinition> moduledefinitions = await http.GetJsonAsync<List<ModuleDefinition>>(apiurl + "?siteid=" + SiteId.ToString());
// get list of loaded assemblies on the client ( in the client-side hosting module the browser client has its own app domain )
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
@ -47,7 +47,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + assemblyname + ".dll");
var bytes = await http.GetByteArrayAsync(apiurl + "/" + assemblyname + ".dll");
Assembly.Load(bytes);
}
}
@ -56,7 +56,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(moduledefinition.AssemblyName + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + moduledefinition.AssemblyName + ".dll");
var bytes = await http.GetByteArrayAsync(apiurl + "/" + moduledefinition.AssemblyName + ".dll");
Assembly.Load(bytes);
}
}
@ -64,9 +64,19 @@ namespace Oqtane.Services
return moduledefinitions.OrderBy(item => item.Name).ToList();
}
public async Task InstallModulesAsync()
public async Task UpdateModuleDefinitionAsync(ModuleDefinition ModuleDefinition)
{
await http.PutJsonAsync(apiurl + "/" + ModuleDefinition.ModuleDefinitionId.ToString(), ModuleDefinition);
}
public async Task InstallModuleDefinitionsAsync()
{
await http.GetJsonAsync<List<string>>(apiurl + "/install");
}
public async Task DeleteModuleDefinitionAsync(int ModuleDefinitionId, int SiteId)
{
await http.DeleteAsync(apiurl + "/" + ModuleDefinitionId.ToString() + "?siteid=" + SiteId.ToString());
}
}
}

View File

@ -26,21 +26,15 @@ namespace Oqtane.Services
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "Module"); }
}
public async Task<List<Module>> GetModulesAsync(int PageId)
public async Task<List<Module>> GetModulesAsync(int SiteId)
{
List<Module> modules = await http.GetJsonAsync<List<Module>>(apiurl + "?pageid=" + PageId.ToString());
List<Module> modules = await http.GetJsonAsync<List<Module>>(apiurl + "?siteid=" + SiteId.ToString());
modules = modules
.OrderBy(item => item.Order)
.ToList();
return modules;
}
public async Task<List<Module>> GetModulesAsync(int SiteId, string ModuleDefinitionName)
{
List<Module> modules = await http.GetJsonAsync<List<Module>>(apiurl + "?siteid=" + SiteId.ToString() + "&moduledefinitionname=" + ModuleDefinitionName);
return modules.ToList();
}
public async Task<Module> GetModuleAsync(int ModuleId)
{
return await http.GetJsonAsync<Module>(apiurl + "/" + ModuleId.ToString());
@ -60,5 +54,15 @@ namespace Oqtane.Services
{
await http.DeleteAsync(apiurl + "/" + ModuleId.ToString());
}
public async Task<bool> ImportModuleAsync(int ModuleId, string Content)
{
return await http.PostJsonAsync<bool>(apiurl + "/import?moduleid=" + ModuleId, Content);
}
public async Task<string> ExportModuleAsync(int ModuleId)
{
return await http.GetStringAsync(apiurl + "/export?moduleid=" + ModuleId.ToString());
}
}
}

View File

@ -0,0 +1,40 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
using System.Linq;
namespace Oqtane.Services
{
public class PackageService : ServiceBase, IPackageService
{
private readonly HttpClient http;
private readonly SiteState sitestate;
private readonly NavigationManager NavigationManager;
public PackageService(HttpClient http, SiteState sitestate, NavigationManager NavigationManager)
{
this.http = http;
this.sitestate = sitestate;
this.NavigationManager = NavigationManager;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "Package"); }
}
public async Task<List<Package>> GetPackagesAsync(string Tag)
{
List<Package> packages = await http.GetJsonAsync<List<Package>>(apiurl + "?tag=" + Tag);
return packages.OrderByDescending(item => item.Downloads).ToList();
}
public async Task DownloadPackageAsync(string PackageId, string Version, string Folder)
{
await http.PostJsonAsync(apiurl + "?packageid=" + PackageId + "&version=" + Version + "&folder=" + Folder, null);
}
}
}

View File

@ -36,6 +36,11 @@ namespace Oqtane.Services
return await http.GetJsonAsync<PageModule>(apiurl + "/" + PageModuleId.ToString());
}
public async Task<PageModule> GetPageModuleAsync(int PageId, int ModuleId)
{
return await http.GetJsonAsync<PageModule>(apiurl + "/" + PageId.ToString() + "/" + ModuleId.ToString());
}
public async Task<PageModule> AddPageModuleAsync(PageModule PageModule)
{
return await http.PostJsonAsync<PageModule>(apiurl, PageModule);

View File

@ -39,6 +39,11 @@ namespace Oqtane.Services
return await http.GetJsonAsync<Page>(apiurl + "/" + PageId.ToString());
}
public async Task<Page> GetPageAsync(int PageId, int UserId)
{
return await http.GetJsonAsync<Page>(apiurl + "/" + PageId.ToString() + "?userid=" + UserId.ToString());
}
public async Task<Page> AddPageAsync(Page Page)
{
return await http.PostJsonAsync<Page>(apiurl, Page);
@ -49,9 +54,9 @@ namespace Oqtane.Services
return await http.PutJsonAsync<Page>(apiurl + "/" + Page.PageId.ToString(), Page);
}
public async Task UpdatePageOrderAsync(int SiteId, int? ParentId)
public async Task UpdatePageOrderAsync(int SiteId, int PageId, int? ParentId)
{
await http.PutJsonAsync(apiurl + "/?siteid=" + SiteId.ToString() + "&parentid=" + ((ParentId == null) ? "" : ParentId.ToString()), null);
await http.PutJsonAsync(apiurl + "/?siteid=" + SiteId.ToString() + "&pageid=" + PageId.ToString() + "&parentid=" + ((ParentId == null) ? "" : ParentId.ToString()), null);
}
public async Task DeletePageAsync(int PageId)

View File

@ -0,0 +1,54 @@
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class ScheduleLogService : ServiceBase, IScheduleLogService
{
private readonly HttpClient http;
private readonly SiteState sitestate;
private readonly NavigationManager NavigationManager;
public ScheduleLogService(HttpClient http, SiteState sitestate, NavigationManager NavigationManager)
{
this.http = http;
this.sitestate = sitestate;
this.NavigationManager = NavigationManager;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "ScheduleLog"); }
}
public async Task<List<ScheduleLog>> GetScheduleLogsAsync()
{
List<ScheduleLog> schedulelogs = await http.GetJsonAsync<List<ScheduleLog>>(apiurl);
return schedulelogs.OrderBy(item => item.StartDate).ToList();
}
public async Task<ScheduleLog> GetScheduleLogAsync(int ScheduleLogId)
{
return await http.GetJsonAsync<ScheduleLog>(apiurl + "/" + ScheduleLogId.ToString());
}
public async Task<ScheduleLog> AddScheduleLogAsync(ScheduleLog schedulelog)
{
return await http.PostJsonAsync<ScheduleLog>(apiurl, schedulelog);
}
public async Task<ScheduleLog> UpdateScheduleLogAsync(ScheduleLog schedulelog)
{
return await http.PutJsonAsync<ScheduleLog>(apiurl + "/" + schedulelog.ScheduleLogId.ToString(), schedulelog);
}
public async Task DeleteScheduleLogAsync(int ScheduleLogId)
{
await http.DeleteAsync(apiurl + "/" + ScheduleLogId.ToString());
}
}
}

View File

@ -0,0 +1,54 @@
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class ScheduleService : ServiceBase, IScheduleService
{
private readonly HttpClient http;
private readonly SiteState sitestate;
private readonly NavigationManager NavigationManager;
public ScheduleService(HttpClient http, SiteState sitestate, NavigationManager NavigationManager)
{
this.http = http;
this.sitestate = sitestate;
this.NavigationManager = NavigationManager;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "Schedule"); }
}
public async Task<List<Schedule>> GetSchedulesAsync()
{
List<Schedule> schedules = await http.GetJsonAsync<List<Schedule>>(apiurl);
return schedules.OrderBy(item => item.Name).ToList();
}
public async Task<Schedule> GetScheduleAsync(int ScheduleId)
{
return await http.GetJsonAsync<Schedule>(apiurl + "/" + ScheduleId.ToString());
}
public async Task<Schedule> AddScheduleAsync(Schedule schedule)
{
return await http.PostJsonAsync<Schedule>(apiurl, schedule);
}
public async Task<Schedule> UpdateScheduleAsync(Schedule schedule)
{
return await http.PutJsonAsync<Schedule>(apiurl + "/" + schedule.ScheduleId.ToString(), schedule);
}
public async Task DeleteScheduleAsync(int ScheduleId)
{
await http.DeleteAsync(apiurl + "/" + ScheduleId.ToString());
}
}
}

View File

@ -10,11 +10,13 @@ namespace Oqtane.Services
public static string CreateApiUrl(Alias alias, string absoluteUri, string serviceName)
{
string apiurl = "";
Uri uri = new Uri(absoluteUri);
string apiurl;
if (alias != null)
{
// build a url which passes the alias that may include a subfolder for multi-tenancy
apiurl = alias.Url + "/";
apiurl = uri.Scheme + "://" + alias.Name + "/";
if (alias.Path == "")
{
apiurl += "~/";
@ -23,7 +25,6 @@ namespace Oqtane.Services
else
{
// build a url which ignores any subfolder for multi-tenancy
Uri uri = new Uri(absoluteUri);
apiurl = uri.Scheme + "://" + uri.Authority + "/~/";
}
apiurl += "api/" + serviceName;

View File

@ -31,24 +31,47 @@ namespace Oqtane.Services
List<Site> sites = await http.GetJsonAsync<List<Site>>(apiurl);
return sites.OrderBy(item => item.Name).ToList();
}
public async Task<List<Site>> GetSitesAsync(Alias Alias)
{
List<Site> sites = await http.GetJsonAsync<List<Site>>(CreateApiUrl(Alias, NavigationManager.Uri, "Site"));
return sites.OrderBy(item => item.Name).ToList();
}
public async Task<Site> GetSiteAsync(int SiteId)
{
return await http.GetJsonAsync<Site>(apiurl + "/" + SiteId.ToString());
}
public async Task<Site> GetSiteAsync(int SiteId, Alias Alias)
{
return await http.GetJsonAsync<Site>(CreateApiUrl(Alias, NavigationManager.Uri, "Site") + "/" + SiteId.ToString());
}
public async Task<Site> AddSiteAsync(Site Site)
{
return await http.PostJsonAsync<Site>(apiurl, Site);
}
public async Task<Site> AddSiteAsync(Site Site, Alias Alias)
{
return await http.PostJsonAsync<Site>(CreateApiUrl(Alias, NavigationManager.Uri, "Site"), Site);
}
public async Task<Site> UpdateSiteAsync(Site Site)
{
return await http.PutJsonAsync<Site>(apiurl + "/" + Site.SiteId.ToString(), Site);
}
public async Task<Site> UpdateSiteAsync(Site Site, Alias Alias)
{
return await http.PutJsonAsync<Site>(CreateApiUrl(Alias, NavigationManager.Uri, "Site") + "/" + Site.SiteId.ToString(), Site);
}
public async Task DeleteSiteAsync(int SiteId)
{
await http.DeleteAsync(apiurl + "/" + SiteId.ToString());
}
public async Task DeleteSiteAsync(int SiteId, Alias Alias)
{
await http.DeleteAsync(CreateApiUrl(Alias, NavigationManager.Uri, "Site") + "/" + SiteId.ToString());
}
}
}

View File

@ -32,9 +32,24 @@ namespace Oqtane.Services
return tenants.OrderBy(item => item.Name).ToList();
}
public async Task<Tenant> GetTenantAsync()
public async Task<Tenant> GetTenantAsync(int TenantId)
{
return await http.GetJsonAsync<Tenant>(apiurl);
return await http.GetJsonAsync<Tenant>(apiurl + "/" + TenantId.ToString());
}
public async Task<Tenant> AddTenantAsync(Tenant Tenant)
{
return await http.PostJsonAsync<Tenant>(apiurl, Tenant);
}
public async Task<Tenant> UpdateTenantAsync(Tenant Tenant)
{
return await http.PutJsonAsync<Tenant>(apiurl + "/" + Tenant.TenantId.ToString(), Tenant);
}
public async Task DeleteTenantAsync(int TenantId)
{
await http.DeleteAsync(apiurl + "/" + TenantId.ToString());
}
}
}

View File

@ -45,7 +45,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + assemblyname + ".dll");
var bytes = await http.GetByteArrayAsync(apiurl + "/" + assemblyname + ".dll");
Assembly.Load(bytes);
}
}
@ -53,7 +53,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(theme.AssemblyName + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + theme.AssemblyName + ".dll");
var bytes = await http.GetByteArrayAsync(apiurl + "/" + theme.AssemblyName + ".dll");
Assembly.Load(bytes);
}
}
@ -61,43 +61,56 @@ namespace Oqtane.Services
return themes.OrderBy(item => item.Name).ToList();
}
public Dictionary<string, string> GetThemeTypes(List<Theme> themes)
public Dictionary<string, string> GetThemeTypes(List<Theme> Themes)
{
var selectableThemes = new Dictionary<string, string>();
foreach (Theme theme in themes)
foreach (Theme theme in Themes)
{
foreach (string themecontrol in theme.ThemeControls.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
selectableThemes.Add(themecontrol, theme.Name + " - " + Utilities.GetTypeNameClass(themecontrol));
selectableThemes.Add(themecontrol, theme.Name + " - " + Utilities.GetTypeNameLastSegment(themecontrol, 0));
}
}
return selectableThemes;
}
public Dictionary<string, string> GetPaneLayoutTypes(List<Theme> themes)
public Dictionary<string, string> GetPaneLayoutTypes(List<Theme> Themes, string ThemeName)
{
var selectablePaneLayouts = new Dictionary<string, string>();
foreach (Theme theme in themes)
{
foreach (string panelayout in theme.PaneLayouts.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
foreach (Theme theme in Themes)
{
if (ThemeName.StartsWith(theme.ThemeName))
{
selectablePaneLayouts.Add(panelayout, theme.Name + " - " + @Utilities.GetTypeNameClass(panelayout));
foreach (string panelayout in theme.PaneLayouts.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
selectablePaneLayouts.Add(panelayout, theme.Name + " - " + @Utilities.GetTypeNameLastSegment(panelayout, 0));
}
}
}
return selectablePaneLayouts;
}
public Dictionary<string, string> GetContainerTypes(List<Theme> themes)
public Dictionary<string, string> GetContainerTypes(List<Theme> Themes)
{
var selectableContainers = new Dictionary<string, string>();
foreach (Theme theme in themes)
foreach (Theme theme in Themes)
{
foreach (string container in theme.ContainerControls.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
selectableContainers.Add(container, theme.Name + " - " + @Utilities.GetTypeNameClass(container));
selectableContainers.Add(container, theme.Name + " - " + @Utilities.GetTypeNameLastSegment(container, 0));
}
}
return selectableContainers;
}
public async Task InstallThemesAsync()
{
await http.GetJsonAsync<List<string>>(apiurl + "/install");
}
public async Task DeleteThemeAsync(string ThemeName)
{
await http.DeleteAsync(apiurl + "/" + ThemeName);
}
}
}

View File

@ -31,9 +31,9 @@ namespace Oqtane.Services
return await http.GetJsonAsync<List<UserRole>>(apiurl);
}
public async Task<List<UserRole>> GetUserRolesAsync(int UserId)
public async Task<List<UserRole>> GetUserRolesAsync(int SiteId)
{
return await http.GetJsonAsync<List<UserRole>>(apiurl + "?userid=" + UserId.ToString());
return await http.GetJsonAsync<List<UserRole>>(apiurl + "?siteid=" + SiteId.ToString());
}
public async Task<UserRole> GetUserRoleAsync(int UserRoleId)

View File

@ -27,9 +27,9 @@ namespace Oqtane.Services
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "User"); }
}
public async Task<List<User>> GetUsersAsync(int SiteId)
public async Task<List<User>> GetUsersAsync()
{
List<User> users = await http.GetJsonAsync<List<User>>(apiurl + "?siteid=" + SiteId.ToString());
List<User> users = await http.GetJsonAsync<List<User>>(apiurl);
return users.OrderBy(item => item.DisplayName).ToList();
}
@ -45,7 +45,26 @@ namespace Oqtane.Services
public async Task<User> AddUserAsync(User User)
{
return await http.PostJsonAsync<User>(apiurl, User);
try
{
return await http.PostJsonAsync<User>(apiurl, User);
}
catch
{
return null;
}
}
public async Task<User> AddUserAsync(User User, Alias Alias)
{
try
{
return await http.PostJsonAsync<User>(CreateApiUrl(Alias, NavigationManager.Uri, "User"), User);
}
catch
{
return null;
}
}
public async Task<User> UpdateUserAsync(User User)
@ -59,13 +78,13 @@ namespace Oqtane.Services
public async Task<User> LoginUserAsync(User User, bool SetCookie, bool IsPersistent)
{
return await http.PostJsonAsync<User>(apiurl + "/login?setcookie=" + SetCookie.ToString() + "&persistent =" + IsPersistent.ToString(), User);
return await http.PostJsonAsync<User>(apiurl + "/login?setcookie=" + SetCookie.ToString() + "&persistent=" + IsPersistent.ToString(), User);
}
public async Task LogoutUserAsync()
public async Task LogoutUserAsync(User User)
{
// best practices recommend post is preferrable to get for logout
await http.PostJsonAsync(apiurl + "/logout", null);
await http.PostJsonAsync(apiurl + "/logout", User);
}
}
}

View File

@ -1,7 +1,4 @@
@using Oqtane.Models
@using Oqtane.Shared
@using Oqtane.Modules
@namespace Oqtane.Shared
@namespace Oqtane.Shared
<CascadingValue Value="@ModuleState">
@DynamicComponent
@ -22,7 +19,7 @@
{
ModuleState = Module; // passed in from Pane component
string container = ModuleState.ContainerType;
if (PageState.ModuleId != -1 && PageState.Control != "" && ModuleState.UseAdminContainer)
if (PageState.ModuleId != -1 && PageState.Action != "" && ModuleState.UseAdminContainer)
{
container = Constants.DefaultAdminContainer;
}
@ -38,7 +35,7 @@
else
{
// container does not exist with type specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageControl));
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageComponent));
builder.AddAttribute(1, "Message", "Error Loading Module Container " + container);
builder.CloseComponent();
}

View File

@ -1,10 +1,7 @@
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Shared
@namespace Oqtane.Shared
@namespace Oqtane.Shared
@inject NavigationManager NavigationManager
@inject IInstallationService InstallationService
@inject ISiteService SiteService
@inject IUserService UserService
<div class="container">
@ -13,7 +10,7 @@
<img src="oqtane.png" />
</div>
</div>
<hr style="width: 100%; color: gray; height: 1px; background-color:gray;" />
<hr class="app-rule" />
<h2 class="text-center">Database Configuration</h2>
<div class="row">
<div class="mx-auto text-center">
@ -35,7 +32,7 @@
<label for="Title" class="control-label" style="font-weight: bold">Server: </label>
</td>
<td>
<input type="text" id="ServerName" class="form-control" @bind="@ServerName" />
<input type="text" class="form-control" @bind="@ServerName" />
</td>
</tr>
<tr>
@ -43,7 +40,7 @@
<label for="Title" class="control-label" style="font-weight: bold">Database: </label>
</td>
<td>
<input type="text" id="DatabaseName" class="form-control" @bind="@DatabaseName" />
<input type="text" class="form-control" @bind="@DatabaseName" />
</td>
</tr>
<tr>
@ -62,7 +59,7 @@
<label for="Title" class="control-label" style="font-weight: bold">Username: </label>
</td>
<td>
<input type="text" id="Username" class="form-control" @bind="@Username" />
<input type="text" class="form-control" @bind="@Username" />
</td>
</tr>
<tr style="@IntegratedSecurityDisplay">
@ -70,14 +67,14 @@
<label for="Title" class="control-label" style="font-weight: bold">Password: </label>
</td>
<td>
<input type="password" id="Password" class="form-control" @bind="@Password" />
<input type="password" class="form-control" @bind="@Password" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
<hr style="width: 100%; color: gray; height: 1px; background-color:gray;" />
<hr class="app-rule" />
<h2 class="text-center">Application Administrator</h2>
<div class="row">
<div class="mx-auto text-center">
@ -85,10 +82,10 @@
<tbody>
<tr>
<td>
<label for="Title" class="control-label" style="font-weight: bold">Email: </label>
<label for="Title" class="control-label" style="font-weight: bold">Username: </label>
</td>
<td>
<input type="text" id="Email" class="form-control" @bind="@Email" />
<input type="text" class="form-control" @bind="@HostUsername" />
</td>
</tr>
<tr>
@ -96,7 +93,15 @@
<label for="Title" class="control-label" style="font-weight: bold">Password: </label>
</td>
<td>
<input type="password" id="Email" class="form-control" @bind="@HostPassword" />
<input type="password" class="form-control" @bind="@HostPassword" />
</td>
</tr>
<tr>
<td>
<label for="Title" class="control-label" style="font-weight: bold">Email: </label>
</td>
<td>
<input type="text" class="form-control" @bind="@HostEmail" />
</td>
</tr>
</tbody>
@ -108,7 +113,7 @@
<button type="button" class="btn btn-success" @onclick="Install">Install Now</button><br /><br />
@((MarkupString)@Message)
</div>
<div class="loading" style="@LoadingDisplay"></div>
<div class="app-progress-indicator" style="@LoadingDisplay"></div>
</div>
</div>
@ -118,18 +123,19 @@
private string DatabaseName = "Oqtane-" + DateTime.Now.ToString("yyyyMMddHHmm");
private string Username = "";
private string Password = "";
private string Email = "";
private string HostUsername = "host";
private string HostPassword = "";
private string HostEmail = "";
private string Message = "";
private string IntegratedSecurityDisplay = "display:none;";
private string LoadingDisplay = "display:none;";
private string IntegratedSecurityDisplay = "display: none;";
private string LoadingDisplay = "display: none;";
private void SetIntegratedSecurity(ChangeEventArgs e)
{
if (Convert.ToBoolean(e.Value))
{
IntegratedSecurityDisplay = "display:none;";
IntegratedSecurityDisplay = "display: none;";
}
else
{
@ -139,7 +145,7 @@
private async Task Install()
{
if (HostPassword.Length >= 6)
if (HostUsername != "" & HostPassword.Length >= 6 & HostEmail != "")
{
LoadingDisplay = "";
StateHasChanged();
@ -152,7 +158,7 @@
else
{
connectionstring = "Data Source=" + ServerName + ";Initial Catalog=" + DatabaseName + ";";
if (IntegratedSecurityDisplay == "display:none;")
if (IntegratedSecurityDisplay == "display: none;")
{
connectionstring += "Integrated Security=SSPI;";
}
@ -165,13 +171,21 @@
GenericResponse response = await InstallationService.Install(connectionstring);
if (response.Success)
{
Site site = new Site();
site.TenantId = -1; // will be populated on server
site.Name = "Default Site";
site.Logo = "oqtane.png";
site.DefaultThemeType = Constants.DefaultTheme;
site.DefaultLayoutType = Constants.DefaultLayout;
site.DefaultContainerType = Constants.DefaultContainer;
site = await SiteService.AddSiteAsync(site);
User user = new User();
user.SiteId = 1;
user.Username = Email;
user.DisplayName = Email;
user.Email = Email;
user.IsHost = true;
user.SiteId = site.SiteId;
user.Username = HostUsername;
user.Password = HostPassword;
user.Email = HostEmail;
user.DisplayName = HostUsername;
user = await UserService.AddUserAsync(user);
NavigationManager.NavigateTo("", true);
@ -179,12 +193,12 @@
else
{
Message = "<div class=\"alert alert-danger\" role=\"alert\">" + response.Message + "</div>";
LoadingDisplay = "display:none;";
LoadingDisplay = "display: none;";
}
}
else
{
Message = "<div class=\"alert alert-danger\" role=\"alert\">Password Must Be 6 Characters Or Greater</div>";
Message = "<div class=\"alert alert-danger\" role=\"alert\">Username And Email Must Be Provided And Password Must Be Greater Than 5 Characters</div>";
}
}
}

View File

@ -42,13 +42,13 @@ namespace Oqtane.Shared
}
}
public Task AddCSS(string filename)
public Task IncludeCSS(string id, string url)
{
try
{
jsRuntime.InvokeAsync<string>(
"interop.addCSS",
filename);
"interop.includeCSS",
id, url);
return Task.CompletedTask;
}
catch
@ -86,6 +86,20 @@ namespace Oqtane.Shared
}
}
public ValueTask<string[]> GetFiles(string name)
{
try
{
return jsRuntime.InvokeAsync<string[]>(
"interop.getFiles",
name);
}
catch
{
return new ValueTask<string[]>(Task.FromResult(new string[0]));
}
}
public Task UploadFiles(string posturl, string folder, string name)
{
try

View File

@ -1,9 +1,14 @@
@using Oqtane.Models
@using Oqtane.Shared
@using Oqtane.Modules
@namespace Oqtane.Shared
@namespace Oqtane.Shared
@DynamicComponent
<ModuleMessage Message="@message" Type="MessageType.Error" />
<CascadingValue Value="this">
<ModuleMessage @ref="modulemessage" />
@DynamicComponent
</CascadingValue>
@if (progressindicator)
{
<div class="app-progress-indicator"></div>
}
@code {
[CascadingParameter]
@ -12,17 +17,24 @@
[CascadingParameter]
private Module ModuleState { get; set; }
private ModuleMessage modulemessage { get; set; }
string message;
RenderFragment DynamicComponent { get; set; }
bool progressindicator = false;
protected override void OnParametersSet()
{
DynamicComponent = builder =>
{
string typename = ModuleState.ModuleType;
if (PageState.Control == "Settings") // module settings are a core component
{
typename = Constants.DefaultSettingsControl;
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, PageState.Action);
}
Type moduleType = null;
if (typename != null)
{
@ -35,11 +47,28 @@
}
else
{
// module does not exist with typename specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageControl));
builder.AddAttribute(1, "Message", "Error Loading Component For Module " + ModuleState.ModuleDefinitionName);
builder.CloseComponent();
// module does not exist with typename specified
message = "Module Does Not Have A Component Named " + Utilities.GetTypeNameLastSegment(typename, 0) + ".razor";
}
};
}
public void AddModuleMessage(string message, MessageType type)
{
progressindicator = false;
StateHasChanged();
modulemessage.SetModuleMessage(message, type);
}
public void ShowProgressIndicator()
{
progressindicator = true;
StateHasChanged();
}
public void HideProgressIndicator()
{
progressindicator = false;
StateHasChanged();
}
}

View File

@ -18,9 +18,8 @@ namespace Oqtane.Shared
public Uri Uri { get; set; }
public Dictionary<string, string> QueryString { get; set; }
public int ModuleId { get; set; }
public string Control { get; set; }
public string Action { get; set; }
public bool EditMode { get; set; }
public bool DesignMode { get; set; }
public int Reload { get; set; }
}
}

View File

@ -1,11 +1,4 @@
@using System
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Shared
@using Oqtane.Security
@using System.Linq
@namespace Oqtane.Shared
@namespace Oqtane.Shared
@inject IUserService UserService
@inject IModuleService ModuleService
@inject IModuleDefinitionService ModuleDefinitionService
@ -34,8 +27,8 @@
{
if (PageState.DesignMode && UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions) && Name != Constants.AdminPane)
{
paneadminborder = "pane-admin-border";
panetitle = "<div class=\"pane-admin-title\">" + Name + " Pane</div>";
paneadminborder = "app-pane-admin-border";
panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
}
else
{
@ -45,23 +38,24 @@
DynamicComponent = builder =>
{
if (PageState.ModuleId != -1 && PageState.Control != "")
if (PageState.ModuleId != -1 && PageState.Action != "")
{
if (Name == Constants.AdminPane)
if (Name.ToLower() == Constants.AdminPane.ToLower())
{
Module module = PageState.Modules.Where(item => item.ModuleId == PageState.ModuleId).FirstOrDefault();
if (module != null)
{
string typename = module.ModuleType;
if (PageState.Control == "Settings")
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
typename = Constants.DefaultSettingsControl;
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, PageState.Action);
}
Type moduleType = Type.GetType(typename);
if (moduleType != null)
{
bool authorized = false;
if (PageState.Control == "Settings")
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions);
}
@ -89,19 +83,19 @@
}
if (authorized)
{
if (PageState.Control != "Settings" && module.ControlTitle != "")
if (!Constants.DefaultModuleActions.Contains(PageState.Action) && module.ControlTitle != "")
{
module.Title = module.ControlTitle;
}
builder.OpenComponent(0, Type.GetType(Constants.DefaultContainer));
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.CloseComponent();
}
}
else
{
// module control does not exist with name specified
}
// module control does not exist with name specified
}
}
}
}
@ -110,12 +104,12 @@
if (PageState.ModuleId != -1)
{
Module module = PageState.Modules.Where(item => item.ModuleId == PageState.ModuleId).FirstOrDefault();
if (module != null && module.Pane == Name)
if (module != null && module.Pane.ToLower() == Name.ToLower())
{
// check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, "View", module.Permissions))
// check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, "View", module.Permissions))
{
builder.OpenComponent(0, Type.GetType(Constants.DefaultContainer));
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.CloseComponent();
}
@ -123,12 +117,12 @@
}
else
{
foreach (Module module in PageState.Modules.Where(item => item.Pane == Name).OrderBy(x => x.Order).ToArray())
foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower() && !item.IsDeleted).OrderBy(x => x.Order).ToArray())
{
// check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, "View", module.Permissions))
// check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, "View", module.Permissions))
{
builder.OpenComponent(0, Type.GetType(Constants.DefaultContainer));
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.SetKey(module.PageModuleId);
builder.CloseComponent();

View File

@ -1,6 +1,4 @@
@using System
@using Oqtane.Shared
@namespace Oqtane.Shared
@namespace Oqtane.Shared
@DynamicComponent
@ -22,8 +20,8 @@
}
else
{
// layout does not exist with type specified
}
// layout does not exist with type specified
}
};
}
}

View File

@ -1,14 +1,4 @@
@using System
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using System.Linq
@using System.Collections.Generic
@using Oqtane.Shared
@using Oqtane.Security
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Routing
@namespace Oqtane.Shared
@namespace Oqtane.Shared
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject SiteState SiteState
@inject NavigationManager NavigationManager
@ -48,7 +38,7 @@
{
if (PageState != null)
{
builder.OpenComponent(0, Type.GetType(Constants.DefaultPage));
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
builder.CloseComponent();
}
};
@ -87,28 +77,44 @@
User user;
List<Module> modules;
int moduleid = -1;
string control = "";
string action = "";
bool editmode = false;
bool designmode = false;
int reload = 0;
Reload reload = Reload.None;
// get Url path and querystring ( and remove anchors )
string path = new Uri(_absoluteUri).PathAndQuery.Substring(1);
if (path.IndexOf("#") != -1)
{
path = path.Substring(0, path.IndexOf("#"));
}
// parse querystring and remove
Dictionary<string, string> querystring = new Dictionary<string, string>();
if (path.IndexOf("?") != -1)
{
querystring = ParseQueryString(path);
path = path.Substring(0, path.IndexOf("?"));
}
if (querystring.ContainsKey("reload"))
{
reload = (Reload)int.Parse(querystring["reload"]);
}
if (PageState != null)
{
reload = PageState.Reload;
editmode = PageState.EditMode;
designmode = PageState.DesignMode;
}
if (PageState == null || reload == Constants.ReloadApplication)
if (PageState == null || reload == Reload.Application)
{
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync();
themes = await ThemeService.GetThemesAsync();
aliases = await AliasService.GetAliasesAsync();
alias = null;
}
else
{
moduledefinitions = PageState.ModuleDefinitions;
themes = PageState.Themes;
aliases = PageState.Aliases;
alias = PageState.Alias;
@ -119,9 +125,9 @@
{
alias = GetAlias(_absoluteUri, aliases);
SiteState.Alias = alias; // set state for services
reload = Constants.ReloadSite;
reload = Reload.Site;
}
if (PageState == null || reload <= Constants.ReloadSite)
if (PageState == null || reload <= Reload.Site)
{
site = await SiteService.GetSiteAsync(alias.SiteId);
}
@ -131,30 +137,17 @@
}
if (site != null)
{
if (PageState == null || reload >= Constants.ReloadSite)
if (PageState == null || reload >= Reload.Site)
{
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(site.SiteId);
pages = await PageService.GetPagesAsync(site.SiteId);
}
else
{
moduledefinitions = PageState.ModuleDefinitions;
pages = PageState.Pages;
}
// get Url path and querystring ( and remove anchors )
string path = new Uri(_absoluteUri).PathAndQuery.Substring(1);
if (path.IndexOf("#") != -1)
{
path = path.Substring(0, path.IndexOf("#"));
}
// parse querystring and remove
Dictionary<string, string> querystring = new Dictionary<string, string>();
if (path.IndexOf("?") != -1)
{
querystring = ParseQueryString(path);
path = path.Substring(0, path.IndexOf("?"));
}
// format path and remove alias
path = path.Replace("//", "/");
if (!path.EndsWith("/")) { path += "/"; }
@ -166,18 +159,18 @@
// extract admin route elements from path
string[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int result;
// check if path has moduleid and control specification ie. page/moduleid/control/
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
{
// path has moduleid and control specification ie. page/moduleid/control/
control = segments[segments.Length - 1];
action = segments[segments.Length - 1];
moduleid = result;
path = path.Replace(moduleid.ToString() + "/" + control + "/", "");
path = path.Replace(moduleid.ToString() + "/" + action + "/", "");
}
else
{
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
// check if path has only moduleid specification ie. page/moduleid/
if (segments.Length >= 1 && int.TryParse(segments[segments.Length - 1], out result))
{
// path has only moduleid specification ie. page/moduleid/
moduleid = result;
path = path.Replace(moduleid.ToString() + "/", "");
}
@ -185,7 +178,7 @@
// remove trailing slash so it can be used as a key for Pages
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);
if (PageState == null || reload >= Constants.ReloadPage)
if (PageState == null || reload >= Reload.Page)
{
page = pages.Where(item => item.Path == path).FirstOrDefault();
}
@ -204,13 +197,13 @@
if (page.Path != path)
{
page = pages.Where(item => item.Path == path).FirstOrDefault();
reload = Constants.ReloadPage;
reload = Reload.Page;
editmode = page.EditMode;
designmode = false;
}
user = null;
if (PageState == null || reload >= Constants.ReloadPage)
if (PageState == null || reload >= Reload.Page)
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity.IsAuthenticated)
@ -228,6 +221,8 @@
// check if user is authorized to view page
if (UserSecurity.IsAuthorized(user, "View", page.Permissions))
{
page = await ProcessPage(page, site, user);
pagestate = new PageState();
pagestate.ModuleDefinitions = moduledefinitions;
pagestate.Themes = themes;
@ -240,17 +235,17 @@
pagestate.Uri = new Uri(_absoluteUri, UriKind.Absolute);
pagestate.QueryString = querystring;
pagestate.ModuleId = moduleid;
pagestate.Control = control;
pagestate.Action = action;
if (PageState != null && (PageState.ModuleId != pagestate.ModuleId || PageState.Control != pagestate.Control))
if (PageState != null && (PageState.ModuleId != pagestate.ModuleId || PageState.Action != pagestate.Action))
{
reload = Constants.ReloadPage;
reload = Reload.Page;
}
if (PageState == null || reload >= Constants.ReloadPage)
if (PageState == null || reload >= Reload.Page)
{
modules = await ModuleService.GetModulesAsync(page.PageId);
modules = ProcessModules(modules, moduledefinitions, pagestate.Control, page.Panes);
modules = await ModuleService.GetModulesAsync(site.SiteId);
modules = ProcessModules(modules, moduledefinitions, page.PageId, pagestate.ModuleId, pagestate.Action, page.Panes, site.DefaultContainerType);
}
else
{
@ -259,18 +254,22 @@
pagestate.Modules = modules;
pagestate.EditMode = editmode;
pagestate.DesignMode = designmode;
pagestate.Reload = Constants.ReloadReset;
OnStateChange?.Invoke(pagestate);
}
else
{
// user is not authorized to view page
if (path != "")
{
NavigationManager.NavigateTo("");
}
}
}
else
{
// page does not exist
NavigationManager.NavigateTo("");
}
}
else
@ -319,15 +318,43 @@
return querystring;
}
private List<Module> ProcessModules(List<Module> modules, List<ModuleDefinition> moduledefinitions, string control, string panes)
private async Task<Page> ProcessPage(Page page, Site site, User user)
{
try
{
if (page.IsPersonalizable && user != null)
{
// load the personalized page
page = await PageService.GetPageAsync(page.PageId, user.UserId);
}
if (string.IsNullOrEmpty(page.ThemeType))
{
page.ThemeType = site.DefaultThemeType;
page.LayoutType = site.DefaultLayoutType;
}
Type type;
if (!string.IsNullOrEmpty(page.LayoutType))
{
type = Type.GetType(page.LayoutType);
}
else
{
type = Type.GetType(page.ThemeType);
}
System.Reflection.PropertyInfo property = type.GetProperty("Panes");
page.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
}
catch
{
// error loading theme or layout
}
return page;
}
private List<Module> ProcessModules(List<Module> modules, List<ModuleDefinition> moduledefinitions, int pageid, int moduleid, string control, string panes, string defaultcontainertype)
{
ModuleDefinition moduledefinition;
if (control == "")
{
control = Constants.DefaultControl;
}
Dictionary<string, int> paneindex = new Dictionary<string, int>();
foreach (Module module in modules)
{
@ -336,56 +363,80 @@
if (moduledefinition != null)
{
string typename = moduledefinition.ControlTypeTemplate;
if (moduledefinition.ControlTypeRoutes != "")
if (module.ModuleId == moduleid && control != "")
{
foreach (string route in moduledefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
// check if the module defines custom routes
if (moduledefinition.ControlTypeRoutes != "")
{
if (route.StartsWith(control + "="))
foreach (string route in moduledefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
typename = route.Replace(control + "=", "");
if (route.StartsWith(control + "="))
{
typename = route.Replace(control + "=", "");
}
}
}
module.ModuleType = typename.Replace(Constants.ActionToken, control);
// admin controls need to load additional metadata from the IModuleControl interface
if (moduleid == module.ModuleId)
{
typename = module.ModuleType;
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(control))
{
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, control);
}
Type moduletype = Type.GetType(typename);
if (moduletype != null)
{
var moduleobject = Activator.CreateInstance(moduletype);
module.SecurityAccessLevel = (SecurityAccessLevel)moduletype.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
module.ControlTitle = (string)moduletype.GetProperty("Title").GetValue(moduleobject);
module.Actions = (string)moduletype.GetProperty("Actions").GetValue(moduleobject);
module.UseAdminContainer = (bool)moduletype.GetProperty("UseAdminContainer").GetValue(moduleobject);
}
}
}
module.ModuleType = typename.Replace("{Control}", control);
// get IModuleControl properties
typename = module.ModuleType;
if (control == "Settings")
else
{
typename = Constants.DefaultSettingsControl;
module.ModuleType = typename.Replace(Constants.ActionToken, Constants.DefaultAction);
}
Type moduletype = Type.GetType(typename);
if (moduletype != null)
}
if (module.PageId == pageid)
{
// ensure module's pane exists in current page and if not, assign it to the Admin pane
if (!panes.ToLower().Contains(module.Pane.ToLower()))
{
var moduleobject = Activator.CreateInstance(moduletype);
module.SecurityAccessLevel = (SecurityAccessLevel)moduletype.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
module.ControlTitle = (string)moduletype.GetProperty("Title").GetValue(moduleobject);
module.Actions = (string)moduletype.GetProperty("Actions").GetValue(moduleobject);
module.UseAdminContainer = (bool)moduletype.GetProperty("UseAdminContainer").GetValue(moduleobject);
module.Pane = Constants.AdminPane;
}
// calculate module position within pane
if (paneindex.ContainsKey(module.Pane))
{
paneindex[module.Pane] += 1;
}
else
{
paneindex.Add(module.Pane, 0);
}
module.PaneModuleIndex = paneindex[module.Pane];
}
// ensure module's pane exists in current page and if not, assign it to the Admin pane
if (!panes.Contains(module.Pane))
if (string.IsNullOrEmpty(module.ContainerType))
{
module.Pane = Constants.AdminPane;
module.ContainerType = defaultcontainertype;
}
// calculate module position within pane
if (paneindex.ContainsKey(module.Pane))
{
paneindex[module.Pane] += 1;
}
else
{
paneindex.Add(module.Pane, 0);
}
module.PaneModuleIndex = paneindex[module.Pane];
}
foreach (Module module in modules)
{
module.PaneModuleCount = paneindex[module.Pane] + 1;
if (module.PageId == pageid)
{
module.PaneModuleCount = paneindex[module.Pane] + 1;
}
}
return modules;
}
@ -414,7 +465,6 @@
// use first alias if Uri does not exist
alias = aliases.FirstOrDefault();
}
alias.Scheme = uri.Scheme;
return alias;
}

View File

@ -1,6 +1,5 @@
@using Oqtane.Shared
@using Oqtane.Modules
@namespace Oqtane.Shared
@namespace Oqtane.Shared
@inject IJSRuntime jsRuntime
@DynamicComponent
@ -21,8 +20,8 @@
}
else
{
// theme does not exist with type specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageControl));
// theme does not exist with type specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageComponent));
builder.AddAttribute(1, "Message", "Error Loading Page Theme " + PageState.Page.ThemeType);
builder.CloseComponent();
}

View File

@ -52,6 +52,10 @@ namespace Oqtane.Client
services.AddScoped<IUserRoleService, UserRoleService>();
services.AddScoped<ISettingService, SettingService>();
services.AddScoped<IFileService, FileService>();
services.AddScoped<IPackageService, PackageService>();
services.AddScoped<ILogService, LogService>();
services.AddScoped<IScheduleService, ScheduleService>();
services.AddScoped<IScheduleLogService, ScheduleLogService>();
// dynamically register module contexts and repository services
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

Some files were not shown because too many files have changed in this diff Show More