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
257 changed files with 20097 additions and 3291 deletions

View File

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

View File

@ -1,37 +1,31 @@
@using Microsoft.AspNetCore.Components.Web @namespace Oqtane.Modules.Admin.Dashboard
@using Microsoft.AspNetCore.Components.Routing
@using Oqtane.Modules
@using Oqtane.Services
@using Oqtane.Models;
@using Oqtane.Security
@namespace Oqtane.Modules.Admin.Dashboard
@inherits ModuleBase @inherits ModuleBase
@inject IPageService PageService @inject IPageService PageService
@inject IUserService UserService @inject IUserService UserService
<ul class="list-group"> <div class="row">
@foreach (var p in pages) @foreach (var p in pages)
{ {
if (UserSecurity.IsAuthorized(PageState.User, "View", p.Permissions)) if (UserSecurity.IsAuthorized(PageState.User, "View", p.Permissions))
{ {
string url = NavigateUrl(p.Path); 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"> <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> </NavLink>
</li> </div>
} }
} }
</ul> </div>
<br />
<br />
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<Page> pages; List<Page> pages;
protected override void OnInitialized() protected override void OnInitialized()
{ {
// display list of pages which are children of current page Page admin = PageState.Pages.Where(item => item.Path == "admin").FirstOrDefault();
pages = PageState.Pages.Where(item => item.ParentId == PageState.Page.PageId).ToList(); 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 @namespace Oqtane.Modules.Admin.Login
@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
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IJSRuntime jsRuntime @inject IJSRuntime jsRuntime
@ -23,7 +14,6 @@
</Authorized> </Authorized>
<NotAuthorized> <NotAuthorized>
<div class="container"> <div class="container">
@((MarkupString)Message)
<div class="form-group"> <div class="form-group">
<label for="Username" class="control-label">Username: </label> <label for="Username" class="control-label">Username: </label>
<input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Username" /> <input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Username" />
@ -47,7 +37,6 @@
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
public string Message { get; set; } = "";
public string Username { get; set; } = ""; public string Username { get; set; } = "";
public string Password { get; set; } = ""; public string Password { get; set; } = "";
public bool Remember { get; set; } = false; public bool Remember { get; set; } = false;
@ -67,6 +56,7 @@
user = await UserService.LoginUserAsync(user, false, false); user = await UserService.LoginUserAsync(user, false, false);
if (user.IsAuthenticated) 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 // complete the login on the server so that the cookies are set correctly on SignalR
var interop = new Interop(jsRuntime); var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken"); string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
@ -75,7 +65,8 @@
} }
else 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 else
@ -88,13 +79,14 @@
user = await UserService.LoginUserAsync(user, true, Remember); user = await UserService.LoginUserAsync(user, true, Remember);
if (user.IsAuthenticated) if (user.IsAuthenticated)
{ {
await logger.LogInformation("Login Successful For Username {Username}", Username);
authstateprovider.NotifyAuthenticationChanged(); authstateprovider.NotifyAuthenticationChanged();
PageState.Reload = Constants.ReloadSite; NavigationManager.NavigateTo(NavigateUrl(ReturnUrl, Reload.Site));
NavigationManager.NavigateTo(NavigateUrl(ReturnUrl));
} }
else 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 @namespace Oqtane.Modules.Admin.ModuleDefinitions
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Modules
@using Oqtane.Services
@using Oqtane.Shared
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IFileService FileService @inject IFileService FileService
@inject IModuleDefinitionService ModuleDefinitionService @inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
@ -16,36 +11,136 @@
<label for="Name" class="control-label">Module: </label> <label for="Name" class="control-label">Module: </label>
</td> </td>
<td> <td>
<FileUpload Filter=".nupkg"></FileUpload> <FileUpload Filter=".nupkg" @ref="fileupload"></FileUpload>
</td> </td>
</tr> </tr>
</table> </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) @if (uploaded)
{ {
<button type="button" class="btn btn-success" @onclick="InstallFile">Install</button> <button type="button" class="btn btn-success" @onclick="InstallModules">Install</button>
}
else
{
<button type="button" class="btn btn-success" @onclick="UploadFile">Upload</button>
} }
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
bool uploaded = false; 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() private async Task UploadFile()
{ {
await FileService.UploadFilesAsync("Modules"); string[] files = await fileupload.GetFiles();
uploaded = true; if (files.Length > 0)
StateHasChanged(); {
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(); try
PageState.Reload = Constants.ReloadApplication; {
NavigationManager.NavigateTo(NavigateUrl()); 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 @namespace Oqtane.Modules.Admin.ModuleDefinitions
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleDefinitionService ModuleDefinitionService @inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
@if (moduledefinitions == null) @if (moduledefinitions == null)
{ {
@ -14,30 +11,94 @@
else else
{ {
<ActionLink Action="Add" Text="Install Module" /> <ActionLink Action="Add" Text="Install Module" />
<table class="table table-borderless">
<thead> <Pager Items="@moduledefinitions">
<tr> <Header>
<th>Name</th> <th>&nbsp;</th>
</tr> <th>&nbsp;</th>
</thead> <th>Name</th>
<tbody> <th>Version</th>
@foreach (var moduledefinition in moduledefinitions) <th>&nbsp;</th>
{ </Header>
<tr> <Row>
<td>@moduledefinition.Name</td> <td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" /></td>
</tr> <td>
} @if (context.AssemblyName != "Oqtane.Client")
</tbody> {
</table> <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 { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
List<ModuleDefinition> moduledefinitions; List<ModuleDefinition> moduledefinitions;
List<Package> packages;
protected override async Task OnInitializedAsync() 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 @namespace Oqtane.Modules.Admin.Modules
@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
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IThemeService ThemeService @inject IThemeService ThemeService
@ -14,7 +6,7 @@
@inject IPageModuleService PageModuleService @inject IPageModuleService PageModuleService
<table class="table table-borderless"> <table class="table table-borderless">
<thead> <tbody>
<tr> <tr>
<td> <td>
<label for="Title" class="control-label">Title: </label> <label for="Title" class="control-label">Title: </label>
@ -23,8 +15,6 @@
<input type="text" name="Title" class="form-control" @bind="@title" /> <input type="text" name="Title" class="form-control" @bind="@title" />
</td> </td>
</tr> </tr>
</thead>
<tbody>
<tr> <tr>
<td> <td>
<label for="Container" class="control-label">Container: </label> <label for="Container" class="control-label">Container: </label>
@ -44,7 +34,7 @@
<label for="Name" class="control-label">Permissions: </label> <label for="Name" class="control-label">Permissions: </label>
</td> </td>
<td> <td>
<PermissionGrid EntityName="Module" Permissions="@permissions" @ref="permissiongrid" /> <PermissionGrid EntityName="Module" PermissionNames="@permissionnames" Permissions="@permissions" @ref="permissiongrid" />
</td> </td>
</tr> </tr>
<tr> <tr>
@ -76,6 +66,7 @@
Dictionary<string, string> containers = new Dictionary<string, string>(); Dictionary<string, string> containers = new Dictionary<string, string>();
string title; string title;
string containertype; string containertype;
string permissionnames = "";
string permissions; string permissions;
string pageid; string pageid;
@ -90,6 +81,7 @@
containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync()); containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync());
containertype = ModuleState.ContainerType; containertype = ModuleState.ContainerType;
permissions = ModuleState.Permissions; permissions = ModuleState.Permissions;
permissionnames = PageState.ModuleDefinitions.Find(item => item.ModuleDefinitionName == ModuleState.ModuleDefinitionName).PermissionNames;
pageid = ModuleState.PageId.ToString(); pageid = ModuleState.PageId.ToString();
DynamicComponent = builder => DynamicComponent = builder =>
@ -111,9 +103,11 @@
await ModuleService.UpdateModuleAsync(module); await ModuleService.UpdateModuleAsync(module);
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId); PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
pagemodule.PageId = int.Parse(pageid);
pagemodule.Title = title; pagemodule.Title = title;
pagemodule.ContainerType = containertype; pagemodule.ContainerType = containertype;
await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
Type moduleType = Type.GetType(ModuleState.ModuleType); Type moduleType = Type.GetType(ModuleState.ModuleType);
if (moduleType != null) if (moduleType != null)
@ -121,8 +115,7 @@
moduleType.GetMethod("UpdateSettings").Invoke(settings, null); // method must be public in settings component moduleType.GetMethod("UpdateSettings").Invoke(settings, null); // method must be public in settings component
} }
PageState.Reload = Constants.ReloadPage; NavigationManager.NavigateTo(NavigateUrl(Reload.Page));
NavigationManager.NavigateTo(NavigateUrl());
} }
} }

View File

@ -1,151 +1,150 @@
@using Microsoft.AspNetCore.Components.Routing @namespace Oqtane.Modules.Admin.Pages
@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 @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IPageService PageService @inject IPageService PageService
@inject IThemeService ThemeService @inject IThemeService ThemeService
<ModuleMessage Message="@message" /> <table class="table table-borderless">
<tr>
<table class="table table-borderless"> <td>
<tr> <label for="Name" class="control-label">Name: </label>
<td> </td>
<label for="Name" class="control-label">Name: </label> <td>
</td> <input class="form-control" @bind="@name" />
<td> </td>
<input class="form-control" @bind="@name" /> </tr>
</td> <tr>
</tr> <td>
<tr> <label for="Name" class="control-label">Path: </label>
<td> </td>
<label for="Name" class="control-label">Path: </label> <td>
</td> <input class="form-control" @bind="@path" />
<td> </td>
<input class="form-control" @bind="@path" /> </tr>
</td> <tr>
</tr> <td>
<tr> <label for="Name" class="control-label">Parent: </label>
<td> </td>
<label for="Name" class="control-label">Parent: </label> <td>
</td> <select class="form-control" @onchange="(e => ParentChanged(e))">
<td> <option value="-1">&lt;Site Root&gt;</option>
<select class="form-control" @onchange="(e => ParentChanged(e))"> @foreach (Page page in pages)
<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)
{ {
<option value="@(page.PageId)">@(page.Name)</option> <option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
} }
</select> </select>
} </td>
</td> </tr>
</tr> <tr>
<tr> <td>
<td> <label for="Name" class="control-label">Insert: </label>
<label for="Name" class="control-label">Navigation? </label> </td>
</td> <td>
<td> <select class="form-control" @bind="@insert">
<select class="form-control" @bind="@isnavigation"> <option value="<<">At Beginning</option>
<option value="True">Yes</option> @if (children != null && children.Count > 0)
<option value="False">No</option> {
</select> <option value="<">Before</option>
</td> <option value=">">After</option>
</tr> }
<tr> <option value=">>">At End</option>
<td> </select>
<label for="Name" class="control-label">Edit Mode? </label> @if (children != null && children.Count > 0 && (insert == "<" || insert == ">"))
</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)
{ {
<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>
</td> </tr>
</tr> <tr>
<tr> <td>
<td> <label for="Name" class="control-label">Navigation? </label>
<label for="Name" class="control-label">Layout: </label> </td>
</td> <td>
<td> <select class="form-control" @bind="@isnavigation">
<select class="form-control" @bind="@layouttype"> <option value="True">Yes</option>
<option value="">&lt;Select Layout&gt;</option> <option value="False">No</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts) </select>
{ </td>
<option value="@panelayout.Key">@panelayout.Value</option> </tr>
} <tr>
</select> <td>
</td> <label for="Name" class="control-label">Personalizable? </label>
</tr> </td>
<tr> <td>
<td> <select class="form-control" @bind="@ispersonalizable">
<label for="Name" class="control-label">Icon: </label> <option value="True">Yes</option>
</td> <option value="False">No</option>
<td> </select>
<input class="form-control" @bind="@icon" /> </td>
</td> </tr>
</tr> <tr>
<tr> <td>
<td> <label for="Name" class="control-label">Default Mode? </label>
<label for="Name" class="control-label">Permissions: </label> </td>
</td> <td>
<td> <select class="form-control" @bind="@mode">
<PermissionGrid EntityName="Page" Permissions="@permissions" @ref="permissiongrid" /> <option value="view">View Mode</option>
</td> <option value="edit">Edit Mode</option>
</tr> </select>
</table> </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> <button type="button" class="btn btn-success" @onclick="SavePage">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string message = "";
Dictionary<string, string> themes = new Dictionary<string, string>(); Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>(); Dictionary<string, string> panelayouts = new Dictionary<string, string>();
@ -157,7 +156,8 @@
List<Page> children; List<Page> children;
int childid = -1; int childid = -1;
string isnavigation = "True"; string isnavigation = "True";
string editmode = "False"; string ispersonalizable = "False";
string mode = "view";
string themetype = ""; string themetype = "";
string layouttype = ""; string layouttype = "";
string icon = ""; string icon = "";
@ -165,7 +165,7 @@
PermissionGrid permissiongrid; PermissionGrid permissiongrid;
protected override void OnInitialized() protected override async Task OnInitializedAsync()
{ {
try try
{ {
@ -173,7 +173,10 @@
children = PageState.Pages.Where(item => item.ParentId == null).ToList(); children = PageState.Pages.Where(item => item.ParentId == null).ToList();
themes = ThemeService.GetThemeTypes(PageState.Themes); 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>(); List<PermissionString> permissionstrings = new List<PermissionString>();
permissionstrings.Add(new PermissionString { PermissionName = "View", Permissions = Constants.AdminRole }); permissionstrings.Add(new PermissionString { PermissionName = "View", Permissions = Constants.AdminRole });
@ -182,16 +185,17 @@
} }
catch (Exception ex) 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 try
{ {
parentid = (string)e.Value; parentid = (string)e.Value;
if (string.IsNullOrEmpty(parentid)) if (parentid == "-1")
{ {
children = PageState.Pages.Where(item => item.ParentId == null).ToList(); children = PageState.Pages.Where(item => item.ParentId == null).ToList();
} }
@ -203,87 +207,121 @@
} }
catch (Exception ex) 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() private async Task SavePage()
{ {
Page page = null;
try try
{ {
Page page = new Page(); if (name != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)))
page.SiteId = PageState.Page.SiteId;
page.Name = name;
if (path == "")
{ {
path = name; page = new Page();
} page.SiteId = PageState.Page.SiteId;
if (path.Contains("/")) page.Name = name;
{ if (path == "")
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.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 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;
Page child; switch (insert)
switch (insert) {
{ case "<<":
case "<<": page.Order = 0;
page.Order = 0; break;
break; case "<":
case "<": child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault(); page.Order = child.Order - 1;
page.Order = child.Order - 1; break;
break; case ">":
case ">": child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault(); page.Order = child.Order + 1;
page.Order = child.Order + 1; break;
break; case ">>":
case ">>": page.Order = int.MaxValue;
page.Order = int.MaxValue; break;
break; }
} page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation));
page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation)); page.EditMode = (mode == "edit" ? true : false);
page.EditMode = (editmode == null ? true : Boolean.Parse(editmode)); page.ThemeType = themetype;
page.ThemeType = themetype; page.LayoutType = (layouttype == null ? "" : layouttype);
page.LayoutType = (layouttype == null ? "" : layouttype); page.Icon = (icon == null ? "" : icon);
page.Icon = (icon == null ? "" : icon); page.Permissions = permissiongrid.GetPermissions();
Type type;
if (!string.IsNullOrEmpty(layouttype)) if (page.ThemeType == PageState.Site.DefaultThemeType)
{ {
type = Type.GetType(layouttype); 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 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) 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 @namespace Oqtane.Modules.Admin.Pages
@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 @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IPageService PageService @inject IPageService PageService
@inject IThemeService ThemeService @inject IThemeService ThemeService
<ModuleMessage Message="@message" />
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
@ -37,7 +27,7 @@
</td> </td>
<td> <td>
<select class="form-control" @onchange="(e => ParentChanged(e))"> <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) @foreach (Page page in pages)
{ {
if (page.PageId.ToString() == parentid) if (page.PageId.ToString() == parentid)
@ -60,7 +50,7 @@
<select class="form-control" @bind="@insert"> <select class="form-control" @bind="@insert">
@if (parentid == currentparentid) @if (parentid == currentparentid)
{ {
<option value="">&lt;Maintain Current Location&gt;</option> <option value="=">&lt;Maintain Current Location&gt;</option>
} }
<option value="<<">To Beginning</option> <option value="<<">To Beginning</option>
@if (children != null && children.Count > 0) @if (children != null && children.Count > 0)
@ -68,7 +58,7 @@
<option value="<">Before</option> <option value="<">Before</option>
<option value=">">After</option> <option value=">">After</option>
} }
<option value=">>" selected>To End</option> <option value=">>">To End</option>
</select> </select>
@if (children != null && children.Count > 0 && (insert == "<" || insert == ">")) @if (children != null && children.Count > 0 && (insert == "<" || insert == ">"))
{ {
@ -95,25 +85,43 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<label for="Name" class="control-label">Edit Mode? </label> <label for="Name" class="control-label">Personalizable? </label>
</td> </td>
<td> <td>
<select class="form-control" @bind="@editmode"> <select class="form-control" @bind="@ispersonalizable">
<option value="True">Yes</option> <option value="True">Yes</option>
<option value="False">No</option> <option value="False">No</option>
</select> </select>
</td> </td>
</tr> </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> <tr>
<td> <td>
<label for="Name" class="control-label">Theme: </label> <label for="Name" class="control-label">Theme: </label>
</td> </td>
<td> <td>
<select class="form-control" @bind="@themetype"> <select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option> <option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes) @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> </select>
</td> </td>
@ -153,13 +161,11 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br /> <br />
<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 { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
string message = "";
Dictionary<string, string> themes = new Dictionary<string, string>(); Dictionary<string, string> themes = new Dictionary<string, string>();
Dictionary<string, string> panelayouts = new Dictionary<string, string>(); Dictionary<string, string> panelayouts = new Dictionary<string, string>();
@ -169,11 +175,12 @@
string path; string path;
string currentparentid; string currentparentid;
string parentid; string parentid;
string insert = ""; string insert = "=";
List<Page> children; List<Page> children;
int childid = -1; int childid = -1;
string isnavigation; string isnavigation;
string editmode; string ispersonalizable;
string mode;
string themetype; string themetype;
string layouttype; string layouttype;
string icon; string icon;
@ -182,10 +189,12 @@
DateTime createdon; DateTime createdon;
string modifiedby; string modifiedby;
DateTime modifiedon; DateTime modifiedon;
string deletedby;
DateTime? deletedon;
PermissionGrid permissiongrid; PermissionGrid permissiongrid;
protected override void OnInitialized() protected override async Task OnInitializedAsync()
{ {
try try
{ {
@ -193,7 +202,6 @@
children = PageState.Pages.Where(item => item.ParentId == null).ToList(); children = PageState.Pages.Where(item => item.ParentId == null).ToList();
themes = ThemeService.GetThemeTypes(PageState.Themes); themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
PageId = Int32.Parse(PageState.QueryString["id"]); PageId = Int32.Parse(PageState.QueryString["id"]);
Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault(); Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
@ -215,8 +223,10 @@
} }
currentparentid = parentid; currentparentid = parentid;
isnavigation = page.IsNavigation.ToString(); isnavigation = page.IsNavigation.ToString();
editmode = page.EditMode.ToString(); ispersonalizable = page.IsPersonalizable.ToString();
mode = (page.EditMode) ? "edit" : "view";
themetype = page.ThemeType; themetype = page.ThemeType;
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes, themetype);
layouttype = page.LayoutType; layouttype = page.LayoutType;
icon = page.Icon; icon = page.Icon;
permissions = page.Permissions; permissions = page.Permissions;
@ -224,20 +234,23 @@
createdon = page.CreatedOn; createdon = page.CreatedOn;
modifiedby = page.ModifiedBy; modifiedby = page.ModifiedBy;
modifiedon = page.ModifiedOn; modifiedon = page.ModifiedOn;
deletedby = page.DeletedBy;
deletedon = page.DeletedOn;
} }
} }
catch (Exception ex) 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 try
{ {
parentid = (string)e.Value; parentid = (string)e.Value;
if (string.IsNullOrEmpty(parentid)) if (parentid == "-1")
{ {
children = PageState.Pages.Where(item => item.ParentId == null).ToList(); children = PageState.Pages.Where(item => item.ParentId == null).ToList();
} }
@ -247,7 +260,7 @@
} }
if (parentid == currentparentid) if (parentid == currentparentid)
{ {
insert = ""; insert = "=";
} }
else else
{ {
@ -257,109 +270,142 @@
} }
catch (Exception ex) 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() private async Task SavePage()
{ {
Page page = null;
try try
{ {
Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault(); if (name != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)))
string currentpath = page.Path; {
page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
string currentpath = page.Path;
page.Name = name; page.Name = name;
if (path == "") if (path == "" && name.ToLower() != "home")
{
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.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 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 != "=")
if (insert != "")
{
Page child;
switch (insert)
{ {
case "<<": Page child;
page.Order = 0; switch (insert)
break; {
case "<": case "<<":
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault(); page.Order = 0;
page.Order = child.Order - 1; break;
break; case "<":
case ">": child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault(); page.Order = child.Order - 1;
page.Order = child.Order + 1; break;
break; case ">":
case ">>": child = PageState.Pages.Where(item => item.PageId == childid).FirstOrDefault();
page.Order = int.MaxValue; page.Order = child.Order + 1;
break; break;
case ">>":
page.Order = int.MaxValue;
break;
}
} }
} page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation));
page.IsNavigation = (isnavigation == null ? true : Boolean.Parse(isnavigation)); page.EditMode = (mode == "edit" ? true : false);
page.EditMode = (editmode == null ? true : Boolean.Parse(editmode)); page.ThemeType = themetype;
page.ThemeType = themetype; page.LayoutType = (layouttype == null ? "" : layouttype);
page.LayoutType = (layouttype == null ? "" : layouttype); page.Icon = (icon == null ? "" : icon);
page.Icon = (icon == null ? "" : icon); page.Permissions = permissiongrid.GetPermissions();
Type type;
if (!string.IsNullOrEmpty(layouttype)) if (page.ThemeType == PageState.Site.DefaultThemeType)
{ {
type = Type.GetType(layouttype); 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 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) 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 @namespace Oqtane.Modules.Admin.Pages
@using Oqtane.Modules.Controls
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Shared
@namespace Oqtane.Modules.Admin.Pages
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@if (PageState.Pages != null) @if (PageState.Pages != null)
{ {
<ActionLink Action="Add" Text="Add Page" /> <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 { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } 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 @namespace Oqtane.Modules.Admin.Register
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Services
@namespace Oqtane.Modules.Admin.Register
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IUserService UserService @inject IUserService UserService
<div class="container"> <div class="container">
<div class="form-group"> <div class="form-group">
<label for="Username" class="control-label">Email: </label> <label for="Username" class="control-label">Username: </label>
<input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Email" /> <input type="text" class="form-control" placeholder="Username" @bind="@Username" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="Password" class="control-label">Password: </label> <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> </div>
<button type="button" class="btn btn-primary" @onclick="RegisterUser">Register</button> <button type="button" class="btn btn-primary" @onclick="RegisterUser">Register</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button> <button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
@ -24,24 +23,49 @@
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
public string Email { get; set; } = ""; string Username = "";
public string Password { get; set; } = ""; string Password = "";
string Email = "";
private async Task RegisterUser() private async Task RegisterUser()
{ {
User user = new User(); try
user.SiteId = PageState.Site.SiteId; {
user.Username = Email; if (Username != "" && Password != "" && Email != "")
user.DisplayName = Email; {
user.Email = Email; User user = new User();
user.IsHost = false; user.SiteId = PageState.Site.SiteId;
user.Password = Password; user.Username = Username;
await UserService.AddUserAsync(user); user.DisplayName = Username;
NavigationManager.NavigateTo(""); 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() 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 @namespace Oqtane.Modules.Admin.Roles
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.Roles
@inherits ModuleBase @inherits ModuleBase
@inject IRoleService RoleService @inject IRoleService RoleService
@ -13,21 +8,20 @@
} }
else else
{ {
<table class="table table-borderless"> <ActionLink Action="Add" Text="Add Role" />
<thead>
<tr> <Pager Items="@Roles">
<th>Name</th> <Header>
</tr> <th>&nbsp;</th>
</thead> <th>&nbsp;</th>
<tbody> <th>Name</th>
@foreach (var Role in Roles) </Header>
{ <Row>
<tr> <td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" /></td>
<td>@Role.Name</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>
</tr> <td>@context.Name</td>
} </Row>
</tbody> </Pager>
</table>
} }
@code { @code {
@ -35,8 +29,23 @@ else
List<Role> Roles; List<Role> Roles;
protected override async Task OnInitializedAsync() protected override async Task OnParametersSetAsync()
{ {
Roles = await RoleService.GetRolesAsync(PageState.Site.SiteId); 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 @namespace Oqtane.Modules.Admin.Sites
@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
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject ITenantService TenantService @inject ITenantService TenantService
@inject IAliasService AliasService @inject IAliasService AliasService
@inject ISiteService SiteService @inject ISiteService SiteService
@inject IPageService PageService @inject IThemeService ThemeService
@inject IUserService UserService
@if (tenants == null) @if (tenants == null)
{ {
@ -19,46 +13,107 @@
} }
else 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> <tr>
<td> <td>
<label for="Name" class="control-label">Tenant: </label> <label for="Name" class="control-label">Host Username:</label>
</td> </td>
<td> <td>
<select class="form-control" @bind="@tenantid"> <input class="form-control" @bind="@username" disabled />
<option value="">&lt;Select Tenant&gt;</option>
@foreach (Tenant tenant in tenants)
{
<option value="@tenant.TenantId">@tenant.Name</option>
}
</select>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<label for="Name" class="control-label">Name: </label> <label for="Name" class="control-label">Host Password:</label>
</td> </td>
<td> <td>
<input class="form-control" @bind="@name" /> <input type="password" class="form-control" @bind="@password" />
</td> </td>
</tr> </tr>
<tr> }
<td> </table>
<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>
<button type="button" class="btn btn-success" @onclick="SaveSite">Save</button> <button type="button" class="btn btn-success" @onclick="SaveSite">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
} }
@ -66,54 +121,152 @@ else
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } 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; List<Tenant> tenants;
string tenantid = ""; string tenantid = "-1";
string name = ""; string name = "";
string url = ""; string urls = "";
string logo = ""; string logo = "";
string themetype = "";
string layouttype = "";
string containertype = "";
bool isinitialized = true;
string username = "";
string password = "";
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
tenants = await TenantService.GetTenantsAsync(); 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() private async Task SaveSite()
{ {
Site site = new Site(); if (tenantid != "-1" && name != "" && urls != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype)) && !string.IsNullOrEmpty(containertype))
site.Name = name; {
site.Logo = (logo == null ? "" : logo); bool isvalid = true;
await SiteService.AddSiteAsync(site);
List<Site> sites = await SiteService.GetSitesAsync();
site = sites.Where(item => item.Name == name).FirstOrDefault();
Alias alias = new Alias(); if (!isinitialized)
alias.Name = url; {
alias.TenantId = int.Parse(tenantid); User user = new User();
alias.SiteId = site.SiteId; user.SiteId = PageState.Site.SiteId;
await AliasService.AddAliasAsync(alias); 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 if (isvalid)
Page p = new Page(); {
p.SiteId = site.SiteId; List<Alias> aliases = new List<Alias>();
p.ParentId = null; urls = urls.Replace("\n", ",");
p.Name = "Home"; foreach (string name in urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
p.Path = ""; {
p.Order = 1; Alias alias = new Alias();
p.IsNavigation = true; alias.Name = name;
p.ThemeType = PageState.Site.DefaultThemeType; alias.TenantId = int.Parse(tenantid);
p.LayoutType = ""; alias.SiteId = -1;
p.Icon = ""; alias = await AliasService.AddAliasAsync(alias);
Type type = Type.GetType(p.ThemeType); aliases.Add(alias);
System.Reflection.PropertyInfo property = type.GetProperty("Panes"); }
p.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
List<PermissionString> permissionstrings = new List<PermissionString>(); Site site = new Site();
permissionstrings.Add(new PermissionString { PermissionName = "View", Permissions = Constants.AllUsersRole }); site.TenantId = int.Parse(tenantid);
permissionstrings.Add(new PermissionString { PermissionName = "Edit", Permissions = Constants.AdminRole }); site.Name = name;
p.Permissions = UserSecurity.SetPermissionStrings(permissionstrings); 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 @namespace Oqtane.Modules.Admin.Sites
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.Sites
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IAliasService AliasService
@inject ISiteService SiteService @inject ISiteService SiteService
@if (sites == null) @if (sites == null)
@ -14,31 +10,55 @@
} }
else 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" /> <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 { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } 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 @namespace Oqtane.Modules.Admin.Themes
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@namespace Oqtane.Modules.Admin.Themes
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService @inject IThemeService ThemeService
@inject IPackageService PackageService
@if (Themes == null) @if (themes == null)
{ {
<p><em>Loading...</em></p> <p><em>Loading...</em></p>
} }
else else
{ {
<table class="table table-borderless"> <ActionLink Action="Add" Text="Install Theme" />
<thead>
<tr> <Pager Items="@themes">
<th>Name</th> <Header>
</tr> <th>&nbsp;</th>
</thead> <th>Name</th>
<tbody> <th>Version</th>
@foreach (var theme in Themes) <th>&nbsp;</th>
{ </Header>
<tr> <Row>
<td>@theme.Name</td> <td>
</tr> @if (context.AssemblyName != "Oqtane.Client")
} {
</tbody> <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))" />
</table> }
</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 { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
List<Theme> Themes; List<Theme> themes;
List<Package> packages;
protected override async Task OnInitializedAsync() 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 @namespace Oqtane.Modules.Admin.UserProfile
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules.Controls
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Services
@namespace Oqtane.Modules.Admin.Profile
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IUserService UserService @inject IUserService UserService
@inject IProfileService ProfileService @inject IProfileService ProfileService
@inject ISettingService SettingService @inject ISettingService SettingService
<ModuleMessage Message="@message" />
@if (PageState.User != null && profiles != null) @if (PageState.User != null && profiles != null)
{ {
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<label for="Name" class="control-label">Name: </label> <label for="Name" class="control-label">Username: </label>
</td> </td>
<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> </td>
</tr> </tr>
<tr> <tr>
@ -32,6 +32,14 @@
<input class="form-control" @bind="@email" /> <input class="form-control" @bind="@email" />
</td> </td>
</tr> </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) @foreach (Profile profile in profiles)
{ {
@ -64,9 +72,10 @@
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } }
string message = ""; string username = "";
string displayname = ""; string password = "";
string email = ""; string email = "";
string displayname = "";
List<Profile> profiles; List<Profile> profiles;
Dictionary<string, string> settings; Dictionary<string, string> settings;
string category = ""; string category = "";
@ -77,19 +86,21 @@
{ {
if (PageState.User != null) if (PageState.User != null)
{ {
displayname = PageState.User.DisplayName; username = PageState.User.Username;
email = PageState.User.Email; email = PageState.User.Email;
displayname = PageState.User.DisplayName;
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId); profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
} }
else else
{ {
message = "Current User Is Not Logged In"; AddModuleMessage("Current User Is Not Logged In", MessageType.Warning);
} }
} }
catch (Exception ex) 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 try
{ {
User user = PageState.User; User user = PageState.User;
user.DisplayName = displayname; user.Username = username;
user.Password = password;
user.Email = email; user.Email = email;
user.DisplayName = displayname;
await UserService.UpdateUserAsync(user); await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
NavigationManager.NavigateTo(""); NavigationManager.NavigateTo(NavigateUrl(""));
} }
catch (Exception ex) 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 @namespace Oqtane.Modules.Admin.Users
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase @inherits ModuleBase
@inject IUserRoleService UserRoleService
@inject IUserService UserService @inject IUserService UserService
@if (Users == null) @if (userroles == null)
{ {
<p><em>Loading...</em></p> <p><em>Loading...</em></p>
} }
else else
{ {
<table class="table"> <ActionLink Action="Add" Text="Add User" />
<thead>
<tr> <Pager Items="@userroles">
<th>Name</th> <Header>
</tr> <th>&nbsp;</th>
</thead> <th>&nbsp;</th>
<tbody> <th>&nbsp;</th>
@foreach (var User in Users) <th>Name</th>
{ </Header>
<tr> <Row>
<td>@User.Username</td> <td><ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" /></td>
</tr> <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>
</tbody> <td>@context.User.DisplayName</td>
</table> </Row>
</Pager>
} }
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
List<User> Users; List<UserRole> userroles;
protected override async Task OnInitializedAsync() 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 @namespace Oqtane.Modules.Controls
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Services
@using Oqtane.Shared
@using Oqtane.Security
@namespace Oqtane.Modules.Controls
@inherits ModuleBase @inherits ModuleBase
@inject IUserService UserService @inject IUserService UserService
@ -15,16 +9,19 @@
@code { @code {
[Parameter] [Parameter]
public string Action { get; set; } public string Action { get; set; } // required
[Parameter] [Parameter]
public string Text { get; set; } // optional public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
[Parameter] [Parameter]
public string Parameters { get; set; } // optional public string Text { get; set; } // optional - defaults to Action if not specified
[Parameter] [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] [Parameter]
public string Style { get; set; } // optional public string Style { get; set; } // optional
@ -39,12 +36,12 @@
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
text = Action; text = Action;
if (!String.IsNullOrEmpty(Text)) if (!string.IsNullOrEmpty(Text))
{ {
text = Text; text = Text;
} }
if (!String.IsNullOrEmpty(Parameters)) if (!string.IsNullOrEmpty(Parameters))
{ {
parameters = Parameters; parameters = Parameters;
} }
@ -60,34 +57,53 @@
} }
url = EditUrl(Action, parameters); url = EditUrl(Action, parameters);
authorized = IsAuthorized();
}
private bool IsAuthorized()
{
bool authorized = false;
if (PageState.EditMode) if (PageState.EditMode)
{ {
string typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameClass(ModuleState.ModuleType) + ",", Action + ","); SecurityAccessLevel security = SecurityAccessLevel.Host;
Type moduleType = Type.GetType(typename); if (Security == null)
if (moduleType != null)
{ {
var moduleobject = Activator.CreateInstance(moduleType); string typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0) + ",", Action + ",");
SecurityAccessLevel SecurityAccessLevel = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null); Type moduleType = Type.GetType(typename);
switch (SecurityAccessLevel) if (moduleType != null)
{ {
case SecurityAccessLevel.Anonymous: var moduleobject = Activator.CreateInstance(moduleType);
authorized = true; security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
break; }
case SecurityAccessLevel.View: else
authorized = UserSecurity.IsAuthorized(PageState.User, "View", ModuleState.Permissions); {
break; security = SecurityAccessLevel.Anonymous; // occurs when an action does not have a corresponding module control
case SecurityAccessLevel.Edit: Class = "btn btn-warning"; // alert developer of missing module comtrol
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;
} }
} }
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 @namespace Oqtane.Modules.Controls
@using Microsoft.AspNetCore.Components.Web
@namespace Oqtane.Modules.Controls
@inherits ModuleBase @inherits ModuleBase
@if (text != "") @if (text != "")
@ -20,6 +18,15 @@
[Parameter] [Parameter]
public DateTime ModifiedOn { get; set; } public DateTime ModifiedOn { get; set; }
[Parameter]
public string DeletedBy { get; set; }
[Parameter]
public DateTime? DeletedOn { get; set; }
[Parameter]
public bool IsDeleted { get; set; }
[Parameter] [Parameter]
public string Style { get; set; } public string Style { get; set; }
@ -56,5 +63,19 @@
} }
text += "</p>"; 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) @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 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> <span id="@progressinfoid"></span> <progress id="@progressbarid" style="visibility: hidden;"></progress>
@ -25,6 +25,7 @@ else
string progressinfoid = ""; string progressinfoid = "";
string progressbarid = ""; string progressbarid = "";
string filter = "*"; string filter = "*";
string files = "";
bool multiple = false; bool multiple = false;
protected override void OnInitialized() protected override void OnInitialized()
@ -43,4 +44,11 @@ else
multiple = bool.Parse(Multiple); 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 @namespace Oqtane.Modules.Controls
@using Oqtane.Modules
@namespace Oqtane.Modules.Controls
@inherits ModuleBase @inherits ModuleBase
@if (Message != "") @if (!string.IsNullOrEmpty(message))
{ {
<div class="@type">@Message</div> <div class="@classname" role="alert">@message</div>
<br />
<br /> <br />
} }
@ -17,24 +14,40 @@
[Parameter] [Parameter]
public MessageType Type { get; set; } 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: case MessageType.Success:
type = "alert alert-success"; classname = "alert alert-success";
break; break;
case MessageType.Info: case MessageType.Info:
type = "alert alert-info"; classname = "alert alert-info";
break; break;
case MessageType.Warning: case MessageType.Warning:
type = "alert alert-warning"; classname = "alert alert-warning";
break; break;
case MessageType.Error: case MessageType.Error:
type = "alert alert-danger"; classname = "alert alert-danger";
break; 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 @namespace Oqtane.Modules.Controls
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Security
@using Oqtane.Shared
@namespace Oqtane.Modules.Controls
@inherits ModuleBase @inherits ModuleBase
@inject IRoleService RoleService @inject IRoleService RoleService
@inject IUserService UserService @inject IUserService UserService
@ -83,6 +77,9 @@
[Parameter] [Parameter]
public string EntityName { get; set; } public string EntityName { get; set; }
[Parameter]
public string PermissionNames { get; set; }
[Parameter] [Parameter]
public string Permissions { get; set; } public string Permissions { get; set; }
@ -95,11 +92,14 @@
protected override async Task OnInitializedAsync() 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"; permissionnames = "View,Edit";
} }
else
{
permissionnames = PermissionNames;
}
roles = await RoleService.GetRolesAsync(ModuleState.SiteId); roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
roles.Insert(0, new Role { Name = Constants.AllUsersRole }); 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" /> <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 @namespace Oqtane.Modules.Counter
@inherits ModuleBase @inherits ModuleBase
Current count: @currentCount Current count: @currentCount

View File

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

View File

@ -1,26 +1,18 @@
@using Microsoft.AspNetCore.Components.Routing @using Oqtane.Modules.HtmlText.Services
@using Microsoft.AspNetCore.Components.Web
@using Oqtane.Modules
@using Oqtane.Modules.Controls
@using Oqtane.Modules.HtmlText.Services
@using Oqtane.Modules.HtmlText.Models @using Oqtane.Modules.HtmlText.Models
@using System.Net.Http;
@using Oqtane.Shared;
@namespace Oqtane.Modules.HtmlText @namespace Oqtane.Modules.HtmlText
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject HttpClient http @inject HttpClient http
@inject SiteState sitestate @inject SiteState sitestate
<ModuleMessage Message="@message" /> <table class="table table-borderless">
<table class="form-group">
<tr> <tr>
<td> <td>
<label for="Name" class="control-label">Content: </label> <label for="Name" class="control-label">Content: </label>
</td> </td>
<td> <td>
<textarea class="form-control" @bind="@content" rows="5" style="width:400px;" /> <textarea class="form-control" @bind="@content" rows="5" />
</td> </td>
</tr> </tr>
</table> </table>
@ -34,7 +26,6 @@
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Edit; } } public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Edit; } }
public override string Title { get { return "Edit Html/Text"; } } public override string Title { get { return "Edit Html/Text"; } }
string message = "";
string content; string content;
string createdby; string createdby;
DateTime createdon; DateTime createdon;
@ -58,7 +49,8 @@
} }
catch (Exception ex) 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; htmltext.Content = content;
await htmltextservice.AddHtmlTextAsync(htmltext); await htmltextservice.AddHtmlTextAsync(htmltext);
} }
PageState.Reload = Constants.ReloadPage; await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
NavigationManager.NavigateTo(NavigateUrl()); NavigationManager.NavigateTo(NavigateUrl(Reload.Page));
} }
catch (Exception ex) 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.HtmlText.Services
@using Oqtane.Modules
@using Oqtane.Modules.HtmlText.Models @using Oqtane.Modules.HtmlText.Models
@using System.Net.Http;
@using Oqtane.Modules.Controls
@using Oqtane.Shared;
@namespace Oqtane.Modules.HtmlText @namespace Oqtane.Modules.HtmlText
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject HttpClient http @inject HttpClient http
@inject SiteState sitestate @inject SiteState sitestate
<ModuleMessage Message="@message" />
@((MarkupString)content) @((MarkupString)content)
<br /> <br />
<ActionLink Action="Edit" /> <ActionLink Action="Edit" />
<br /> <br /><br />
<br />
@code { @code {
string message = "";
string content; string content;
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
@ -37,7 +28,7 @@
} }
catch (Exception ex) 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 namespace Oqtane.Modules.HtmlText
{ {
public class Module : IModule public class ModuleInfo : IModule
{ {
public Dictionary<string, string> Properties public Dictionary<string, string> Properties
{ {
@ -13,7 +12,8 @@ namespace Oqtane.Modules.HtmlText
{ {
{ "Name", "HtmlText" }, { "Name", "HtmlText" },
{ "Description", "Renders HTML or Text" }, { "Description", "Renders HTML or Text" },
{ "Version", "1.0.0" } { "Version", "1.0.0" },
{ "ServerAssemblyName", "Oqtane.Server" }
}; };
return properties; return properties;
} }

View File

@ -1,11 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Oqtane.Services; using Oqtane.Services;
using Oqtane.Modules.HtmlText.Models; using Oqtane.Modules.HtmlText.Models;
using Oqtane.Shared; using Oqtane.Shared;
using Oqtane.Models;
namespace Oqtane.Modules.HtmlText.Services namespace Oqtane.Modules.HtmlText.Services
{ {
@ -29,7 +28,17 @@ namespace Oqtane.Modules.HtmlText.Services
public async Task<HtmlTextInfo> GetHtmlTextAsync(int ModuleId) 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) public async Task AddHtmlTextAsync(HtmlTextInfo htmltext)
@ -46,5 +55,6 @@ namespace Oqtane.Modules.HtmlText.Services
{ {
await http.DeleteAsync(apiurl + "/" + ModuleId.ToString() + "?entityid=" + ModuleId.ToString()); 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 public interface IModuleControl
{ {

View File

@ -1,17 +1,43 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Oqtane.Shared; using Oqtane.Shared;
using Oqtane.Models; using Oqtane.Models;
using System.Threading.Tasks;
using System.Linq;
using Oqtane.Services;
using System;
namespace Oqtane.Modules namespace Oqtane.Modules
{ {
public class ModuleBase : ComponentBase, IModuleControl public class ModuleBase : ComponentBase, IModuleControl
{ {
public Logger logger { get; set; }
public ModuleBase()
{
this.logger = new Logger(this);
}
[Inject]
protected ILogService LoggingService { get; set; }
[CascadingParameter] [CascadingParameter]
protected PageState PageState { get; set; } protected PageState PageState { get; set; }
[CascadingParameter] [CascadingParameter]
protected Module ModuleState { get; set; } 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 SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security
public virtual string Title { get { return ""; } } public virtual string Title { get { return ""; } }
@ -20,19 +46,42 @@ namespace Oqtane.Modules
public virtual bool UseAdminContainer { get { return true; } } public virtual bool UseAdminContainer { get { return true; } }
// path method
public string ModulePath()
{
return "Modules/" + this.GetType().Namespace + "/";
}
// url methods
public string NavigateUrl() public string NavigateUrl()
{ {
return NavigateUrl(PageState.Page.Path); return NavigateUrl(PageState.Page.Path);
} }
public string NavigateUrl(Reload reload)
{
return NavigateUrl(PageState.Page.Path, reload);
}
public string NavigateUrl(string path) 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) 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) public string EditUrl(string action)
@ -59,5 +108,126 @@ namespace Oqtane.Modules
{ {
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters); 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 @using Oqtane.Modules.Weather.Services
@namespace Oqtane.Modules.Weather @namespace Oqtane.Modules.Weather
@inherits ModuleBase @inherits ModuleBase

View File

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

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
<RestoreAdditionalProjectSources> <RestoreAdditionalProjectSources>
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
https://dotnet.myget.org/F/blazor-dev/api/v3/index.json; https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;
@ -27,10 +28,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Blazor" 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.19424.4" PrivateAssets="all" /> <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.19424.4" /> <PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview9.19465.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.0.0-preview9.19424.4" /> <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.0.0" />
</ItemGroup> </ItemGroup>
<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.AspNetCore.Components;
using Microsoft.JSInterop; using Microsoft.JSInterop;
using Oqtane.Shared; using Oqtane.Shared;
@ -7,12 +10,14 @@ namespace Oqtane.Services
{ {
public class FileService : ServiceBase, IFileService public class FileService : ServiceBase, IFileService
{ {
private readonly HttpClient http;
private readonly SiteState sitestate; private readonly SiteState sitestate;
private readonly NavigationManager NavigationManager; private readonly NavigationManager NavigationManager;
private readonly IJSRuntime jsRuntime; 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.sitestate = sitestate;
this.NavigationManager = NavigationManager; this.NavigationManager = NavigationManager;
this.jsRuntime = jsRuntime; this.jsRuntime = jsRuntime;
@ -23,15 +28,52 @@ namespace Oqtane.Services
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "File"); } 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); var interop = new Interop(jsRuntime);
await interop.UploadFiles(apiurl + "/upload", Folder, FileUploadName); 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); 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 public interface IFileService
{ {
Task UploadFilesAsync(string Folder); Task<List<string>> GetFilesAsync(string Folder);
Task UploadFilesAsync(string Folder, string FileUploadName); 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 Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Oqtane.Services namespace Oqtane.Services
@ -8,5 +7,6 @@ namespace Oqtane.Services
{ {
Task<GenericResponse> IsInstalled(); Task<GenericResponse> IsInstalled();
Task<GenericResponse> Install(string connectionstring); 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 public interface IModuleDefinitionService
{ {
Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(); Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int SiteId);
Task InstallModulesAsync(); Task UpdateModuleDefinitionAsync(ModuleDefinition ModuleDefinition);
} Task InstallModuleDefinitionsAsync();
Task DeleteModuleDefinitionAsync(int ModuleDefinitionId, int SiteId);
}
} }

View File

@ -6,11 +6,12 @@ namespace Oqtane.Services
{ {
public interface IModuleService public interface IModuleService
{ {
Task<List<Module>> GetModulesAsync(int PageId); Task<List<Module>> GetModulesAsync(int SiteId);
Task<List<Module>> GetModulesAsync(int SiteId, string ModuleDefinitionName);
Task<Module> GetModuleAsync(int ModuleId); Task<Module> GetModuleAsync(int ModuleId);
Task<Module> AddModuleAsync(Module Module); Task<Module> AddModuleAsync(Module Module);
Task<Module> UpdateModuleAsync(Module Module); Task<Module> UpdateModuleAsync(Module Module);
Task DeleteModuleAsync(int ModuleId); 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<List<PageModule>> GetPageModulesAsync();
Task<PageModule> GetPageModuleAsync(int PageModuleId); Task<PageModule> GetPageModuleAsync(int PageModuleId);
Task<PageModule> GetPageModuleAsync(int PageId, int ModuleId);
Task<PageModule> AddPageModuleAsync(PageModule PageModule); Task<PageModule> AddPageModuleAsync(PageModule PageModule);
Task<PageModule> UpdatePageModuleAsync(PageModule PageModule); Task<PageModule> UpdatePageModuleAsync(PageModule PageModule);
Task UpdatePageModuleOrderAsync(int PageId, string Pane); Task UpdatePageModuleOrderAsync(int PageId, string Pane);

View File

@ -8,9 +8,10 @@ namespace Oqtane.Services
{ {
Task<List<Page>> GetPagesAsync(int SiteId); Task<List<Page>> GetPagesAsync(int SiteId);
Task<Page> GetPageAsync(int PageId); Task<Page> GetPageAsync(int PageId);
Task<Page> GetPageAsync(int PageId, int UserId);
Task<Page> AddPageAsync(Page Page); Task<Page> AddPageAsync(Page Page);
Task<Page> UpdatePageAsync(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); 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 public interface ISiteService
{ {
Task<List<Site>> GetSitesAsync(); Task<List<Site>> GetSitesAsync();
Task<List<Site>> GetSitesAsync(Alias Alias);
Task<Site> GetSiteAsync(int SiteId); Task<Site> GetSiteAsync(int SiteId);
Task<Site> GetSiteAsync(int SiteId, Alias Alias);
Task<Site> AddSiteAsync(Site Site); Task<Site> AddSiteAsync(Site Site);
Task<Site> AddSiteAsync(Site Site, Alias Alias);
Task<Site> UpdateSiteAsync(Site Site); Task<Site> UpdateSiteAsync(Site Site);
Task<Site> UpdateSiteAsync(Site Site, Alias Alias);
Task DeleteSiteAsync(int SiteId); Task DeleteSiteAsync(int SiteId);
Task DeleteSiteAsync(int SiteId, Alias Alias);
} }
} }

View File

@ -8,6 +8,12 @@ namespace Oqtane.Services
{ {
Task<List<Tenant>> GetTenantsAsync(); 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 public interface IThemeService
{ {
Task<List<Theme>> GetThemesAsync(); Task<List<Theme>> GetThemesAsync();
Dictionary<string, string> GetThemeTypes(List<Theme> themes); Dictionary<string, string> GetThemeTypes(List<Theme> Themes);
Dictionary<string, string> GetPaneLayoutTypes(List<Theme> themes); Dictionary<string, string> GetPaneLayoutTypes(List<Theme> Themes, string ThemeName);
Dictionary<string, string> GetContainerTypes(List<Theme> themes); 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 public interface IUserRoleService
{ {
Task<List<UserRole>> GetUserRolesAsync(); Task<List<UserRole>> GetUserRolesAsync();
Task<List<UserRole>> GetUserRolesAsync(int UserId); Task<List<UserRole>> GetUserRolesAsync(int SiteId);
Task<UserRole> GetUserRoleAsync(int UserRoleId); Task<UserRole> GetUserRoleAsync(int UserRoleId);
Task<UserRole> AddUserRoleAsync(UserRole UserRole); Task<UserRole> AddUserRoleAsync(UserRole UserRole);
Task<UserRole> UpdateUserRoleAsync(UserRole UserRole); Task<UserRole> UpdateUserRoleAsync(UserRole UserRole);

View File

@ -6,7 +6,7 @@ namespace Oqtane.Services
{ {
public interface IUserService public interface IUserService
{ {
Task<List<User>> GetUsersAsync(int SiteId); Task<List<User>> GetUsersAsync();
Task<User> GetUserAsync(int UserId, int SiteId); Task<User> GetUserAsync(int UserId, int SiteId);
@ -14,12 +14,14 @@ namespace Oqtane.Services
Task<User> AddUserAsync(User User); Task<User> AddUserAsync(User User);
Task<User> AddUserAsync(User User, Alias alias);
Task<User> UpdateUserAsync(User User); Task<User> UpdateUserAsync(User User);
Task DeleteUserAsync(int UserId); Task DeleteUserAsync(int UserId);
Task<User> LoginUserAsync(User User, bool SetCookie, bool IsPersistent); 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"); } 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 // 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 ) // 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(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
@ -47,7 +47,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null) if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{ {
// download assembly from server and load // 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); Assembly.Load(bytes);
} }
} }
@ -56,7 +56,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(moduledefinition.AssemblyName + ",")).FirstOrDefault() == null) if (assemblies.Where(item => item.FullName.StartsWith(moduledefinition.AssemblyName + ",")).FirstOrDefault() == null)
{ {
// download assembly from server and load // 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); Assembly.Load(bytes);
} }
} }
@ -64,9 +64,19 @@ namespace Oqtane.Services
return moduledefinitions.OrderBy(item => item.Name).ToList(); 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"); 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"); } 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 modules = modules
.OrderBy(item => item.Order) .OrderBy(item => item.Order)
.ToList(); .ToList();
return modules; 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) public async Task<Module> GetModuleAsync(int ModuleId)
{ {
return await http.GetJsonAsync<Module>(apiurl + "/" + ModuleId.ToString()); return await http.GetJsonAsync<Module>(apiurl + "/" + ModuleId.ToString());
@ -60,5 +54,15 @@ namespace Oqtane.Services
{ {
await http.DeleteAsync(apiurl + "/" + ModuleId.ToString()); 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()); 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) public async Task<PageModule> AddPageModuleAsync(PageModule PageModule)
{ {
return await http.PostJsonAsync<PageModule>(apiurl, 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()); 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) public async Task<Page> AddPageAsync(Page Page)
{ {
return await http.PostJsonAsync<Page>(apiurl, 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); 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) 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) public static string CreateApiUrl(Alias alias, string absoluteUri, string serviceName)
{ {
string apiurl = ""; Uri uri = new Uri(absoluteUri);
string apiurl;
if (alias != null) if (alias != null)
{ {
// build a url which passes the alias that may include a subfolder for multi-tenancy // 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 == "") if (alias.Path == "")
{ {
apiurl += "~/"; apiurl += "~/";
@ -23,7 +25,6 @@ namespace Oqtane.Services
else else
{ {
// build a url which ignores any subfolder for multi-tenancy // build a url which ignores any subfolder for multi-tenancy
Uri uri = new Uri(absoluteUri);
apiurl = uri.Scheme + "://" + uri.Authority + "/~/"; apiurl = uri.Scheme + "://" + uri.Authority + "/~/";
} }
apiurl += "api/" + serviceName; apiurl += "api/" + serviceName;

View File

@ -31,24 +31,47 @@ namespace Oqtane.Services
List<Site> sites = await http.GetJsonAsync<List<Site>>(apiurl); List<Site> sites = await http.GetJsonAsync<List<Site>>(apiurl);
return sites.OrderBy(item => item.Name).ToList(); 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) public async Task<Site> GetSiteAsync(int SiteId)
{ {
return await http.GetJsonAsync<Site>(apiurl + "/" + SiteId.ToString()); 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) public async Task<Site> AddSiteAsync(Site Site)
{ {
return await http.PostJsonAsync<Site>(apiurl, 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) public async Task<Site> UpdateSiteAsync(Site Site)
{ {
return await http.PutJsonAsync<Site>(apiurl + "/" + Site.SiteId.ToString(), 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) public async Task DeleteSiteAsync(int SiteId)
{ {
await http.DeleteAsync(apiurl + "/" + SiteId.ToString()); 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(); 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) if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{ {
// download assembly from server and load // 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); Assembly.Load(bytes);
} }
} }
@ -53,7 +53,7 @@ namespace Oqtane.Services
if (assemblies.Where(item => item.FullName.StartsWith(theme.AssemblyName + ",")).FirstOrDefault() == null) if (assemblies.Where(item => item.FullName.StartsWith(theme.AssemblyName + ",")).FirstOrDefault() == null)
{ {
// download assembly from server and load // 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); Assembly.Load(bytes);
} }
} }
@ -61,43 +61,56 @@ namespace Oqtane.Services
return themes.OrderBy(item => item.Name).ToList(); 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>(); 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)) 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; 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>(); var selectablePaneLayouts = new Dictionary<string, string>();
foreach (Theme theme in themes) foreach (Theme theme in Themes)
{ {
foreach (string panelayout in theme.PaneLayouts.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) 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; return selectablePaneLayouts;
} }
public Dictionary<string, string> GetContainerTypes(List<Theme> themes) public Dictionary<string, string> GetContainerTypes(List<Theme> Themes)
{ {
var selectableContainers = new Dictionary<string, string>(); 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)) 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; 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); 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) public async Task<UserRole> GetUserRoleAsync(int UserRoleId)

View File

@ -27,9 +27,9 @@ namespace Oqtane.Services
get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "User"); } 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(); return users.OrderBy(item => item.DisplayName).ToList();
} }
@ -45,7 +45,26 @@ namespace Oqtane.Services
public async Task<User> AddUserAsync(User User) 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) 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) 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 // 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 @namespace Oqtane.Shared
@using Oqtane.Shared
@using Oqtane.Modules
@namespace Oqtane.Shared
<CascadingValue Value="@ModuleState"> <CascadingValue Value="@ModuleState">
@DynamicComponent @DynamicComponent
@ -22,7 +19,7 @@
{ {
ModuleState = Module; // passed in from Pane component ModuleState = Module; // passed in from Pane component
string container = ModuleState.ContainerType; string container = ModuleState.ContainerType;
if (PageState.ModuleId != -1 && PageState.Control != "" && ModuleState.UseAdminContainer) if (PageState.ModuleId != -1 && PageState.Action != "" && ModuleState.UseAdminContainer)
{ {
container = Constants.DefaultAdminContainer; container = Constants.DefaultAdminContainer;
} }
@ -38,7 +35,7 @@
else else
{ {
// container does not exist with type specified // 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.AddAttribute(1, "Message", "Error Loading Module Container " + container);
builder.CloseComponent(); builder.CloseComponent();
} }

View File

@ -1,10 +1,7 @@
@using Microsoft.AspNetCore.Components.Web @namespace Oqtane.Shared
@using Oqtane.Services
@using Oqtane.Models
@using Oqtane.Shared
@namespace Oqtane.Shared
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IInstallationService InstallationService @inject IInstallationService InstallationService
@inject ISiteService SiteService
@inject IUserService UserService @inject IUserService UserService
<div class="container"> <div class="container">
@ -13,7 +10,7 @@
<img src="oqtane.png" /> <img src="oqtane.png" />
</div> </div>
</div> </div>
<hr style="width: 100%; color: gray; height: 1px; background-color:gray;" /> <hr class="app-rule" />
<h2 class="text-center">Database Configuration</h2> <h2 class="text-center">Database Configuration</h2>
<div class="row"> <div class="row">
<div class="mx-auto text-center"> <div class="mx-auto text-center">
@ -35,7 +32,7 @@
<label for="Title" class="control-label" style="font-weight: bold">Server: </label> <label for="Title" class="control-label" style="font-weight: bold">Server: </label>
</td> </td>
<td> <td>
<input type="text" id="ServerName" class="form-control" @bind="@ServerName" /> <input type="text" class="form-control" @bind="@ServerName" />
</td> </td>
</tr> </tr>
<tr> <tr>
@ -43,7 +40,7 @@
<label for="Title" class="control-label" style="font-weight: bold">Database: </label> <label for="Title" class="control-label" style="font-weight: bold">Database: </label>
</td> </td>
<td> <td>
<input type="text" id="DatabaseName" class="form-control" @bind="@DatabaseName" /> <input type="text" class="form-control" @bind="@DatabaseName" />
</td> </td>
</tr> </tr>
<tr> <tr>
@ -62,7 +59,7 @@
<label for="Title" class="control-label" style="font-weight: bold">Username: </label> <label for="Title" class="control-label" style="font-weight: bold">Username: </label>
</td> </td>
<td> <td>
<input type="text" id="Username" class="form-control" @bind="@Username" /> <input type="text" class="form-control" @bind="@Username" />
</td> </td>
</tr> </tr>
<tr style="@IntegratedSecurityDisplay"> <tr style="@IntegratedSecurityDisplay">
@ -70,14 +67,14 @@
<label for="Title" class="control-label" style="font-weight: bold">Password: </label> <label for="Title" class="control-label" style="font-weight: bold">Password: </label>
</td> </td>
<td> <td>
<input type="password" id="Password" class="form-control" @bind="@Password" /> <input type="password" class="form-control" @bind="@Password" />
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
<hr style="width: 100%; color: gray; height: 1px; background-color:gray;" /> <hr class="app-rule" />
<h2 class="text-center">Application Administrator</h2> <h2 class="text-center">Application Administrator</h2>
<div class="row"> <div class="row">
<div class="mx-auto text-center"> <div class="mx-auto text-center">
@ -85,10 +82,10 @@
<tbody> <tbody>
<tr> <tr>
<td> <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>
<td> <td>
<input type="text" id="Email" class="form-control" @bind="@Email" /> <input type="text" class="form-control" @bind="@HostUsername" />
</td> </td>
</tr> </tr>
<tr> <tr>
@ -96,7 +93,15 @@
<label for="Title" class="control-label" style="font-weight: bold">Password: </label> <label for="Title" class="control-label" style="font-weight: bold">Password: </label>
</td> </td>
<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> </td>
</tr> </tr>
</tbody> </tbody>
@ -108,7 +113,7 @@
<button type="button" class="btn btn-success" @onclick="Install">Install Now</button><br /><br /> <button type="button" class="btn btn-success" @onclick="Install">Install Now</button><br /><br />
@((MarkupString)@Message) @((MarkupString)@Message)
</div> </div>
<div class="loading" style="@LoadingDisplay"></div> <div class="app-progress-indicator" style="@LoadingDisplay"></div>
</div> </div>
</div> </div>
@ -118,18 +123,19 @@
private string DatabaseName = "Oqtane-" + DateTime.Now.ToString("yyyyMMddHHmm"); private string DatabaseName = "Oqtane-" + DateTime.Now.ToString("yyyyMMddHHmm");
private string Username = ""; private string Username = "";
private string Password = ""; private string Password = "";
private string Email = ""; private string HostUsername = "host";
private string HostPassword = ""; private string HostPassword = "";
private string HostEmail = "";
private string Message = ""; private string Message = "";
private string IntegratedSecurityDisplay = "display:none;"; private string IntegratedSecurityDisplay = "display: none;";
private string LoadingDisplay = "display:none;"; private string LoadingDisplay = "display: none;";
private void SetIntegratedSecurity(ChangeEventArgs e) private void SetIntegratedSecurity(ChangeEventArgs e)
{ {
if (Convert.ToBoolean(e.Value)) if (Convert.ToBoolean(e.Value))
{ {
IntegratedSecurityDisplay = "display:none;"; IntegratedSecurityDisplay = "display: none;";
} }
else else
{ {
@ -139,7 +145,7 @@
private async Task Install() private async Task Install()
{ {
if (HostPassword.Length >= 6) if (HostUsername != "" & HostPassword.Length >= 6 & HostEmail != "")
{ {
LoadingDisplay = ""; LoadingDisplay = "";
StateHasChanged(); StateHasChanged();
@ -152,7 +158,7 @@
else else
{ {
connectionstring = "Data Source=" + ServerName + ";Initial Catalog=" + DatabaseName + ";"; connectionstring = "Data Source=" + ServerName + ";Initial Catalog=" + DatabaseName + ";";
if (IntegratedSecurityDisplay == "display:none;") if (IntegratedSecurityDisplay == "display: none;")
{ {
connectionstring += "Integrated Security=SSPI;"; connectionstring += "Integrated Security=SSPI;";
} }
@ -165,13 +171,21 @@
GenericResponse response = await InstallationService.Install(connectionstring); GenericResponse response = await InstallationService.Install(connectionstring);
if (response.Success) 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 user = new User();
user.SiteId = 1; user.SiteId = site.SiteId;
user.Username = Email; user.Username = HostUsername;
user.DisplayName = Email;
user.Email = Email;
user.IsHost = true;
user.Password = HostPassword; user.Password = HostPassword;
user.Email = HostEmail;
user.DisplayName = HostUsername;
user = await UserService.AddUserAsync(user); user = await UserService.AddUserAsync(user);
NavigationManager.NavigateTo("", true); NavigationManager.NavigateTo("", true);
@ -179,12 +193,12 @@
else else
{ {
Message = "<div class=\"alert alert-danger\" role=\"alert\">" + response.Message + "</div>"; Message = "<div class=\"alert alert-danger\" role=\"alert\">" + response.Message + "</div>";
LoadingDisplay = "display:none;"; LoadingDisplay = "display: none;";
} }
} }
else 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 try
{ {
jsRuntime.InvokeAsync<string>( jsRuntime.InvokeAsync<string>(
"interop.addCSS", "interop.includeCSS",
filename); id, url);
return Task.CompletedTask; return Task.CompletedTask;
} }
catch 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) public Task UploadFiles(string posturl, string folder, string name)
{ {
try try

View File

@ -1,9 +1,14 @@
@using Oqtane.Models @namespace Oqtane.Shared
@using Oqtane.Shared
@using Oqtane.Modules
@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 { @code {
[CascadingParameter] [CascadingParameter]
@ -12,17 +17,24 @@
[CascadingParameter] [CascadingParameter]
private Module ModuleState { get; set; } private Module ModuleState { get; set; }
private ModuleMessage modulemessage { get; set; }
string message;
RenderFragment DynamicComponent { get; set; } RenderFragment DynamicComponent { get; set; }
bool progressindicator = false;
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
DynamicComponent = builder => DynamicComponent = builder =>
{ {
string typename = ModuleState.ModuleType; string typename = ModuleState.ModuleType;
if (PageState.Control == "Settings") // module settings are a core component // 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 = null; Type moduleType = null;
if (typename != null) if (typename != null)
{ {
@ -35,11 +47,28 @@
} }
else else
{ {
// module does not exist with typename specified // module does not exist with typename specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageControl)); message = "Module Does Not Have A Component Named " + Utilities.GetTypeNameLastSegment(typename, 0) + ".razor";
builder.AddAttribute(1, "Message", "Error Loading Component For Module " + ModuleState.ModuleDefinitionName);
builder.CloseComponent();
} }
}; };
} }
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 Uri Uri { get; set; }
public Dictionary<string, string> QueryString { get; set; } public Dictionary<string, string> QueryString { get; set; }
public int ModuleId { get; set; } public int ModuleId { get; set; }
public string Control { get; set; } public string Action { get; set; }
public bool EditMode { get; set; } public bool EditMode { get; set; }
public bool DesignMode { get; set; } public bool DesignMode { get; set; }
public int Reload { get; set; }
} }
} }

View File

@ -1,11 +1,4 @@
@using System @namespace Oqtane.Shared
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Models
@using Oqtane.Shared
@using Oqtane.Security
@using System.Linq
@namespace Oqtane.Shared
@inject IUserService UserService @inject IUserService UserService
@inject IModuleService ModuleService @inject IModuleService ModuleService
@inject IModuleDefinitionService ModuleDefinitionService @inject IModuleDefinitionService ModuleDefinitionService
@ -34,8 +27,8 @@
{ {
if (PageState.DesignMode && UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions) && Name != Constants.AdminPane) if (PageState.DesignMode && UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions) && Name != Constants.AdminPane)
{ {
paneadminborder = "pane-admin-border"; paneadminborder = "app-pane-admin-border";
panetitle = "<div class=\"pane-admin-title\">" + Name + " Pane</div>"; panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
} }
else else
{ {
@ -45,23 +38,24 @@
DynamicComponent = builder => 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(); Module module = PageState.Modules.Where(item => item.ModuleId == PageState.ModuleId).FirstOrDefault();
if (module != null) if (module != null)
{ {
string typename = module.ModuleType; 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); Type moduleType = Type.GetType(typename);
if (moduleType != null) if (moduleType != null)
{ {
bool authorized = false; bool authorized = false;
if (PageState.Control == "Settings") if (Constants.DefaultModuleActions.Contains(PageState.Action))
{ {
authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions); authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions);
} }
@ -89,19 +83,19 @@
} }
if (authorized) if (authorized)
{ {
if (PageState.Control != "Settings" && module.ControlTitle != "") if (!Constants.DefaultModuleActions.Contains(PageState.Action) && module.ControlTitle != "")
{ {
module.Title = 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.AddAttribute(1, "Module", module);
builder.CloseComponent(); builder.CloseComponent();
} }
} }
else 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) if (PageState.ModuleId != -1)
{ {
Module module = PageState.Modules.Where(item => item.ModuleId == PageState.ModuleId).FirstOrDefault(); 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 // check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, "View", module.Permissions)) 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.AddAttribute(1, "Module", module);
builder.CloseComponent(); builder.CloseComponent();
} }
@ -123,12 +117,12 @@
} }
else 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 // check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, "View", module.Permissions)) 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.AddAttribute(1, "Module", module);
builder.SetKey(module.PageModuleId); builder.SetKey(module.PageModuleId);
builder.CloseComponent(); builder.CloseComponent();

View File

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

View File

@ -1,14 +1,4 @@
@using System @namespace Oqtane.Shared
@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
@inject AuthenticationStateProvider AuthenticationStateProvider @inject AuthenticationStateProvider AuthenticationStateProvider
@inject SiteState SiteState @inject SiteState SiteState
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@ -48,7 +38,7 @@
{ {
if (PageState != null) if (PageState != null)
{ {
builder.OpenComponent(0, Type.GetType(Constants.DefaultPage)); builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
builder.CloseComponent(); builder.CloseComponent();
} }
}; };
@ -87,28 +77,44 @@
User user; User user;
List<Module> modules; List<Module> modules;
int moduleid = -1; int moduleid = -1;
string control = ""; string action = "";
bool editmode = false; bool editmode = false;
bool designmode = 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) if (PageState != null)
{ {
reload = PageState.Reload;
editmode = PageState.EditMode; editmode = PageState.EditMode;
designmode = PageState.DesignMode; designmode = PageState.DesignMode;
} }
if (PageState == null || reload == Constants.ReloadApplication) if (PageState == null || reload == Reload.Application)
{ {
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync();
themes = await ThemeService.GetThemesAsync(); themes = await ThemeService.GetThemesAsync();
aliases = await AliasService.GetAliasesAsync(); aliases = await AliasService.GetAliasesAsync();
alias = null; alias = null;
} }
else else
{ {
moduledefinitions = PageState.ModuleDefinitions;
themes = PageState.Themes; themes = PageState.Themes;
aliases = PageState.Aliases; aliases = PageState.Aliases;
alias = PageState.Alias; alias = PageState.Alias;
@ -119,9 +125,9 @@
{ {
alias = GetAlias(_absoluteUri, aliases); alias = GetAlias(_absoluteUri, aliases);
SiteState.Alias = alias; // set state for services 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); site = await SiteService.GetSiteAsync(alias.SiteId);
} }
@ -131,30 +137,17 @@
} }
if (site != null) 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); pages = await PageService.GetPagesAsync(site.SiteId);
} }
else else
{ {
moduledefinitions = PageState.ModuleDefinitions;
pages = PageState.Pages; 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 // format path and remove alias
path = path.Replace("//", "/"); path = path.Replace("//", "/");
if (!path.EndsWith("/")) { path += "/"; } if (!path.EndsWith("/")) { path += "/"; }
@ -166,18 +159,18 @@
// extract admin route elements from path // extract admin route elements from path
string[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); string[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int result; 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)) if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
{ {
// path has moduleid and control specification ie. page/moduleid/control/ action = segments[segments.Length - 1];
control = segments[segments.Length - 1];
moduleid = result; moduleid = result;
path = path.Replace(moduleid.ToString() + "/" + control + "/", ""); path = path.Replace(moduleid.ToString() + "/" + action + "/", "");
} }
else 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; moduleid = result;
path = path.Replace(moduleid.ToString() + "/", ""); path = path.Replace(moduleid.ToString() + "/", "");
} }
@ -185,7 +178,7 @@
// remove trailing slash so it can be used as a key for Pages // remove trailing slash so it can be used as a key for Pages
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1); 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(); page = pages.Where(item => item.Path == path).FirstOrDefault();
} }
@ -204,13 +197,13 @@
if (page.Path != path) if (page.Path != path)
{ {
page = pages.Where(item => item.Path == path).FirstOrDefault(); page = pages.Where(item => item.Path == path).FirstOrDefault();
reload = Constants.ReloadPage; reload = Reload.Page;
editmode = page.EditMode; editmode = page.EditMode;
designmode = false; designmode = false;
} }
user = null; user = null;
if (PageState == null || reload >= Constants.ReloadPage) if (PageState == null || reload >= Reload.Page)
{ {
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity.IsAuthenticated) if (authState.User.Identity.IsAuthenticated)
@ -228,6 +221,8 @@
// check if user is authorized to view page // check if user is authorized to view page
if (UserSecurity.IsAuthorized(user, "View", page.Permissions)) if (UserSecurity.IsAuthorized(user, "View", page.Permissions))
{ {
page = await ProcessPage(page, site, user);
pagestate = new PageState(); pagestate = new PageState();
pagestate.ModuleDefinitions = moduledefinitions; pagestate.ModuleDefinitions = moduledefinitions;
pagestate.Themes = themes; pagestate.Themes = themes;
@ -240,17 +235,17 @@
pagestate.Uri = new Uri(_absoluteUri, UriKind.Absolute); pagestate.Uri = new Uri(_absoluteUri, UriKind.Absolute);
pagestate.QueryString = querystring; pagestate.QueryString = querystring;
pagestate.ModuleId = moduleid; 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 = await ModuleService.GetModulesAsync(site.SiteId);
modules = ProcessModules(modules, moduledefinitions, pagestate.Control, page.Panes); modules = ProcessModules(modules, moduledefinitions, page.PageId, pagestate.ModuleId, pagestate.Action, page.Panes, site.DefaultContainerType);
} }
else else
{ {
@ -259,18 +254,22 @@
pagestate.Modules = modules; pagestate.Modules = modules;
pagestate.EditMode = editmode; pagestate.EditMode = editmode;
pagestate.DesignMode = designmode; pagestate.DesignMode = designmode;
pagestate.Reload = Constants.ReloadReset;
OnStateChange?.Invoke(pagestate); OnStateChange?.Invoke(pagestate);
} }
else else
{ {
// user is not authorized to view page // user is not authorized to view page
if (path != "")
{
NavigationManager.NavigateTo("");
}
} }
} }
else else
{ {
// page does not exist // page does not exist
NavigationManager.NavigateTo("");
} }
} }
else else
@ -319,15 +318,43 @@
return querystring; 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; ModuleDefinition moduledefinition;
if (control == "")
{
control = Constants.DefaultControl;
}
Dictionary<string, int> paneindex = new Dictionary<string, int>(); Dictionary<string, int> paneindex = new Dictionary<string, int>();
foreach (Module module in modules) foreach (Module module in modules)
{ {
@ -336,56 +363,80 @@
if (moduledefinition != null) if (moduledefinition != null)
{ {
string typename = moduledefinition.ControlTypeTemplate; 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); else
// get IModuleControl properties
typename = module.ModuleType;
if (control == "Settings")
{ {
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.Pane = Constants.AdminPane;
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);
} }
// 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 (string.IsNullOrEmpty(module.ContainerType))
if (!panes.Contains(module.Pane))
{ {
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) foreach (Module module in modules)
{ {
module.PaneModuleCount = paneindex[module.Pane] + 1; if (module.PageId == pageid)
{
module.PaneModuleCount = paneindex[module.Pane] + 1;
}
} }
return modules; return modules;
} }
@ -414,7 +465,6 @@
// use first alias if Uri does not exist // use first alias if Uri does not exist
alias = aliases.FirstOrDefault(); alias = aliases.FirstOrDefault();
} }
alias.Scheme = uri.Scheme;
return alias; return alias;
} }

View File

@ -1,6 +1,5 @@
@using Oqtane.Shared @namespace Oqtane.Shared
@using Oqtane.Modules @inject IJSRuntime jsRuntime
@namespace Oqtane.Shared
@DynamicComponent @DynamicComponent
@ -21,8 +20,8 @@
} }
else else
{ {
// theme does not exist with type specified // theme 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 Page Theme " + PageState.Page.ThemeType); builder.AddAttribute(1, "Message", "Error Loading Page Theme " + PageState.Page.ThemeType);
builder.CloseComponent(); builder.CloseComponent();
} }

View File

@ -52,6 +52,10 @@ namespace Oqtane.Client
services.AddScoped<IUserRoleService, UserRoleService>(); services.AddScoped<IUserRoleService, UserRoleService>();
services.AddScoped<ISettingService, SettingService>(); services.AddScoped<ISettingService, SettingService>();
services.AddScoped<IFileService, FileService>(); 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 // dynamically register module contexts and repository services
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

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