Merge pull request #1 from oqtane/master

Sync master
This commit is contained in:
jimspillane
2020-04-30 21:07:21 -04:00
committed by GitHub
174 changed files with 4414 additions and 6358 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ Oqtane.Server/appsettings.json
Oqtane.Server/Data/*.mdf Oqtane.Server/Data/*.mdf
Oqtane.Server/Data/*.ldf Oqtane.Server/Data/*.ldf
/Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2019 .NET Foundation Copyright (c) 2018-2020 .NET Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -4,26 +4,8 @@
@inject IFileService FileService @inject IFileService FileService
@inject IFolderService FolderService @inject IFolderService FolderService
@if (_folders != null) <TabStrip>
{ <TabPanel Name="Upload" Heading="Upload Files">
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#Upload" role="tab">
Upload Files
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#Download" role="tab">
Download Files
</a>
</li>
</ul>
<div class="tab-content">
<div id="Upload" class="tab-pane fade show active" role="tabpanel">
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
@ -34,12 +16,15 @@
</td> </td>
</tr> </tr>
</table> </table>
</div> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<div id="Download" class="tab-pane fade" role="tabpanel"> </TabPanel>
<TabPanel Name="Download" Heading="Download Files">
@if (_folders != null)
{
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="url" HelpText="Enter the file url">Url: </Label> <Label For="url" HelpText="Enter the url of the file you wish to download">Url: </Label>
</td> </td>
<td> <td>
<input id="url" class="form-control" @bind="@url" /> <input id="url" class="form-control" @bind="@url" />
@ -47,7 +32,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="folder" HelpText="Select the folder the file is in">Folder: </Label> <Label For="folder" HelpText="Select the folder to save the file in">Folder: </Label>
</td> </td>
<td> <td>
<select id="folder" class="form-control" @bind="@_folderId"> <select id="folder" class="form-control" @bind="@_folderId">
@ -60,14 +45,11 @@
</td> </td>
</tr> </tr>
</table> </table>
<button type="button" class="btn btn-primary" @onclick="Download">Download</button> <button type="button" class="btn btn-success" @onclick="Download">Download</button>
</div>
</div>
</div>
</div>
<br />
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
} }
</TabPanel>
</TabStrip>
@code { @code {
private string url = string.Empty; private string url = string.Empty;

View File

@ -33,7 +33,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="2" align="center"> <td colspan="2" align="center">
<Label For="permissions" HelpText="Select the permissions you want for the file">Permissions: </Label> <Label For="permissions" HelpText="Select the permissions you want for the folder">Permissions: </Label>
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="Browse,View,Edit" Permissions="@_permissions" @ref="_permissionGrid" /> <PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="Browse,View,Edit" Permissions="@_permissions" @ref="_permissionGrid" />
</td> </td>
</tr> </tr>

View File

@ -14,7 +14,7 @@
<text>...</text> <text>...</text>
</Authorizing> </Authorizing>
<Authorized> <Authorized>
You are already logged in <ModuleMessage Message="You Are Already Logged In" Type="MessageType.Info" />
</Authorized> </Authorized>
<NotAuthorized> <NotAuthorized>
<div class="container"> <div class="container">

View File

@ -152,7 +152,7 @@
private string _properties = string.Empty; private string _properties = string.Empty;
private string _server = string.Empty; private string _server = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {

View File

@ -76,7 +76,7 @@ else
private string _rows = "10"; private string _rows = "10";
private List<Log> _logs; private List<Log> _logs;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {

View File

@ -55,7 +55,7 @@
protected override void OnInitialized() protected override void OnInitialized()
{ {
AddModuleMessage("Please Note That Once You Select The Create Module Button The Application Must Restart In Order To Complete The Process.", MessageType.Info); AddModuleMessage("Please Note That Once You Select The Create Module Button The Application Must Restart In Order To Complete The Process. If You Create An External Module You Will Need To Compile The Source Code In Order To Make It Functional.", MessageType.Info);
} }
private async Task CreateModule() private async Task CreateModule()

View File

@ -62,7 +62,8 @@ else
- Repository\I[Module]Repository.cs - interface for defining repository methods<br /> - Repository\I[Module]Repository.cs - interface for defining repository methods<br />
- Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br /> - Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br />
- Repository\[Module]Context.cs - provides a DB Context for data access<br /> - Repository\[Module]Context.cs - provides a DB Context for data access<br />
- Scripts\01.00.00.sql - database schema definition<br /><br /> - Scripts\[Owner].[Module].1.0.0.sql - database schema definition script<br /><br />
- Scripts\[Owner].[Module].Uninstall.sql - database uninstall script<br /><br />
[RootPath]Shared\<br /> [RootPath]Shared\<br />
- [Owner].[Module]s.Module.Shared.csproj - shared project<br /> - [Owner].[Module]s.Module.Shared.csproj - shared project<br />
- Models\[Module].cs - model definition<br /><br /> - Models\[Module].cs - model definition<br /><br />

View File

@ -11,7 +11,8 @@ namespace [Owner].[Module]s.Modules
Description = "[Module]", Description = "[Module]",
Version = "1.0.0", Version = "1.0.0",
Dependencies = "[Owner].[Module]s.Module.Shared", Dependencies = "[Owner].[Module]s.Module.Shared",
ServerAssemblyName = "[ServerAssemblyName]" ServerManagerType = "[ServerManagerType]",
ReleaseVersions = "1.0.0"
}; };
} }
} }

View File

@ -12,13 +12,11 @@ namespace [Owner].[Module]s.Services
{ {
public class [Module]Service : ServiceBase, I[Module]Service, IService public class [Module]Service : ServiceBase, I[Module]Service, IService
{ {
private readonly HttpClient _http;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
private readonly SiteState _siteState; private readonly SiteState _siteState;
public [Module]Service(HttpClient http, SiteState siteState, NavigationManager navigationManager) public [Module]Service(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -30,28 +28,28 @@ namespace [Owner].[Module]s.Services
public async Task<List<[Module]>> Get[Module]sAsync(int ModuleId) public async Task<List<[Module]>> Get[Module]sAsync(int ModuleId)
{ {
List<[Module]> [Module]s = await _http.GetJsonAsync<List<[Module]>>(Apiurl + "?moduleid=" + ModuleId.ToString()); List<[Module]> [Module]s = await GetJsonAsync<List<[Module]>>(Apiurl + "?moduleid=" + ModuleId.ToString());
return [Module]s.OrderBy(item => item.Name).ToList(); return [Module]s.OrderBy(item => item.Name).ToList();
} }
public async Task<[Module]> Get[Module]Async(int [Module]Id) public async Task<[Module]> Get[Module]Async(int [Module]Id)
{ {
return await _http.GetJsonAsync<[Module]>(Apiurl + "/" + [Module]Id.ToString()); return await GetJsonAsync<[Module]>(Apiurl + "/" + [Module]Id.ToString());
} }
public async Task<[Module]> Add[Module]Async([Module] [Module]) public async Task<[Module]> Add[Module]Async([Module] [Module])
{ {
return await _http.PostJsonAsync<[Module]>(Apiurl + "?entityid=" + [Module].ModuleId, [Module]); return await PostJsonAsync<[Module]>(Apiurl + "?entityid=" + [Module].ModuleId, [Module]);
} }
public async Task<[Module]> Update[Module]Async([Module] [Module]) public async Task<[Module]> Update[Module]Async([Module] [Module])
{ {
return await _http.PutJsonAsync<[Module]>(Apiurl + "/" + [Module].[Module]Id + "?entityid=" + [Module].ModuleId, [Module]); return await PutJsonAsync<[Module]>(Apiurl + "/" + [Module].[Module]Id + "?entityid=" + [Module].ModuleId, [Module]);
} }
public async Task Delete[Module]Async(int [Module]Id) public async Task Delete[Module]Async(int [Module]Id)
{ {
await _http.DeleteAsync(Apiurl + "/" + [Module]Id.ToString()); await DeleteAsync(Apiurl + "/" + [Module]Id.ToString());
} }
} }
} }

View File

@ -12,9 +12,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview3.20168.3" /> <!-- <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview5.20216.8" />-->
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview3.20168.3" PrivateAssets="all" /> <!-- <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview5.20216.8" PrivateAssets="all" />-->
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.2.0-preview3.20168.3" /> <PackageReference Include="System.Net.Http.Json" Version="3.2.0-preview5.20210.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -3,18 +3,32 @@ using System.Linq;
using System.Text.Json; using System.Text.Json;
using Oqtane.Modules; using Oqtane.Modules;
using Oqtane.Models; using Oqtane.Models;
using Oqtane.Infrastructure;
using Oqtane.Repository;
using [Owner].[Module]s.Models; using [Owner].[Module]s.Models;
using [Owner].[Module]s.Repository; using [Owner].[Module]s.Repository;
namespace [Owner].[Module]s.Modules namespace [Owner].[Module]s.Manager
{ {
public class [Module]Manager : IPortable public class [Module]Manager : IInstallable, IPortable
{ {
private I[Module]Repository _[Module]s; private I[Module]Repository _[Module]s;
private ISqlRepository _sql;
public [Module]Manager(I[Module]Repository [Module]s) public [Module]Manager(I[Module]Repository [Module]s, ISqlRepository sql)
{ {
_[Module]s = [Module]s; _[Module]s = [Module]s;
_sql = sql;
}
public bool Install(Tenant tenant, string version)
{
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]." + version + ".sql");
}
public bool Uninstall(Tenant tenant)
{
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module].Uninstall.sql");
} }
public string ExportModule(Module module) public string ExportModule(Module module)

View File

@ -13,17 +13,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="Scripts\01.00.00.sql" /> <EmbeddedResource Include="Scripts\[Owner].[Module].1.0.0.sql" />
<None Remove="Scripts\Uninstall.sql" /> <EmbeddedResource Include="Scripts\[Owner].[Module].Uninstall.sql" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Scripts\01.00.00.sql" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0-preview5.20216.8" />
<EmbeddedResource Include="Scripts\Uninstall.sql" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" />

View File

@ -54,7 +54,8 @@ else
- Repository\I[Module]Repository.cs - interface for defining repository methods<br /> - Repository\I[Module]Repository.cs - interface for defining repository methods<br />
- Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br /> - Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br />
- Repository\[Module]Context.cs - provides a DB Context for data access<br /> - Repository\[Module]Context.cs - provides a DB Context for data access<br />
- Scripts\01.00.00.sql - database schema definition<br /><br /> - Scripts\[Owner].[Module].1.0.0.sql - database schema definition script<br /><br />
- Scripts\[Owner].[Module].Uninstall.sql - database uninstall script<br /><br />
[RootPath]Oqtane.Shared\Modules\[Module]\<br /> [RootPath]Oqtane.Shared\Modules\[Module]\<br />
- Models\[Module].cs - model definition<br /><br /> - Models\[Module].cs - model definition<br /><br />

View File

@ -11,7 +11,8 @@ namespace [Owner].[Module]s.Modules
Description = "[Module]", Description = "[Module]",
Version = "1.0.0", Version = "1.0.0",
Dependencies = "[Owner].[Module]s.Module.Shared", Dependencies = "[Owner].[Module]s.Module.Shared",
ServerAssemblyName = "[ServerAssemblyName]" ServerManagerType = "[ServerManagerType]",
ReleaseVersions = "1.0.0"
}; };
} }
} }

View File

@ -12,13 +12,11 @@ namespace [Owner].[Module]s.Services
{ {
public class [Module]Service : ServiceBase, I[Module]Service, IService public class [Module]Service : ServiceBase, I[Module]Service, IService
{ {
private readonly HttpClient _http;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
private readonly SiteState _siteState; private readonly SiteState _siteState;
public [Module]Service(HttpClient http, SiteState siteState, NavigationManager navigationManager) public [Module]Service(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -30,28 +28,28 @@ namespace [Owner].[Module]s.Services
public async Task<List<[Module]>> Get[Module]sAsync(int ModuleId) public async Task<List<[Module]>> Get[Module]sAsync(int ModuleId)
{ {
List<[Module]> [Module]s = await _http.GetJsonAsync<List<[Module]>>(Apiurl + "?moduleid=" + ModuleId.ToString()); List<[Module]> [Module]s = await GetJsonAsync<List<[Module]>>(Apiurl + "?moduleid=" + ModuleId.ToString());
return [Module]s.OrderBy(item => item.Name).ToList(); return [Module]s.OrderBy(item => item.Name).ToList();
} }
public async Task<[Module]> Get[Module]Async(int [Module]Id) public async Task<[Module]> Get[Module]Async(int [Module]Id)
{ {
return await _http.GetJsonAsync<[Module]>(Apiurl + "/" + [Module]Id.ToString()); return await GetJsonAsync<[Module]>(Apiurl + "/" + [Module]Id.ToString());
} }
public async Task<[Module]> Add[Module]Async([Module] [Module]) public async Task<[Module]> Add[Module]Async([Module] [Module])
{ {
return await _http.PostJsonAsync<[Module]>(Apiurl + "?entityid=" + [Module].ModuleId, [Module]); return await PostJsonAsync<[Module]>(Apiurl + "?entityid=" + [Module].ModuleId, [Module]);
} }
public async Task<[Module]> Update[Module]Async([Module] [Module]) public async Task<[Module]> Update[Module]Async([Module] [Module])
{ {
return await _http.PutJsonAsync<[Module]>(Apiurl + "/" + [Module].[Module]Id + "?entityid=" + [Module].ModuleId, [Module]); return await PutJsonAsync<[Module]>(Apiurl + "/" + [Module].[Module]Id + "?entityid=" + [Module].ModuleId, [Module]);
} }
public async Task Delete[Module]Async(int [Module]Id) public async Task Delete[Module]Async(int [Module]Id)
{ {
await _http.DeleteAsync(Apiurl + "/" + [Module]Id.ToString()); await DeleteAsync(Apiurl + "/" + [Module]Id.ToString());
} }
} }
} }

View File

@ -3,18 +3,32 @@ using System.Linq;
using System.Text.Json; using System.Text.Json;
using Oqtane.Modules; using Oqtane.Modules;
using Oqtane.Models; using Oqtane.Models;
using Oqtane.Infrastructure;
using Oqtane.Repository;
using [Owner].[Module]s.Models; using [Owner].[Module]s.Models;
using [Owner].[Module]s.Repository; using [Owner].[Module]s.Repository;
namespace [Owner].[Module]s.Modules namespace [Owner].[Module]s.Manager
{ {
public class [Module]Manager : IPortable public class [Module]Manager : IInstallable, IPortable
{ {
private I[Module]Repository _[Module]s; private I[Module]Repository _[Module]s;
private ISqlRepository _sql;
public [Module]Manager(I[Module]Repository [Module]s) public [Module]Manager(I[Module]Repository [Module]s, ISqlRepository sql)
{ {
_[Module]s = [Module]s; _[Module]s = [Module]s;
_sql = sql;
}
public bool Install(Tenant tenant, string version)
{
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]." + version + ".sql");
}
public bool Uninstall(Tenant tenant)
{
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module].Uninstall.sql");
} }
public string ExportModule(Module module) public string ExportModule(Module module)

View File

@ -5,22 +5,13 @@
@inject IModuleDefinitionService ModuleDefinitionService @inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService @inject IPackageService PackageService
<table class="table table-borderless">
<tr>
<td>
<Label For="module" HelpText="Upload a module from your system">Module: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Modules" />
</td>
</tr>
</table>
@if (_packages != null) @if (_packages != null)
{ {
<hr class="app-rule" /> <TabStrip>
<div class="mx-auto text-center"><h2>Available Modules</h2></div> @if (_packages.Count > 0)
{
<TabPanel Name="Download">
<ModuleMessage Type="MessageType.Info" Message="Download one or more modules from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<Pager Items="@_packages"> <Pager Items="@_packages">
<Header> <Header>
<th>Name</th> <th>Name</th>
@ -31,15 +22,29 @@
<td>@context.Name</td> <td>@context.Name</td>
<td>@context.Version</td> <td>@context.Version</td>
<td> <td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadModule(context.PackageId, context.Version))>Download Module</button> <button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadModule(context.PackageId, context.Version))>Download</button>
</td> </td>
</Row> </Row>
</Pager> </Pager>
</TabPanel>
} }
<TabPanel Name="Upload">
<table class="table table-borderless">
<tr>
<td>
<Label HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation.">Module: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Modules" UploadMultiple="True" />
</td>
</tr>
</table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="InstallModules">Install</button> <button type="button" class="btn btn-success" @onclick="InstallModules">Install</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
@code { @code {
private List<Package> _packages; private List<Package> _packages;
@ -81,18 +86,18 @@
} }
} }
private async Task DownloadModule(string moduledefinitionname, string version) private async Task DownloadModule(string packageid, string version)
{ {
try try
{ {
await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules"); await PackageService.DownloadPackageAsync(packageid, version, "Modules");
await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", moduledefinitionname, version); await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", packageid, version);
AddModuleMessage("Module Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success); AddModuleMessage("Modules Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
StateHasChanged(); StateHasChanged();
} }
catch (Exception ex) catch (Exception ex)
{ {
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", moduledefinitionname, version); await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", packageid, version);
AddModuleMessage("Error Downloading Module", MessageType.Error); AddModuleMessage("Error Downloading Module", MessageType.Error);
} }
} }

View File

@ -3,6 +3,8 @@
@inject IModuleDefinitionService ModuleDefinitionService @inject IModuleDefinitionService ModuleDefinitionService
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
<TabStrip>
<TabPanel Name="Definition">
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
@ -13,21 +15,101 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2" align="center"> <td>
<Label For="permissions" HelpText="Select who you want to access the module">Permissions: </Label> <Label For="description" HelpText="The description of the module">Description: </Label>
</td>
<td>
<textarea id="description" class="form-control" @bind="@_description" rows="2"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="categories" HelpText="Comma delimited list of module categories">Categories: </Label>
</td>
<td>
<input id="categories" class="form-control" @bind="@_categories" />
</td>
</tr>
</table>
<Section Name="Information">
<table class="table table-borderless">
<tr>
<td>
<Label For="moduledefinitionname" HelpText="The internal name of the module">Internal Name: </Label>
</td>
<td>
<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
</td>
</tr>
<tr>
<td>
<Label For="version" HelpText="The version of the module">Version: </Label>
</td>
<td>
<input id="version" class="form-control" @bind="@_version" disabled />
</td>
</tr>
<tr>
<td>
<Label For="owner" HelpText="The owner or creator of the module">Owner: </Label>
</td>
<td>
<input id="owner" class="form-control" @bind="@_owner" disabled />
</td>
</tr>
<tr>
<td>
<Label For="url" HelpText="The reference url of the module">Reference Url: </Label>
</td>
<td>
<input id="url" class="form-control" @bind="@_url" disabled />
</td>
</tr>
<tr>
<td>
<Label For="contact" HelpText="The contact for the module">Contact: </Label>
</td>
<td>
<input id="contact" class="form-control" @bind="@_contact" disabled />
</td>
</tr>
<tr>
<td>
<Label For="license" HelpText="The license of the module">License: </Label>
</td>
<td>
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
</td>
</tr>
</table>
</Section>
</TabPanel>
<TabPanel Name="Permissions">
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" Permissions="@_permissions" @ref="_permissionGrid" /> <PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" Permissions="@_permissions" @ref="_permissionGrid" />
</td> </td>
</tr> </tr>
</table> </table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">Save</button> <button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">Save</button>
<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"></AuditInfo>
@code { @code {
private int _moduleDefinitionId; private int _moduleDefinitionId;
private string _name; private string _name;
private string _version;
private string _categories;
private string _moduledefinitionname = "";
private string _description = "";
private string _owner = "";
private string _url = "";
private string _contact = "";
private string _license = "";
private string _permissions; private string _permissions;
private string _createdby; private string _createdby;
private DateTime _createdon; private DateTime _createdon;
@ -49,6 +131,14 @@
if (moduleDefinition != null) if (moduleDefinition != null)
{ {
_name = moduleDefinition.Name; _name = moduleDefinition.Name;
_version = moduleDefinition.Version;
_categories = moduleDefinition.Categories;
_moduledefinitionname = moduleDefinition.ModuleDefinitionName;
_description = moduleDefinition.Description;
_owner = moduleDefinition.Owner;
_url = moduleDefinition.Url;
_contact = moduleDefinition.Contact;
_license = moduleDefinition.License;
_permissions = moduleDefinition.Permissions; _permissions = moduleDefinition.Permissions;
_createdby = moduleDefinition.CreatedBy; _createdby = moduleDefinition.CreatedBy;
_createdon = moduleDefinition.CreatedOn; _createdon = moduleDefinition.CreatedOn;
@ -68,6 +158,18 @@
try try
{ {
var moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId); var moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
if (moduledefinition.Name != _name)
{
moduledefinition.Name = _name;
}
if (moduledefinition.Description != _description)
{
moduledefinition.Description = _description;
}
if (moduledefinition.Categories != _categories)
{
moduledefinition.Categories = _categories;
}
moduledefinition.Permissions = _permissionGrid.GetPermissions(); moduledefinition.Permissions = _permissionGrid.GetPermissions();
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition); await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition); await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);

View File

@ -5,32 +5,11 @@
@inject IModuleService ModuleService @inject IModuleService ModuleService
@inject IPageModuleService PageModuleService @inject IPageModuleService PageModuleService
<TabStrip>
<TabPanel Name="Settings" Heading="Module Settings">
@if (_containers != null) @if (_containers != null)
{ {
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#Settings" role="tab">
Module Settings
</a>
</li>
@if (_settingsModuleType != null)
{
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#ModuleSettings" role="tab">
@_settingstitle
</a>
</li>
}
</ul>
<div class="tab-content">
<div id="Settings" class="tab-pane fade show active" role="tabpanel">
<br />
<table class="table table-borderless"> <table class="table table-borderless">
<tbody>
<tr> <tr>
<td> <td>
<Label For="title" HelpText="Enter the title of the module">Title: </Label> <Label For="title" HelpText="Enter the title of the module">Title: </Label>
@ -53,12 +32,6 @@
</select> </select>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2" align="center">
<Label For="permissions" HelpText="Who do you want to be able to access the module">Permissions: </Label>
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
<tr> <tr>
<td> <td>
<Label For="page" HelpText="The page that the module is on">Page: </Label> <Label For="page" HelpText="The page that the module is on">Page: </Label>
@ -67,28 +40,38 @@
<select id="page" class="form-control" @bind="@_pageId"> <select id="page" class="form-control" @bind="@_pageId">
@foreach (Page p in PageState.Pages) @foreach (Page p in PageState.Pages)
{ {
<option value="@p.PageId">@p.Name</option> if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
}
} }
</select> </select>
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> }
</TabPanel>
<TabPanel Name="Permissions">
@if (_containers != null)
{
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
}
</TabPanel>
@if (_settingsModuleType != null) @if (_settingsModuleType != null)
{ {
<div id="ModuleSettings" class="tab-pane fade" role="tabpanel"> <TabPanel Name="ModuleSettings" Heading="@_settingstitle">
<br />
@DynamicComponent @DynamicComponent
</div> </TabPanel>
} }
</div> </TabStrip>
</div>
</div>
<button type="button" class="btn btn-success" @onclick="SaveModule">Save</button> <button type="button" class="btn btn-success" @onclick="SaveModule">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
@code { @code {
private Dictionary<string, string> _containers; private Dictionary<string, string> _containers;

View File

@ -4,6 +4,8 @@
@inject IPageService PageService @inject IPageService PageService
@inject IThemeService ThemeService @inject IThemeService ThemeService
<TabStrip>
<TabPanel Name="Settings">
@if (_themeList != null) @if (_themeList != null)
{ {
<table class="table table-borderless"> <table class="table table-borderless">
@ -17,23 +19,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Title" HelpText="Enter the page title">Title: </Label> <Label For="Parent" HelpText="Select the parent for the page in the site hierarchy">Parent: </Label>
</td>
<td>
<input id="Title" class="form-control" @bind="@_title" />
</td>
</tr>
<tr>
<td>
<Label For="Path" HelpText="Enter the path for the page">Path: </Label>
</td>
<td>
<input id="Path" class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<Label For="Parent" HelpText="Select the parent for the page">Parent: </Label>
</td> </td>
<td> <td>
<select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))"> <select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))">
@ -47,7 +33,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Insert" HelpText="Select the insert for the page">Insert: </Label> <Label For="Insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages">Insert: </Label>
</td> </td>
<td> <td>
<select id="Insert" class="form-control" @bind="@_insert"> <select id="Insert" class="form-control" @bind="@_insert">
@ -61,7 +47,7 @@
</select> </select>
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">")) @if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
{ {
<select id="Insert" class="form-control" @bind="@_childid"> <select class="form-control" @bind="@_childid">
<option value="-1">&lt;Select Page&gt;</option> <option value="-1">&lt;Select Page&gt;</option>
@foreach (Page page in _children) @foreach (Page page in _children)
{ {
@ -73,7 +59,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Navigation" HelpText="Select whether the page has navigation bar">Navigation? </Label> <Label For="Navigation" HelpText="Select whether the page is part of the site navigation or hidden">Navigation? </Label>
</td> </td>
<td> <td>
<select id="Navigation" class="form-control" @bind="@_isnavigation"> <select id="Navigation" class="form-control" @bind="@_isnavigation">
@ -84,26 +70,84 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Url" HelpText="Enter the url for the page">Url: </Label> <Label For="Path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used.">Url Path: </Label>
</td>
<td>
<input id="Path" class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<Label For="Url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it">Redirect: </Label>
</td> </td>
<td> <td>
<input id="Url" class="form-control" @bind="@_url" /> <input id="Url" class="form-control" @bind="@_url" />
</td> </td>
</tr> </tr>
</table>
<Section Name="Appearance">
<table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="Personalizable" HelpText="Do you want the page to be personalized by users">Personalizable? </Label> <Label For="Title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used.">Title: </Label>
</td> </td>
<td> <td>
<select id="Personalizable" class="form-control" @bind="@_ispersonalizable"> <input id="Title" class="form-control" @bind="@_title" />
<option value="True">Yes</option> </td>
<option value="False">No</option> </tr>
<tr>
<td>
<Label For="Theme" HelpText="Select the theme for this page">Theme: </Label>
</td>
<td>
<select id="Theme" 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> </select>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Default-Mode" HelpText="Select the default mode you want for the page">Default Mode? </Label> <Label For="Layout" HelpText="Select a layout for the page (if the selected theme supports it)">Layout: </Label>
</td>
<td>
<select id="Layout" class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
{
if (panelayout.Key == _layouttype)
{
<option value="@panelayout.Key" selected>@panelayout.Value</option>
}
else
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
</td>
<td>
<input id="Icon" class="form-control" @bind="@_icon" />
</td>
</tr>
<tr>
<td>
<Label For="Default-Mode" HelpText="Select the default administration mode you want for this page">Default Mode? </Label>
</td> </td>
<td> <td>
<select id="Default-Mode" class="form-control" @bind="@_mode"> <select id="Default-Mode" class="form-control" @bind="@_mode">
@ -114,54 +158,35 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Theme" HelpText="Select the theme you want for the page">Theme: </Label> <Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content">Personalizable? </Label>
</td> </td>
<td> <td>
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))"> <select id="Personalizable" class="form-control" @bind="@_ispersonalizable">
<option value="">&lt;Select Theme&gt;</option> <option value="True">Yes</option>
@foreach (KeyValuePair<string, string> item in _themes) <option value="False">No</option>
{
<option value="@item.Key">@item.Value</option>
}
</select> </select>
</td> </td>
</tr> </tr>
<tr> </table>
<td> </Section>
<Label For="Layout" HelpText="Select the layout for the page">Layout: </Label>
</td>
<td>
<select id="Layout" 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> </TabPanel>
</td> <TabPanel Name="Permissions">
</tr> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="Icon" HelpText="Enter the icon for the page">Icon: </Label>
</td>
<td>
<input id="Icon" class="form-control" @bind="@_icon" />
</td>
</tr>
<tr>
<td colspan="2" align="center">
<Label For="Permissions" HelpText="Select the permissions you want for the page">Permissions: </Label>
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" /> <PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
</td> </td>
</tr> </tr>
</table> </table>
</TabPanel>
</TabStrip>
<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 {
private Dictionary<string, string> _themes = new Dictionary<string, string>(); private Dictionary<string, string> _themes;
private Dictionary<string, string> _panelayouts = new Dictionary<string, string>(); private Dictionary<string, string> _panelayouts;
private List<Theme> _themeList; private List<Theme> _themeList;
private List<Page> _pageList; private List<Page> _pageList;
private string _name; private string _name;
@ -191,12 +216,12 @@
_pageList = PageState.Pages; _pageList = PageState.Pages;
_children = PageState.Pages.Where(item => item.ParentId == null).ToList(); _children = PageState.Pages.Where(item => item.ParentId == null).ToList();
_themes = ThemeService.GetThemeTypes(_themeList);
_themetype = PageState.Site.DefaultThemeType; _themetype = PageState.Site.DefaultThemeType;
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouttype = PageState.Site.DefaultLayoutType; _layouttype = PageState.Site.DefaultLayoutType;
_themes = ThemeService.GetThemeTypes(_themeList);
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_permissions = string.Empty; _permissions = string.Empty;
} }
catch (Exception ex) catch (Exception ex)
@ -211,13 +236,26 @@
try try
{ {
_parentid = (string)e.Value; _parentid = (string)e.Value;
_children = new List<Page>();
if (_parentid == "-1") if (_parentid == "-1")
{ {
_children = PageState.Pages.Where(item => item.ParentId == null).ToList(); foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
} }
else else
{ {
_children = PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)).ToList(); foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
} }
StateHasChanged(); StateHasChanged();
} }
@ -241,7 +279,6 @@
{ {
_panelayouts = new Dictionary<string, string>(); _panelayouts = new Dictionary<string, string>();
} }
StateHasChanged(); StateHasChanged();
} }
catch (Exception ex) catch (Exception ex)

View File

@ -4,6 +4,8 @@
@inject IPageService PageService @inject IPageService PageService
@inject IThemeService ThemeService @inject IThemeService ThemeService
<TabStrip>
<TabPanel Name="Settings">
@if (_themeList != null) @if (_themeList != null)
{ {
<table class="table table-borderless"> <table class="table table-borderless">
@ -12,28 +14,12 @@
<Label For="Name" HelpText="Enter the page name">Name: </Label> <Label For="Name" HelpText="Enter the page name">Name: </Label>
</td> </td>
<td> <td>
<input id="name" class="form-control" @bind="@_name" /> <input id="Name" class="form-control" @bind="@_name" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Title" HelpText="Enter the page title">Title: </Label> <Label For="Parent" HelpText="Select the parent for the page in the site hierarchy">Parent: </Label>
</td>
<td>
<input id="Title" class="form-control" @bind="@_title" />
</td>
</tr>
<tr>
<td>
<Label For="Path" HelpText="Enter the path for the page">Path: </Label>
</td>
<td>
<input id="Path" class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<Label For="Parent" HelpText="Select the parent for the page">Parent: </Label>
</td> </td>
<td> <td>
<select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))"> <select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))">
@ -54,7 +40,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Move" HelpText="Select where you wan to move the page">Move: </Label> <Label For="Move" HelpText="Select the location where you would like the page to be moved in relation to other pages">Move: </Label>
</td> </td>
<td> <td>
<select id="Move" class="form-control" @bind="@_insert"> <select id="Move" class="form-control" @bind="@_insert">
@ -72,7 +58,7 @@
</select> </select>
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">")) @if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
{ {
<select id="Move" class="form-control" @bind="@_childid"> <select class="form-control" @bind="@_childid">
<option value="-1">&lt;Select Page&gt;</option> <option value="-1">&lt;Select Page&gt;</option>
@foreach (Page page in _children) @foreach (Page page in _children)
{ {
@ -84,15 +70,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label for="Url" HelpText="Enter the url for the page">Url: </Label> <Label For="Navigation" HelpText="Select whether the page is part of the site navigation or hidden">Navigation? </Label>
</td>
<td>
<input id="Url" class="form-control" @bind="@_url" />
</td>
</tr>
<tr>
<td>
<Label For="Navigation" HelpText="Select whether the page has navigation bar">Navigation? </Label>
</td> </td>
<td> <td>
<select id="Navigation" class="form-control" @bind="@_isnavigation"> <select id="Navigation" class="form-control" @bind="@_isnavigation">
@ -103,29 +81,34 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Personalizable" HelpText="Do you want the page to be personalized by users">Personalizable? </Label> <Label For="Path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used.">Url Path: </Label>
</td> </td>
<td> <td>
<select id="Personalizable" class="form-control" @bind="@_ispersonalizable"> <input id="Path" class="form-control" @bind="@_path" />
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Default-Mode" HelpText="Select the default mode you want for the page">Default Mode? </Label> <Label For="Url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it">Redirect: </Label>
</td> </td>
<td> <td>
<select id="Default-Mode" class="form-control" @bind="@_mode"> <input id="Url" class="form-control" @bind="@_url" />
<option value="view">View Mode</option> </td>
<option value="edit">Edit Mode</option> </tr>
</select> </table>
<Section Name="Appearance">
<table class="table table-borderless">
<tr>
<td>
<Label For="Title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used.">Title: </Label>
</td>
<td>
<input id="Title" class="form-control" @bind="@_title" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Theme" HelpText="Select the theme you want for the page">Theme: </Label> <Label For="Theme" HelpText="Select the theme for this page">Theme: </Label>
</td> </td>
<td> <td>
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))"> <select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
@ -146,43 +129,77 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Layout" HelpText="Select the layout for the page">Layout: </Label> <Label For="Layout" HelpText="Select a layout for the page (if the selected theme supports it)">Layout: </Label>
</td> </td>
<td> <td>
<select id="Layout" class="form-control" @bind="@_layouttype"> <select id="Layout" class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option> <option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts) @foreach (KeyValuePair<string, string> panelayout in _panelayouts)
{
if (panelayout.Key == _layouttype)
{
<option value="@panelayout.Key" selected>@panelayout.Value</option>
}
else
{ {
<option value="@panelayout.Key">@panelayout.Value</option> <option value="@panelayout.Key">@panelayout.Value</option>
} }
}
</select> </select>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="Icon" HelpText="Enter the icon for the page">Icon: </Label> <Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
</td> </td>
<td> <td>
<input id="Icon" class="form-control" @bind="@_icon" /> <input id="Icon" class="form-control" @bind="@_icon" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2" align="center"> <td>
<Label For="Permissions" HelpText="Select the permissions you want for the page">Permissions: </Label> <Label For="Default-Mode" HelpText="Select the default administration mode you want for this page">Default Mode? </Label>
</td>
<td>
<select id="Default-Mode" class="form-control" @bind="@_mode">
<option value="view">View Mode</option>
<option value="edit">Edit Mode</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content">Personalizable? </Label>
</td>
<td>
<select id="Personalizable" class="form-control" @bind="@_ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
</Section>
<br /><br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
}
</TabPanel>
<TabPanel Name="Permissions">
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" /> <PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
</td> </td>
</tr> </tr>
</table> </table>
</TabPanel>
</TabStrip>
<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>
<br />
<br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
}
@code { @code {
private Dictionary<string, string> _themes = new Dictionary<string, string>(); private Dictionary<string, string> _themes;
private Dictionary<string, string> _panelayouts = new Dictionary<string, string>(); private Dictionary<string, string> _panelayouts;
private List<Theme> _themeList; private List<Theme> _themeList;
private List<Page> _pageList; private List<Page> _pageList;
private int _pageId; private int _pageId;
@ -277,13 +294,26 @@
try try
{ {
_parentid = (string)e.Value; _parentid = (string)e.Value;
_children = new List<Page>();
if (_parentid == "-1") if (_parentid == "-1")
{ {
_children = PageState.Pages.Where(item => item.ParentId == null).ToList(); foreach(Page p in PageState.Pages.Where(item => item.ParentId == null))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
} }
else else
{ {
_children = PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)).ToList(); foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
} }
if (_parentid == _currentparentid) if (_parentid == _currentparentid)
{ {

View File

@ -154,7 +154,13 @@
profile.DefaultValue = _defaultvalue; profile.DefaultValue = _defaultvalue;
profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired)); profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired));
profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate)); profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate));
if (_profileid != -1)
{
profile = await ProfileService.UpdateProfileAsync(profile); profile = await ProfileService.UpdateProfileAsync(profile);
}else
{
profile = await ProfileService.AddProfileAsync(profile);
}
await logger.LogInformation("Profile Saved {Profile}", profile); await logger.LogInformation("Profile Saved {Profile}", profile);
NavigationManager.NavigateTo(NavigateUrl()); NavigationManager.NavigateTo(NavigateUrl());

View File

@ -3,10 +3,17 @@
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IUserService UserService @inject IUserService UserService
@if (_message != string.Empty) @if (PageState.Site.AllowRegistration)
{ {
<ModuleMessage Message="@_message" Type="MessageType.Info" /> <AuthorizeView>
} <Authorizing>
<text>...</text>
</Authorizing>
<Authorized>
<ModuleMessage Message="You Are Already Registered" Type="MessageType.Info" />
</Authorized>
<NotAuthorized>
<ModuleMessage Message="Please Note That Registration Requires A Valid Email Address In Order To Verify Your Identity" Type="MessageType.Info" />
<div class="container"> <div class="container">
<div class="form-group"> <div class="form-group">
@ -32,9 +39,15 @@
<button type="button" class="btn btn-primary" @onclick="Register">Register</button> <button type="button" class="btn btn-primary" @onclick="Register">Register</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button> <button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
</div> </div>
</NotAuthorized>
</AuthorizeView>
}
else
{
<ModuleMessage Message="Registration is Disabled For This Site" Type="MessageType.Info" />
}
@code { @code {
private string _message = "Please Note That Registration Requires A Valid Email Address In Order To Verify Your Identity";
private string _username = string.Empty; private string _username = string.Empty;
private string _password = string.Empty; private string _password = string.Empty;
private string _confirm = string.Empty; private string _confirm = string.Empty;
@ -47,7 +60,6 @@
{ {
try try
{ {
_message = string.Empty;
bool _isEmailValid = Utilities.IsValidEmail(_email); bool _isEmailValid = Utilities.IsValidEmail(_email);
if (_username != "" && _password != "" && _confirm != "" && _isEmailValid) if (_username != "" && _password != "" && _confirm != "" && _isEmailValid)

View File

@ -12,6 +12,7 @@ else
<Pager Items="@_roles"> <Pager Items="@_roles">
<Header> <Header>
<th>&nbsp;</th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>Name</th> <th>Name</th>
@ -19,6 +20,7 @@ else
<Row> <Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Disabled="@(context.IsSystem)" /></td> <td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Disabled="@(context.IsSystem)" /></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))" Disabled="@(context.IsSystem)" /></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))" Disabled="@(context.IsSystem)" /></td>
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" /></td>
<td>@context.Name</td> <td>@context.Name</td>
</Row> </Row>
</Pager> </Pager>

View File

@ -0,0 +1,201 @@
@namespace Oqtane.Modules.Admin.Roles
@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="role" HelpText="The role you are assigning users to">Role: </Label>
</td>
<td>
<input id="role" class="form-control" @bind="@name" disabled />
</td>
</tr>
<tr>
<td>
<Label For="user" HelpText="Select a user">User: </Label>
</td>
<td>
<select id="user" class="form-control" @bind="@userid">
<option value="-1">&lt;Select User&gt;</option>
@foreach (UserRole userrole in users)
{
<option value="@(userrole.UserId)">@userrole.User.DisplayName</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="effectiveDate" HelpText="The date that this role assignment is active">Effective Date: </Label>
</td>
<td>
<input id="effectiveDate" class="form-control" @bind="@effectivedate" />
</td>
</tr>
<tr>
<td>
<Label For="expiryDate" HelpText="The date that this role assignment expires">Expiry Date: </Label>
</td>
<td>
<input id="expiryDate" 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>Users</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.User.DisplayName</td>
<td>
<button type="button" class="btn btn-danger" @onclick=@(async () => await DeleteUserRole(context.UserRoleId))>Delete</button>
</td>
</Row>
</Pager>
</p>
}
@code {
private int roleid;
private string name = string.Empty;
private List<UserRole> users;
private int userid = -1;
private string effectivedate = string.Empty;
private string expirydate = string.Empty;
private List<UserRole> userroles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
try
{
roleid = Int32.Parse(PageState.QueryString["id"]);
Role role = await RoleService.GetRoleAsync(roleid);
name = role.Name;
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
users = users.Where(item => item.Role.Name == Constants.RegisteredRole).ToList();
await GetUserRoles();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Users {Error}", ex.Message);
AddModuleMessage("Error Loading Users", MessageType.Error);
}
}
private async Task GetUserRoles()
{
try
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.RoleId == roleid).ToList();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading User Roles {RoleId} {Error}", roleid, ex.Message);
AddModuleMessage("Error Loading User Roles", MessageType.Error);
}
}
private async Task SaveUserRole()
{
try
{
if (userid != -1)
{
var 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 User", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving User Roles {RoleId} {Error}", roleid, 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

@ -7,6 +7,7 @@
@inject IThemeService ThemeService @inject IThemeService ThemeService
@inject ISiteTemplateService SiteTemplateService @inject ISiteTemplateService SiteTemplateService
@inject IUserService UserService @inject IUserService UserService
@inject IInstallationService InstallationService
@if (_tenants == null) @if (_tenants == null)
{ {
@ -17,21 +18,7 @@ else
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="tenant" HelpText="Select the tenant for the site">Tenant: </Label> <Label For="name" HelpText="Enter the name of the site">Site Name: </Label>
</td>
<td>
<select id="tenant" 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" HelpText="Enter the name of the site">Name: </Label>
</td> </td>
<td> <td>
<input id="name" class="form-control" @bind="@_name" /> <input id="name" class="form-control" @bind="@_name" />
@ -101,14 +88,99 @@ else
</select> </select>
</td> </td>
</tr> </tr>
@if (!_isinitialized) <tr>
<td>
<Label For="tenant" HelpText="Select the tenant for the site">Tenant: </Label>
</td>
<td>
<select id="tenant" class="form-control" @onchange="(e => TenantChanged(e))">
<option value="-">&lt;Select Tenant&gt;</option>
<option value="+">&lt;Create New Tenant&gt;</option>
@foreach (Tenant tenant in _tenants)
{ {
<option value="@tenant.TenantId">@tenant.Name</option>
}
</select>
</td>
</tr>
@if (_tenantid == "+")
{
<tr>
<td colspan="2">
<hr class="app-rule" />
</td>
</tr>
<tr>
<td>
<Label For="name" HelpText="Enter the name for the tenant">Tenant Name: </Label>
</td>
<td>
<input id="name" class="form-control" @bind="@_tenantname" />
</td>
</tr>
<tr>
<td>
<Label For="databaseType" HelpText="Select the database type for the tenant">Database Type: </Label>
</td>
<td>
<select id="databaseType" class="custom-select" @bind="@_databasetype">
<option value="LocalDB">Local Database</option>
<option value="SQLServer">SQL Server</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="server" HelpText="Enter the server for the tenant">Server: </Label>
</td>
<td>
<input id="server" type="text" class="form-control" @bind="@_server" />
</td>
</tr>
<tr>
<td>
<Label For="database" HelpText="Enter the database for the tenant">Database: </Label>
</td>
<td>
<input id="database" type="text" class="form-control" @bind="@_database" />
</td>
</tr>
<tr>
<td>
<Label For="integratedSecurity" HelpText="Select if you want integrated security or not">Integrated Security: </Label>
</td>
<td>
<select id="integratedSecurity" class="custom-select" @onchange="SetIntegratedSecurity">
<option value="true" selected>True</option>
<option value="false">False</option>
</select>
</td>
</tr>
@if (!_integratedsecurity)
{
<tr>
<td>
<Label For="username" HelpText="Enter the username for the integrated security">Database Username: </Label>
</td>
<td>
<input id="username" type="text" class="form-control" @bind="@_username" />
</td>
</tr>
<tr>
<td>
<Label For="password" HelpText="Enter the password for the integrated security">Database Password: </Label>
</td>
<td>
<input id="password" type="password" class="form-control" @bind="@_password" />
</td>
</tr>
}
<tr> <tr>
<td> <td>
<Label For="hostUsername" HelpText="Enter the username of the host for this site">Host Username:</Label> <Label For="hostUsername" HelpText="Enter the username of the host for this site">Host Username:</Label>
</td> </td>
<td> <td>
<input id="hostUsername" class="form-control" @bind="@_username" readonly /> <input id="hostUsername" class="form-control" @bind="@_hostusername" readonly />
</td> </td>
</tr> </tr>
<tr> <tr>
@ -116,7 +188,7 @@ else
<Label For="hostPassword" HelpText="Enter the password for the host of this site">Host Password:</Label> <Label For="hostPassword" HelpText="Enter the password for the host of this site">Host Password:</Label>
</td> </td>
<td> <td>
<input id="hostPassword" type="password" class="form-control" @bind="@_password" /> <input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" />
</td> </td>
</tr> </tr>
} }
@ -132,16 +204,24 @@ else
private List<SiteTemplate> _siteTemplates; private List<SiteTemplate> _siteTemplates;
private List<Theme> _themeList; private List<Theme> _themeList;
private List<Tenant> _tenants; private List<Tenant> _tenants;
private string _tenantid = "-1"; private string _tenantid = "-";
private string _tenantname = string.Empty;
private string _databasetype = "LocalDB";
private string _server = "(LocalDb)\\MSSQLLocalDB";
private string _database = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm");
private string _username = string.Empty;
private string _password = string.Empty;
private bool _integratedsecurity = true;
private string _hostusername = Constants.HostUser;
private string _hostpassword = string.Empty;
private string _name = string.Empty; private string _name = string.Empty;
private string _urls = string.Empty; private string _urls = string.Empty;
private string _themetype = string.Empty; private string _themetype = string.Empty;
private string _layouttype = string.Empty; private string _layouttype = string.Empty;
private string _containertype = string.Empty; private string _containertype = string.Empty;
private string _sitetemplatetype = string.Empty; private string _sitetemplatetype = string.Empty;
private bool _isinitialized = true;
private string _username = string.Empty;
private string _password = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
@ -153,29 +233,29 @@ else
_themes = ThemeService.GetThemeTypes(_themeList); _themes = ThemeService.GetThemeTypes(_themeList);
_containers = ThemeService.GetContainerTypes(_themeList); _containers = ThemeService.GetContainerTypes(_themeList);
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync(); _siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
_username = Constants.HostUser;
} }
private async void TenantChanged(ChangeEventArgs e) private void TenantChanged(ChangeEventArgs e)
{
try
{ {
_tenantid = (string)e.Value; _tenantid = (string)e.Value;
if (_tenantid != "-1") if (string.IsNullOrEmpty(_tenantname))
{ {
var tenant = _tenants.FirstOrDefault(item => item.TenantId == int.Parse(_tenantid)); _tenantname = _name;
if (tenant != null) }
{
_isinitialized = tenant.IsInitialized;
StateHasChanged(); StateHasChanged();
} }
}
} private void SetIntegratedSecurity(ChangeEventArgs e)
catch (Exception ex)
{ {
await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", _tenantid, ex.Message); if (Convert.ToBoolean((string)e.Value))
AddModuleMessage("Error Loading Tenant", MessageType.Error); {
_integratedsecurity = true;
} }
else
{
_integratedsecurity = false;
}
StateHasChanged();
} }
private async void ThemeChanged(ChangeEventArgs e) private async void ThemeChanged(ChangeEventArgs e)
@ -203,105 +283,116 @@ else
private async Task SaveSite() private async Task SaveSite()
{ {
if (_tenantid != "-1" && _name != string.Empty && _urls != string.Empty && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)) && !string.IsNullOrEmpty(_containertype) && !string.IsNullOrEmpty(_sitetemplatetype)) if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)) && !string.IsNullOrEmpty(_containertype) && !string.IsNullOrEmpty(_sitetemplatetype))
{ {
var unique = true; var duplicates = new List<string>();
var aliases = await AliasService.GetAliasesAsync(); var aliases = await AliasService.GetAliasesAsync();
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{ {
if (aliases.Exists(item => item.Name == name)) if (aliases.Exists(item => item.Name == name))
{ {
unique = false; duplicates.Add(name);
} }
} }
if (unique) if (duplicates.Count == 0)
{ {
var isvalid = true; InstallConfig config = new InstallConfig();
if (!_isinitialized) if (_tenantid == "+")
{ {
if (!string.IsNullOrEmpty(_tenantname) && _tenants.FirstOrDefault(item => item.Name == _tenantname) == null)
{
// validate host credentials
var user = new User(); var user = new User();
user.SiteId = PageState.Site.SiteId; user.SiteId = PageState.Site.SiteId;
user.Username = _username; user.Username = Constants.HostUser;
user.Password = _password; user.Password = _hostpassword;
user = await UserService.LoginUserAsync(user, false, false); user = await UserService.LoginUserAsync(user, false, false);
isvalid = user.IsAuthenticated; if (user.IsAuthenticated)
}
if (isvalid)
{ {
ShowProgressIndicator(); if (!string.IsNullOrEmpty(_server) && !string.IsNullOrEmpty(_database))
aliases = new List<Alias>();
_urls = _urls.Replace("\n", ",");
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{ {
var alias = new Alias(); var connectionString = string.Empty;
alias.Name = name; if (_databasetype == "LocalDB")
alias.TenantId = int.Parse(_tenantid);
alias.SiteId = -1;
alias = await AliasService.AddAliasAsync(alias);
aliases.Add(alias);
}
var site = new Site();
site.TenantId = int.Parse(_tenantid);
site.Name = _name;
site.LogoFileId = null;
site.FaviconFileId = null;
site.DefaultThemeType = _themetype;
site.DefaultLayoutType = (_layouttype == null ? string.Empty : _layouttype);
site.DefaultContainerType = _containertype;
site.PwaIsEnabled = false;
site.PwaAppIconFileId = null;
site.PwaSplashIconFileId = null;
site.AllowRegistration = false;
site.SiteTemplateType = _sitetemplatetype;
site = await SiteService.AddSiteAsync(site, aliases[0]);
foreach (Alias alias in aliases)
{ {
alias.SiteId = site.SiteId; connectionString = "Data Source=" + _server + ";AttachDbFilename=|DataDirectory|\\" + _database + ".mdf;Initial Catalog=" + _database + ";Integrated Security=SSPI;";
await AliasService.UpdateAliasAsync(alias); }
} else
{
if (!_isinitialized) connectionString = "Data Source=" + _server + ";Initial Catalog=" + _database + ";";
{
var user = new User(); if (_integratedsecurity)
user.SiteId = site.SiteId; {
user.Username = _username; connectionString += "Integrated Security=SSPI;";
user.Password = _password; }
user.Email = PageState.User.Email; else
user.DisplayName = PageState.User.DisplayName; {
user = await UserService.AddUserAsync(user, aliases[0]); connectionString += "User ID=" + _username + ";Password=" + _password;
}
if (user != null) }
{
var tenant = _tenants.FirstOrDefault(item => item.TenantId == int.Parse(_tenantid)); config.ConnectionString = connectionString;
if (tenant != null) config.HostPassword = _hostpassword;
{ config.HostEmail = user.Email;
tenant.IsInitialized = true; config.HostName = user.DisplayName;
await TenantService.UpdateTenantAsync(tenant); config.TenantName = _tenantname;
} config.IsNewTenant = true;
} }
} else
{
await Log(aliases[0], LogLevel.Information, string.Empty, null, "Site Created {Site}", site); AddModuleMessage("You Must Specify A Server And Database", MessageType.Error);
}
var uri = new Uri(NavigationManager.Uri);
NavigationManager.NavigateTo(uri.Scheme + "://" + aliases[0].Name, true);
} }
else else
{ {
await logger.LogError("Invalid Password Entered For Host {Username}", _username);
AddModuleMessage("Invalid Host Password", MessageType.Error); AddModuleMessage("Invalid Host Password", MessageType.Error);
} }
} }
else else
{ {
AddModuleMessage("An Alias Specified Has Already Been Used For Another Site", MessageType.Warning); AddModuleMessage("Tenant Name Is Missing Or Already Exists", MessageType.Error);
}
}
else
{
var tenant = _tenants.FirstOrDefault(item => item.TenantId == int.Parse(_tenantid));
if (tenant != null)
{
config.TenantName = tenant.Name;
config.ConnectionString= tenant.DBConnectionString;
config.IsNewTenant = false;
}
}
if (!string.IsNullOrEmpty(config.TenantName))
{
config.SiteName = _name;
config.Aliases = _urls.Replace("\n", ",");
config.DefaultTheme = _themetype;
config.DefaultLayout = _layouttype;
config.DefaultContainer = _containertype;
config.SiteTemplate = _sitetemplatetype;
ShowProgressIndicator();
var installation = await InstallationService.Install(config);
if (installation.Success)
{
var aliasname = config.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
var uri = new Uri(NavigationManager.Uri);
NavigationManager.NavigateTo(uri.Scheme + "://" + aliasname, true);
}
else
{
await logger.LogError("Error Creating Site {Error}", installation.Message);
AddModuleMessage(installation.Message, MessageType.Error);
}
}
}
else
{
AddModuleMessage(string.Join(", ", duplicates.ToArray()) + " Already Used For Another Site", MessageType.Warning);
} }
} }
else else

View File

@ -0,0 +1,81 @@
@namespace Oqtane.Modules.Admin.SystemInfo
@inherits ModuleBase
@inject ISystemService SystemService
<table class="table table-borderless">
<tr>
<td>
<Label For="version" HelpText="Framework Version">Framework Version: </Label>
</td>
<td>
<input id="version" class="form-control" @bind="@_version" disabled />
</td>
</tr>
<tr>
<td>
<Label For="runtime" HelpText="Blazor Runtime (Server or WebAssembly)">Blazor Runtime: </Label>
</td>
<td>
<input id="runtime" class="form-control" @bind="@_runtime" disabled />
</td>
</tr>
<tr>
<td>
<Label For="clrversion" HelpText="Common Language Runtime Version">CLR Version: </Label>
</td>
<td>
<input id="clrversion" class="form-control" @bind="@_clrversion" disabled />
</td>
</tr>
<tr>
<td>
<Label For="osversion" HelpText="Operating System Version">OS Version: </Label>
</td>
<td>
<input id="osversion" class="form-control" @bind="@_osversion" disabled />
</td>
</tr>
<tr>
<td>
<Label For="serverpath" HelpText="Server Path">Server Path: </Label>
</td>
<td>
<input id="serverpath" class="form-control" @bind="@_serverpath" disabled />
</td>
</tr>
<tr>
<td>
<Label For="servertime" HelpText="Server Time">Server Time: </Label>
</td>
<td>
<input id="servertime" class="form-control" @bind="@_servertime" disabled />
</td>
</tr>
</table>
<a class="btn btn-primary" href="swagger/index.html" target="_new">Access Framework API</a>
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
private string _version = string.Empty;
private string _runtime = string.Empty;
private string _clrversion = string.Empty;
private string _osversion = string.Empty;
private string _serverpath = string.Empty;
private string _servertime = string.Empty;
protected override async Task OnInitializedAsync()
{
_version = Constants.Version;
_runtime = PageState.Runtime.ToString();
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
if (systeminfo != null)
{
_clrversion = systeminfo["clrversion"];
_osversion = systeminfo["osversion"];
_serverpath = systeminfo["serverpath"];
_servertime = systeminfo["servertime"];
}
}
}

View File

@ -1,156 +0,0 @@
@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" HelpText="Enter the name for the tenant">Name: </Label>
</td>
<td>
<input id="name" class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<Label For="databaseType" HelpText="Select the database type for the tenant">Database Type: </Label>
</td>
<td>
<select id="databaseType" class="custom-select" @bind="@type">
<option value="LocalDB">Local Database</option>
<option value="SQLServer">SQL Server</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="server" HelpText="Enter the server for the tenant">Server: </Label>
</td>
<td>
<input id="server" type="text" class="form-control" @bind="@server" />
</td>
</tr>
<tr>
<td>
<Label For="database" HelpText="Enter the database for the tenant">Database: </Label>
</td>
<td>
<input id="database" type="text" class="form-control" @bind="@database" />
</td>
</tr>
<tr>
<td>
<Label For="integratedSecurity" HelpText="Select if you want integrated security or not">Integrated Security: </Label>
</td>
<td>
<select id="integratedSecurity" class="custom-select" @onchange="SetIntegratedSecurity">
<option value="true" selected>True</option>
<option value="false">False</option>
</select>
</td>
</tr>
<tr style="@integratedsecurity">
<td>
<Label For="username" HelpText="Enter the username for the integrated security">Username: </Label>
</td>
<td>
<input id="username" type="text" class="form-control" @bind="@username" />
</td>
</tr>
<tr style="@integratedsecurity">
<td>
<Label For="password" HelpText="Enter the password for the integrated security">Password: </Label>
</td>
<td>
<input id="password" type="password" class="form-control" @bind="@password" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveTenant">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
private string name = string.Empty;
private string type = "LocalDB";
private string server = "(LocalDb)\\MSSQLLocalDB";
private string database = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm");
private string username = string.Empty;
private string password = string.Empty;
private string schema = string.Empty;
private string integratedsecurity = "display: none;";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
private void SetIntegratedSecurity(ChangeEventArgs e)
{
if (Convert.ToBoolean((string)e.Value))
{
integratedsecurity = "display: none;";
}
else
{
integratedsecurity = string.Empty;
}
}
private async Task SaveTenant()
{
if (!string.IsNullOrEmpty(name))
{
ShowProgressIndicator();
var connectionString = string.Empty;
if (type == "LocalDB")
{
connectionString = "Data Source=" + server + ";AttachDbFilename=|DataDirectory|\\" + database + ".mdf;Initial Catalog=" + database + ";Integrated Security=SSPI;";
}
else
{
connectionString = "Data Source=" + server + ";Initial Catalog=" + database + ";";
if (integratedsecurity == "display: none;")
{
connectionString += "Integrated Security=SSPI;";
}
else
{
connectionString += "User ID=" + username + ";Password=" + password;
}
}
var config = new InstallConfig
{
IsMaster = false,
ConnectionString = connectionString,
};
var installation = await InstallationService.Install(config);
if (installation.Success)
{
//TODO : Move to Database Manager
var tenant = new Tenant
{
Name = name,
DBConnectionString = connectionString,
IsInitialized = false
};
await TenantService.AddTenantAsync(tenant);
await logger.LogInformation("Tenant Created {Tenant}", tenant);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
await logger.LogError("Error Creating Tenant {Error}", installation.Message);
AddModuleMessage(installation.Message, MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Provide A Name For The Tenant", MessageType.Warning);
}
}
}

View File

@ -6,7 +6,7 @@
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="name" HelpText="Enter the nameof the tenant">Name: </Label> <Label For="name" HelpText="The name of the tenant">Name: </Label>
</td> </td>
<td> <td>
@if (name == Constants.MasterTenant) @if (name == Constants.MasterTenant)
@ -21,10 +21,10 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="connectionString" HelpText="Enter the connection string for the tenant">Connection String: </Label> <Label For="connectionstring" HelpText="The database connection string">Connection String: </Label>
</td> </td>
<td> <td>
<input id="integratedSecurity" class="form-control" @bind="@connectionstring" /> <textarea id="connectionstring" class="form-control" @bind="@connectionstring" rows="3" readonly></textarea>
</td> </td>
</tr> </tr>

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.Tenants @namespace Oqtane.Modules.Admin.Tenants
@inherits ModuleBase @inherits ModuleBase
@inject ITenantService TenantService @inject ITenantService TenantService
@inject IAliasService AliasService
@if (tenants == null) @if (tenants == null)
{ {
@ -8,8 +9,6 @@
} }
else else
{ {
<ActionLink Action="Add" Text="Add Tenant" />
<Pager Items="@tenants"> <Pager Items="@tenants">
<Header> <Header>
<th>&nbsp;</th> <th>&nbsp;</th>
@ -38,11 +37,27 @@ else
private async Task DeleteTenant(Tenant Tenant) private async Task DeleteTenant(Tenant Tenant)
{ {
try try
{
string message = string.Empty;
var aliases = await AliasService.GetAliasesAsync();
foreach (var alias in aliases)
{
if (alias.TenantId == Tenant.TenantId)
{
message += ", " + alias.Name;
}
}
if (string.IsNullOrEmpty(message))
{ {
await TenantService.DeleteTenantAsync(Tenant.TenantId); await TenantService.DeleteTenantAsync(Tenant.TenantId);
await logger.LogInformation("Tenant Deleted {Tenant}", Tenant); await logger.LogInformation("Tenant Deleted {Tenant}", Tenant);
StateHasChanged(); StateHasChanged();
} }
else
{
AddModuleMessage("Tenant Cannot Be Deleted Until The Following Sites Are Deleted: " + message.Substring(2), MessageType.Warning);
}
}
catch (Exception ex) catch (Exception ex)
{ {
await logger.LogError(ex, "Error Deleting Tenant {Tenant} {Error}", Tenant, ex.Message); await logger.LogError(ex, "Error Deleting Tenant {Tenant} {Error}", Tenant, ex.Message);

View File

@ -5,23 +5,14 @@
@inject IThemeService ThemeService @inject IThemeService ThemeService
@inject IPackageService PackageService @inject IPackageService PackageService
<table class="table table-borderless"> @if (_packages != null)
<tr>
<td>
<Label For="theme" HelpText="Upload a theme from your system">Theme: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Themes" />
</td>
</tr>
</table>
@if (packages != null)
{ {
<hr class="app-rule" /> <TabStrip>
<div class="mx-auto text-center"><h2>Available Themes</h2></div> @if (_packages.Count > 0)
{
<Pager Items="@packages"> <TabPanel Name="Download">
<ModuleMessage Type="MessageType.Info" Message="Download one or more themes from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<Pager Items="@_packages">
<Header> <Header>
<th>Name</th> <th>Name</th>
<th>Version</th> <th>Version</th>
@ -31,44 +22,83 @@
<td>@context.Name</td> <td>@context.Name</td>
<td>@context.Version</td> <td>@context.Version</td>
<td> <td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadTheme(context.PackageId, context.Version))>Download Theme</button> <button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadTheme(context.PackageId, context.Version))>Download</button>
</td> </td>
</Row> </Row>
</Pager> </Pager>
</TabPanel>
} }
<TabPanel Name="Upload">
<table class="table table-borderless">
<tr>
<td>
<Label HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation.">Theme: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Themes" UploadMultiple="True" />
</td>
</tr>
</table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="InstallThemes">Install</button> <button type="button" class="btn btn-success" @onclick="InstallThemes">Install</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
@code { @code {
private List<Package> packages; private List<Package> _packages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{
try
{ {
var themes = await ThemeService.GetThemesAsync(); var themes = await ThemeService.GetThemesAsync();
packages = await PackageService.GetPackagesAsync("theme"); _packages = await PackageService.GetPackagesAsync("theme");
foreach(Package package in packages.ToArray()) foreach (Package package in _packages.ToArray())
{ {
if (themes.Exists(item => Utilities.GetTypeName(item.ThemeName) == package.PackageId)) if (themes.Exists(item => Utilities.GetTypeName(item.ThemeName) == package.PackageId))
{ {
packages.Remove(package); _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 InstallThemes() private async Task InstallThemes()
{
try
{ {
await ThemeService.InstallThemesAsync(); await ThemeService.InstallThemesAsync();
NavigationManager.NavigateTo(NavigateUrl()); NavigationManager.NavigateTo(NavigateUrl());
} }
catch (Exception ex)
{
await logger.LogError(ex, "Error Installating Theme");
}
}
private async Task DownloadTheme(string packageid, string version) private async Task DownloadTheme(string packageid, string version)
{
try
{ {
await PackageService.DownloadPackageAsync(packageid, version, "Themes"); await PackageService.DownloadPackageAsync(packageid, version, "Themes");
AddModuleMessage("Theme Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success); await logger.LogInformation("Theme {ThemeName} {Version} Downloaded Successfully", packageid, version);
AddModuleMessage("Themes Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
StateHasChanged(); StateHasChanged();
} }
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ThemeName} {Version}", packageid, version);
AddModuleMessage("Error Downloading Theme", MessageType.Error);
}
}
} }

View File

@ -5,42 +5,55 @@
@inject IPackageService PackageService @inject IPackageService PackageService
@inject IInstallationService InstallationService @inject IInstallationService InstallationService
@if (_package != null)
{
<TabStrip>
<TabPanel Name="Download">
@if (_upgradeavailable)
{
<ModuleMessage Type="MessageType.Info" Message="Download a new version of the framework. Once you are ready click Install to complete the installation."></ModuleMessage>
@("Framework") @_package.Version <button type="button" class="btn btn-success" @onclick=@(async () => await Download(Constants.PackageId, Constants.Version))>Download</button>
}
else
{
<ModuleMessage Type="MessageType.Info" Message="Framework Is Already Up To Date"></ModuleMessage>
}
</TabPanel>
@if (_upgradeavailable)
{
<TabPanel Name="Upload">
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="framework" HelpText="Upload a framework to update the site">Framework: </Label> <Label HelpText="Upload a new framework package. Once it is uploaded click Install to complete the installation.">Framework: </Label>
</td> </td>
<td> <td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Framework" /> <FileManager Filter="nupkg" ShowFiles="false" Folder="Framework" />
</td> </td>
</tr> </tr>
</table> </table>
<button type="button" class="btn btn-success" @onclick="Upgrade">Upgrade</button> </TabPanel>
}
@if (upgradeavailable) </TabStrip>
{
<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 { @code {
private bool upgradeavailable = false; private Package _package;
private bool _upgradeavailable = false;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
var packages = await PackageService.GetPackagesAsync("framework"); List<Package> packages = await PackageService.GetPackagesAsync("framework");
var package = packages.FirstOrDefault(); _package = packages.FirstOrDefault();
if (package != null) if (_package != null)
{ {
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) > 0); _upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
} }
if (!upgradeavailable) else
{ {
AddModuleMessage("Framework Is Up To Date", MessageType.Info); _package = new Package { Name = Constants.PackageId, Version = Constants.Version };
} }
} }

View File

@ -6,27 +6,7 @@
@inject ISettingService SettingService @inject ISettingService SettingService
@inject INotificationService NotificationService @inject INotificationService NotificationService
@if (PageState.User != null && profiles != null) @if (PageState.User != null && photofileid != -1)
{
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#Profile" role="tab">
Profile
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#Notifications" role="tab">
Notifications
</a>
</li>
</ul>
<div class="tab-content">
<div id="Profile" class="tab-pane fade show active" role="tabpanel">
@if (photofileid != -1)
{ {
<img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block"> <img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
} }
@ -34,6 +14,10 @@
{ {
<br /> <br />
} }
<TabStrip>
<TabPanel Name="Identity">
@if (PageState.User != null)
{
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
@ -83,7 +67,15 @@
<FileManager FileId="@photofileid.ToString()" @ref="filemanager" /> <FileManager FileId="@photofileid.ToString()" @ref="filemanager" />
</td> </td>
</tr> </tr>
</table>
<button type="button" class="btn btn-primary" @onclick="Save">Save</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
}
</TabPanel>
<TabPanel Name="Profile">
@if (profiles != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles) @foreach (Profile profile in profiles)
{ {
var p = profile; var p = profile;
@ -108,10 +100,11 @@
</table> </table>
<button type="button" class="btn btn-primary" @onclick="Save">Save</button> <button type="button" class="btn btn-primary" @onclick="Save">Save</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button> <button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
</div> }
</TabPanel>
<div id="Notifications" class="tab-pane fade" role="tabpanel"> <TabPanel Name="Notifications">
<br /> @if (notifications != null)
{
<ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" /> <ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" />
<br /><br /> <br /><br />
@if (filter == "to") @if (filter == "to")
@ -165,11 +158,9 @@
<option value="to">Inbox</option> <option value="to">Inbox</option>
<option value="from">Sent Items</option> <option value="from">Sent Items</option>
</select> </select>
</div>
</div>
</div>
</div>
} }
</TabPanel>
</TabStrip>
@code { @code {
private string username = string.Empty; private string username = string.Empty;

View File

@ -5,6 +5,8 @@
@inject IProfileService ProfileService @inject IProfileService ProfileService
@inject ISettingService SettingService @inject ISettingService SettingService
<TabStrip>
<TabPanel Name="Identity">
@if (profiles != null) @if (profiles != null)
{ {
<table class="table table-borderless"> <table class="table table-borderless">
@ -48,7 +50,13 @@
<input class="form-control" @bind="@displayname" /> <input class="form-control" @bind="@displayname" />
</td> </td>
</tr> </tr>
</table>
}
</TabPanel>
<TabPanel Name="Profile">
@if (profiles != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles) @foreach (Profile profile in profiles)
{ {
var p = profile; var p = profile;
@ -71,9 +79,12 @@
</tr> </tr>
} }
</table> </table>
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button> <button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
@code { @code {
private string username = string.Empty; private string username = string.Empty;

View File

@ -5,9 +5,7 @@
@inject IProfileService ProfileService @inject IProfileService ProfileService
@inject ISettingService SettingService @inject ISettingService SettingService
@if (profiles != null) @if (PageState.User != null && photofileid != -1)
{
@if (photofileid != -1)
{ {
<img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block"> <img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
} }
@ -15,6 +13,10 @@
{ {
<br /> <br />
} }
<TabStrip>
<TabPanel Name="Identity">
@if (profiles != null)
{
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
@ -64,7 +66,24 @@
<FileManager FileId="@photofileid.ToString()" @ref="filemanager" /> <FileManager FileId="@photofileid.ToString()" @ref="filemanager" />
</td> </td>
</tr> </tr>
<tr>
<td>
<label 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>
}
</TabPanel>
<TabPanel Name="Profile">
@if (profiles != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles) @foreach (Profile profile in profiles)
{ {
var p = profile; var p = profile;
@ -86,24 +105,15 @@
</td> </td>
</tr> </tr>
} }
<tr>
<td>
<Label For="isDeleted" HelpText="Has the user been deleted">Is Deleted? </Label>
</td>
<td>
<select id="isDeleted" class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table> </table>
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button> <button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<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" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo> <AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@code { @code {
private int userid; private int userid;
@ -170,7 +180,7 @@
{ {
try try
{ {
if (username != string.Empty && password != string.Empty && confirm != string.Empty && email != string.Empty) if (username != string.Empty && email != string.Empty)
{ {
if (password == confirm) if (password == confirm)
{ {

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.Users @namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase @inherits ModuleBase
@inject IRoleService RoleService @inject IRoleService RoleService
@inject IUserService UserService
@inject IUserRoleService UserRoleService @inject IUserRoleService UserRoleService
@if (userroles == null) @if (userroles == null)
@ -12,7 +13,15 @@ else
<table class="table table-borderless"> <table class="table table-borderless">
<tr> <tr>
<td> <td>
<Label For="role" HelpText="What is the role of this user">Role: </Label> <Label For="user" HelpText="The user you are assigning roles to">User: </Label>
</td>
<td>
<input id="user" class="form-control" @bind="@name" disabled />
</td>
</tr>
<tr>
<td>
<Label For="role" HelpText="Select a role">Role: </Label>
</td> </td>
<td> <td>
<select id="role" class="form-control" @bind="@roleid"> <select id="role" class="form-control" @bind="@roleid">
@ -26,7 +35,7 @@ else
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="effectiveDate" HelpText="The date that this role is implemented">Effective Date: </Label> <Label For="effectiveDate" HelpText="The date that this role assignment is active">Effective Date: </Label>
</td> </td>
<td> <td>
<input id="effectiveDate" class="form-control" @bind="@effectivedate" /> <input id="effectiveDate" class="form-control" @bind="@effectivedate" />
@ -34,7 +43,7 @@ else
</tr> </tr>
<tr> <tr>
<td> <td>
<Label For="expiryDate" HelpText="The date that this role expires">Expiry Date: </Label> <Label For="expiryDate" HelpText="The date that this role assignment expires">Expiry Date: </Label>
</td> </td>
<td> <td>
<input id="expiryDate" class="form-control" @bind="@expirydate" /> <input id="expiryDate" class="form-control" @bind="@expirydate" />
@ -48,13 +57,13 @@ else
<p align="center"> <p align="center">
<Pager Items="@userroles"> <Pager Items="@userroles">
<Header> <Header>
<th>Role</th> <th>Roles</th>
<th>&nbsp;</th> <th>&nbsp;</th>
</Header> </Header>
<Row> <Row>
<td>@context.Role.Name</td> <td>@context.Role.Name</td>
<td> <td>
@if (!context.Role.IsSystem) @if (context.Role.Name != Constants.RegisteredRole)
{ {
<button type="button" class="btn btn-danger" @onclick=@(async () => await DeleteUserRole(context.UserRoleId))>Delete</button> <button type="button" class="btn btn-danger" @onclick=@(async () => await DeleteUserRole(context.UserRoleId))>Delete</button>
} }
@ -66,6 +75,7 @@ else
@code { @code {
private int userid; private int userid;
private string name = string.Empty;
private List<Role> roles; private List<Role> roles;
private int roleid = -1; private int roleid = -1;
private string effectivedate = string.Empty; private string effectivedate = string.Empty;
@ -79,6 +89,8 @@ else
try try
{ {
userid = Int32.Parse(PageState.QueryString["id"]); userid = Int32.Parse(PageState.QueryString["id"]);
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
name = user.DisplayName;
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId); roles = await RoleService.GetRolesAsync(PageState.Site.SiteId);
await GetUserRoles(); await GetUserRoles();
} }

View File

@ -12,7 +12,7 @@
<th>Role</th> <th>Role</th>
@foreach (PermissionString permission in _permissions) @foreach (PermissionString permission in _permissions)
{ {
<th style="text-align: center;">@permission.PermissionName @EntityName</th> <th style="text-align: center;">@permission.PermissionName</th>
} }
</tr> </tr>
@foreach (Role role in _roles) @foreach (Role role in _roles)
@ -38,7 +38,7 @@
<th>User</th> <th>User</th>
@foreach (PermissionString permission in _permissions) @foreach (PermissionString permission in _permissions)
{ {
<th style="text-align: center;">@permission.PermissionName @EntityName</th> <th style="text-align: center;">@permission.PermissionName</th>
} }
</tr> </tr>
</thead> </thead>

View File

@ -38,7 +38,15 @@
public RenderFragment ChildContent { get; set; } // contains the TabPanels public RenderFragment ChildContent { get; set; } // contains the TabPanels
[Parameter] [Parameter]
public string ActiveTab { get; set; } // optional - defaults to first TabPanel if not specified public string ActiveTab { get; set; } // optional - defaults to first TabPanel if not specified. Can also be set using a "tab=" querystring parameter.
protected override void OnInitialized()
{
if (PageState.QueryString.ContainsKey("tab"))
{
ActiveTab = PageState.QueryString["tab"];
}
}
internal void AddTabPanel(TabPanel tabPanel) internal void AddTabPanel(TabPanel tabPanel)
{ {
@ -47,6 +55,7 @@
{ {
ActiveTab = tabPanel.Name; ActiveTab = tabPanel.Name;
} }
StateHasChanged();
} }
private string DisplayHeading(string Name, string Heading) private string DisplayHeading(string Name, string Heading)

View File

@ -1,16 +0,0 @@
@namespace Oqtane.Modules.Counter
@inherits ModuleBase
Current count: @currentCount
<br />
<button type="button" class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<br />
<br />
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}

View File

@ -1,14 +0,0 @@
using Oqtane.Models;
namespace Oqtane.Modules.Counter
{
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "Counter",
Description = "Increments a counter",
Version = "1.0.0"
};
}
}

View File

@ -8,9 +8,15 @@
@((MarkupString)content) @((MarkupString)content)
@if (PageState.EditMode)
{
<br /> <br />
}
<ActionLink Action="Edit" /> <ActionLink Action="Edit" />
@if (PageState.EditMode)
{
<br /><br /> <br /><br />
}
@code { @code {
private string content = ""; private string content = "";

View File

@ -7,9 +7,10 @@ namespace Oqtane.Modules.HtmlText
public ModuleDefinition ModuleDefinition => new ModuleDefinition public ModuleDefinition ModuleDefinition => new ModuleDefinition
{ {
Name = "HtmlText", Name = "HtmlText",
Description = "Renders HTML or Text", Description = "Renders HTML or Text Content",
Version = "1.0.0", Version = "1.0.0",
ServerAssemblyName = "Oqtane.Server" ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
ReleaseVersions = "1.0.0"
}; };
} }
} }

View File

@ -11,13 +11,13 @@ namespace Oqtane.Modules.HtmlText.Services
{ {
public class HtmlTextService : ServiceBase, IHtmlTextService public class HtmlTextService : ServiceBase, IHtmlTextService
{ {
private readonly HttpClient _http;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
private readonly SiteState _siteState; private readonly SiteState _siteState;
public HtmlTextService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public HtmlTextService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -31,7 +31,7 @@ namespace Oqtane.Modules.HtmlText.Services
{ {
//because GetJsonAsync() returns an error if no content exists for the ModuleId ( https://github.com/aspnet/AspNetCore/issues/14041 ) //because GetJsonAsync() returns an error if no content exists for the ModuleId ( https://github.com/aspnet/AspNetCore/issues/14041 )
//null value is transfered as empty list //null value is transfered as empty list
var htmlTextList = await _http.GetJsonAsync<List<HtmlTextInfo>>(ApiUrl + "/" + moduleId + "?entityid=" + moduleId); var htmlTextList = await GetJsonAsync<List<HtmlTextInfo>>(ApiUrl + "/" + moduleId + "?entityid=" + moduleId);
htmlText = htmlTextList.FirstOrDefault(); htmlText = htmlTextList.FirstOrDefault();
} }
catch catch
@ -44,17 +44,18 @@ namespace Oqtane.Modules.HtmlText.Services
public async Task AddHtmlTextAsync(HtmlTextInfo htmlText) public async Task AddHtmlTextAsync(HtmlTextInfo htmlText)
{ {
await _http.PostJsonAsync(ApiUrl + "?entityid=" + htmlText.ModuleId, htmlText); await PostJsonAsync(ApiUrl + "?entityid=" + htmlText.ModuleId, htmlText);
} }
public async Task UpdateHtmlTextAsync(HtmlTextInfo htmlText) public async Task UpdateHtmlTextAsync(HtmlTextInfo htmlText)
{ {
await _http.PutJsonAsync(ApiUrl + "/" + htmlText.HtmlTextId + "?entityid=" + htmlText.ModuleId, htmlText); await PutJsonAsync(ApiUrl + "/" + htmlText.HtmlTextId + "?entityid=" + htmlText.ModuleId, htmlText);
} }
public async Task DeleteHtmlTextAsync(int moduleId) public async Task DeleteHtmlTextAsync(int moduleId)
{ {
await _http.DeleteAsync(ApiUrl + "/" + moduleId + "?entityid=" + moduleId); await DeleteAsync(ApiUrl + "/" + moduleId + "?entityid=" + moduleId);
} }
} }
} }

View File

@ -1,42 +0,0 @@
@using Oqtane.Modules.Weather.Services
@namespace Oqtane.Modules.Weather
@inherits ModuleBase
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
WeatherForecastService forecastservice = new WeatherForecastService();
forecasts = await forecastservice.GetForecastAsync(DateTime.UtcNow);
}
}

View File

@ -1,12 +0,0 @@
using System;
namespace Oqtane.Modules.Weather
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF { get; set; }
public string Summary { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using Oqtane.Models;
namespace Oqtane.Modules.Weather
{
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "Weather",
Description = "Displays random weather using a service",
Version = "1.0.0"
};
}
}

View File

@ -1,10 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Oqtane.Modules.Weather.Services
{
public interface IWeatherForecastService
{
Task<WeatherForecast[]> GetForecastAsync(DateTime startDate);
}
}

View File

@ -1,26 +0,0 @@
using Oqtane.Modules;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Oqtane.Modules.Weather.Services
{
public class WeatherForecastService : IWeatherForecastService
{
private static string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
}

View File

@ -27,10 +27,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview3.20168.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview5.20216.8" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview3.20168.3" PrivateAssets="all" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview5.20216.8" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.2" />
<PackageReference Include="System.Net.Http.Json" Version="3.2.0-preview5.20210.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -5,6 +5,7 @@ using Oqtane.Services;
using System.Reflection; using System.Reflection;
using System; using System;
using System.Linq; using System.Linq;
using System.Net.Http;
using Oqtane.Modules; using Oqtane.Modules;
using Oqtane.Shared; using Oqtane.Shared;
using Oqtane.Providers; using Oqtane.Providers;
@ -19,7 +20,9 @@ namespace Oqtane.Client
var builder = WebAssemblyHostBuilder.CreateDefault(args); var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app"); builder.RootComponents.Add<App>("app");
builder.Services.AddBaseAddressHttpClient(); builder.Services.AddSingleton(
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }
);
builder.Services.AddOptions(); builder.Services.AddOptions();
// register auth services // register auth services
@ -52,6 +55,7 @@ namespace Oqtane.Client
builder.Services.AddScoped<IFileService, FileService>(); builder.Services.AddScoped<IFileService, FileService>();
builder.Services.AddScoped<ISiteTemplateService, SiteTemplateService>(); builder.Services.AddScoped<ISiteTemplateService, SiteTemplateService>();
builder.Services.AddScoped<ISqlService, SqlService>(); builder.Services.AddScoped<ISqlService, SqlService>();
builder.Services.AddScoped<ISystemService, SystemService>();
// dynamically register module contexts and repository services // dynamically register module contexts and repository services
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -29,7 +30,7 @@ namespace Oqtane.Providers
// get HttpClient lazily from IServiceProvider as you cannot use standard dependency injection due to the AuthenticationStateProvider being initialized prior to NavigationManager ( https://github.com/aspnet/AspNetCore/issues/11867 ) // get HttpClient lazily from IServiceProvider as you cannot use standard dependency injection due to the AuthenticationStateProvider being initialized prior to NavigationManager ( https://github.com/aspnet/AspNetCore/issues/11867 )
var http = _serviceProvider.GetRequiredService<HttpClient>(); var http = _serviceProvider.GetRequiredService<HttpClient>();
string apiurl = ServiceBase.CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "User") + "/authenticate"; string apiurl = ServiceBase.CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "User") + "/authenticate";
User user = await http.GetJsonAsync<User>(apiurl); User user = await http.GetFromJsonAsync<User>(apiurl);
ClaimsIdentity identity = new ClaimsIdentity(); ClaimsIdentity identity = new ClaimsIdentity();
if (user.IsAuthenticated) if (user.IsAuthenticated)

View File

@ -2,23 +2,24 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Net.Http; using System.Net.Http;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Components; //using Microsoft.AspNetCore.Components;
using System.Collections.Generic; using System.Collections.Generic;
using Oqtane.Shared; using Oqtane.Shared;
using System.Net; using System.Net;
using System; using System;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Components;
namespace Oqtane.Services namespace Oqtane.Services
{ {
public class AliasService : ServiceBase, IAliasService public class AliasService : ServiceBase, IAliasService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public AliasService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public AliasService(HttpClient http, SiteState siteState, NavigationManager navigationManager) :base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -30,13 +31,13 @@ namespace Oqtane.Services
public async Task<List<Alias>> GetAliasesAsync() public async Task<List<Alias>> GetAliasesAsync()
{ {
List<Alias> aliases = await _http.GetJsonAsync<List<Alias>>(Apiurl); List<Alias> aliases = await GetJsonAsync<List<Alias>>(Apiurl);
return aliases.OrderBy(item => item.Name).ToList(); return aliases.OrderBy(item => item.Name).ToList();
} }
public async Task<Alias> GetAliasAsync(int aliasId) public async Task<Alias> GetAliasAsync(int aliasId)
{ {
return await _http.GetJsonAsync<Alias>($"{Apiurl}/{aliasId.ToString()}"); return await GetJsonAsync<Alias>($"{Apiurl}/{aliasId.ToString()}");
} }
public async Task<Alias> GetAliasAsync(string url, DateTime lastSyncDate) public async Task<Alias> GetAliasAsync(string url, DateTime lastSyncDate)
@ -51,21 +52,21 @@ namespace Oqtane.Services
{ {
name = name.Substring(0, name.Length - 1); name = name.Substring(0, name.Length - 1);
} }
return await _http.GetJsonAsync<Alias>($"{Apiurl}/name/{WebUtility.UrlEncode(name)}?lastsyncdate={lastSyncDate.ToString("yyyyMMddHHmmssfff")}"); return await GetJsonAsync<Alias>($"{Apiurl}/name/{WebUtility.UrlEncode(name)}?lastsyncdate={lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
} }
public async Task<Alias> AddAliasAsync(Alias alias) public async Task<Alias> AddAliasAsync(Alias alias)
{ {
return await _http.PostJsonAsync<Alias>(Apiurl, alias); return await PostJsonAsync<Alias>(Apiurl, alias);
} }
public async Task<Alias> UpdateAliasAsync(Alias alias) public async Task<Alias> UpdateAliasAsync(Alias alias)
{ {
return await _http.PutJsonAsync<Alias>($"{Apiurl}/{alias.AliasId.ToString()}", alias); return await PutJsonAsync<Alias>($"{Apiurl}/{alias.AliasId.ToString()}", alias);
} }
public async Task DeleteAliasAsync(int aliasId) public async Task DeleteAliasAsync(int aliasId)
{ {
await _http.DeleteAsync($"{Apiurl}/{aliasId.ToString()}"); await DeleteAsync($"{Apiurl}/{aliasId.ToString()}");
} }
} }
} }

View File

@ -13,15 +13,13 @@ 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(HttpClient http, SiteState siteState, NavigationManager navigationManager, public FileService(HttpClient http, SiteState siteState, NavigationManager navigationManager,
IJSRuntime jsRuntime) IJSRuntime jsRuntime) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
_jsRuntime = jsRuntime; _jsRuntime = jsRuntime;
@ -39,51 +37,44 @@ namespace Oqtane.Services
public async Task<List<File>> GetFilesAsync(string folder) public async Task<List<File>> GetFilesAsync(string folder)
{ {
return await _http.GetJsonAsync<List<File>>($"{Apiurl}?folder={folder}"); return await GetJsonAsync<List<File>>($"{Apiurl}?folder={folder}");
} }
public async Task<List<File>> GetFilesAsync(int siteId, string folderPath) public async Task<List<File>> GetFilesAsync(int siteId, string folderPath)
{ {
if (!folderPath.EndsWith("\\")) if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
{ {
folderPath += "\\"; folderPath = Utilities.PathCombine(folderPath,"\\");
} }
var path = WebUtility.UrlEncode(folderPath); var path = WebUtility.UrlEncode(folderPath);
return await _http.GetJsonAsync<List<File>>($"{Apiurl}/{siteId}/{path}"); return await GetJsonAsync<List<File>>($"{Apiurl}/{siteId}/{path}");
} }
public async Task<File> GetFileAsync(int fileId) public async Task<File> GetFileAsync(int fileId)
{ {
try return await GetJsonAsync<File>($"{Apiurl}/{fileId.ToString()}");
{
return await _http.GetJsonAsync<File>($"{Apiurl}/{fileId.ToString()}");
}
catch
{
return null;
}
} }
public async Task<File> AddFileAsync(File file) public async Task<File> AddFileAsync(File file)
{ {
return await _http.PostJsonAsync<File>(Apiurl, file); return await PostJsonAsync<File>(Apiurl, file);
} }
public async Task<File> UpdateFileAsync(File file) public async Task<File> UpdateFileAsync(File file)
{ {
return await _http.PutJsonAsync<File>($"{Apiurl}/{file.FileId.ToString()}", file); return await PutJsonAsync<File>($"{Apiurl}/{file.FileId.ToString()}", file);
} }
public async Task DeleteFileAsync(int fileId) public async Task DeleteFileAsync(int fileId)
{ {
await _http.DeleteAsync($"{Apiurl}/{fileId.ToString()}"); await DeleteAsync($"{Apiurl}/{fileId.ToString()}");
} }
public async Task<File> UploadFileAsync(string url, int folderId) public async Task<File> UploadFileAsync(string url, int folderId)
{ {
return await _http.GetJsonAsync<File>($"{Apiurl}/upload?url={WebUtility.UrlEncode(url)}&folderid={folderId.ToString()}"); return await GetJsonAsync<File>($"{Apiurl}/upload?url={WebUtility.UrlEncode(url)}&folderid={folderId.ToString()}");
} }
public async Task<string> UploadFilesAsync(int folderId, string[] files, string id) public async Task<string> UploadFilesAsync(int folderId, string[] files, string id)
@ -133,7 +124,7 @@ namespace Oqtane.Services
public async Task<byte[]> DownloadFileAsync(int fileId) public async Task<byte[]> DownloadFileAsync(int fileId)
{ {
return await _http.GetByteArrayAsync($"{Apiurl}/download/{fileId.ToString()}"); return await GetByteArrayAsync($"{Apiurl}/download/{fileId.ToString()}");
} }
} }
} }

View File

@ -13,13 +13,11 @@ namespace Oqtane.Services
{ {
public class FolderService : ServiceBase, IFolderService public class FolderService : ServiceBase, IFolderService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public FolderService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public FolderService(HttpClient http, SiteState siteState, NavigationManager navigationManager):base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,36 +26,36 @@ namespace Oqtane.Services
public async Task<List<Folder>> GetFoldersAsync(int siteId) public async Task<List<Folder>> GetFoldersAsync(int siteId)
{ {
List<Folder> folders = await _http.GetJsonAsync<List<Folder>>($"{ApiUrl}?siteid={siteId.ToString()}"); List<Folder> folders = await GetJsonAsync<List<Folder>>($"{ApiUrl}?siteid={siteId.ToString()}");
folders = GetFoldersHierarchy(folders); folders = GetFoldersHierarchy(folders);
return folders; return folders;
} }
public async Task<Folder> GetFolderAsync(int folderId) public async Task<Folder> GetFolderAsync(int folderId)
{ {
return await _http.GetJsonAsync<Folder>($"{ApiUrl}/{folderId.ToString()}"); return await GetJsonAsync<Folder>($"{ApiUrl}/{folderId.ToString()}");
} }
public async Task<Folder> GetFolderAsync(int siteId, [NotNull] string folderPath) public async Task<Folder> GetFolderAsync(int siteId, [NotNull] string folderPath)
{ {
if (!folderPath.EndsWith("\\")) if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
{ {
folderPath += "\\"; folderPath = Utilities.PathCombine(folderPath, "\\");
} }
var path = WebUtility.UrlEncode(folderPath); var path = WebUtility.UrlEncode(folderPath);
return await _http.GetJsonAsync<Folder>($"{ApiUrl}/{siteId}/{path}"); return await GetJsonAsync<Folder>($"{ApiUrl}/{siteId}/{path}");
} }
public async Task<Folder> AddFolderAsync(Folder folder) public async Task<Folder> AddFolderAsync(Folder folder)
{ {
return await _http.PostJsonAsync<Folder>(ApiUrl, folder); return await PostJsonAsync<Folder>(ApiUrl, folder);
} }
public async Task<Folder> UpdateFolderAsync(Folder folder) public async Task<Folder> UpdateFolderAsync(Folder folder)
{ {
return await _http.PutJsonAsync<Folder>($"{ApiUrl}/{folder.FolderId.ToString()}", folder); return await PutJsonAsync<Folder>($"{ApiUrl}/{folder.FolderId.ToString()}", folder);
} }
public async Task UpdateFolderOrderAsync(int siteId, int folderId, int? parentId) public async Task UpdateFolderOrderAsync(int siteId, int folderId, int? parentId)
@ -65,12 +63,12 @@ namespace Oqtane.Services
var parent = parentId == null var parent = parentId == null
? string.Empty ? string.Empty
: parentId.ToString(); : parentId.ToString();
await _http.PutJsonAsync($"{ApiUrl}/?siteid={siteId.ToString()}&folderid={folderId.ToString()}&parentid={parent}", null); await PutAsync($"{ApiUrl}/?siteid={siteId.ToString()}&folderid={folderId.ToString()}&parentid={parent}");
} }
public async Task DeleteFolderAsync(int folderId) public async Task DeleteFolderAsync(int folderId)
{ {
await _http.DeleteAsync($"{ApiUrl}/{folderId.ToString()}"); await DeleteAsync($"{ApiUrl}/{folderId.ToString()}");
} }
private static List<Folder> GetFoldersHierarchy(List<Folder> folders) private static List<Folder> GetFoldersHierarchy(List<Folder> folders)

View File

@ -8,13 +8,11 @@ namespace Oqtane.Services
{ {
public class InstallationService : ServiceBase, IInstallationService public class InstallationService : ServiceBase, IInstallationService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public InstallationService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public InstallationService(HttpClient http, SiteState siteState, NavigationManager navigationManager):base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -23,17 +21,17 @@ namespace Oqtane.Services
public async Task<Installation> IsInstalled() public async Task<Installation> IsInstalled()
{ {
return await _http.GetJsonAsync<Installation>($"{ApiUrl}/installed"); return await GetJsonAsync<Installation>($"{ApiUrl}/installed");
} }
public async Task<Installation> Install(InstallConfig config) public async Task<Installation> Install(InstallConfig config)
{ {
return await _http.PostJsonAsync<Installation>(ApiUrl, config); return await PostJsonAsync<InstallConfig,Installation>(ApiUrl, config);
} }
public async Task<Installation> Upgrade() public async Task<Installation> Upgrade()
{ {
return await _http.GetJsonAsync<Installation>($"{ApiUrl}/upgrade"); return await GetJsonAsync<Installation>($"{ApiUrl}/upgrade");
} }
} }
} }

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface ISystemService
{
Task<Dictionary<string, string>> GetSystemInfoAsync();
}
}

View File

@ -10,13 +10,12 @@ namespace Oqtane.Services
{ {
public class JobLogService : ServiceBase, IJobLogService public class JobLogService : ServiceBase, IJobLogService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public JobLogService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public JobLogService(HttpClient http, SiteState siteState, NavigationManager navigationManager) :base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,27 +27,27 @@ namespace Oqtane.Services
public async Task<List<JobLog>> GetJobLogsAsync() public async Task<List<JobLog>> GetJobLogsAsync()
{ {
List<JobLog> joblogs = await _http.GetJsonAsync<List<JobLog>>(Apiurl); List<JobLog> joblogs = await GetJsonAsync<List<JobLog>>(Apiurl);
return joblogs.OrderBy(item => item.StartDate).ToList(); return joblogs.OrderBy(item => item.StartDate).ToList();
} }
public async Task<JobLog> GetJobLogAsync(int jobLogId) public async Task<JobLog> GetJobLogAsync(int jobLogId)
{ {
return await _http.GetJsonAsync<JobLog>($"{Apiurl}/{jobLogId.ToString()}"); return await GetJsonAsync<JobLog>($"{Apiurl}/{jobLogId.ToString()}");
} }
public async Task<JobLog> AddJobLogAsync(JobLog joblog) public async Task<JobLog> AddJobLogAsync(JobLog joblog)
{ {
return await _http.PostJsonAsync<JobLog>(Apiurl, joblog); return await PostJsonAsync<JobLog>(Apiurl, joblog);
} }
public async Task<JobLog> UpdateJobLogAsync(JobLog joblog) public async Task<JobLog> UpdateJobLogAsync(JobLog joblog)
{ {
return await _http.PutJsonAsync<JobLog>($"{Apiurl}/{joblog.JobLogId.ToString()}", joblog); return await PutJsonAsync<JobLog>($"{Apiurl}/{joblog.JobLogId.ToString()}", joblog);
} }
public async Task DeleteJobLogAsync(int jobLogId) public async Task DeleteJobLogAsync(int jobLogId)
{ {
await _http.DeleteAsync($"{Apiurl}/{jobLogId.ToString()}"); await DeleteAsync($"{Apiurl}/{jobLogId.ToString()}");
} }
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class JobService : ServiceBase, IJobService public class JobService : ServiceBase, IJobService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public JobService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public JobService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,37 +28,37 @@ namespace Oqtane.Services
public async Task<List<Job>> GetJobsAsync() public async Task<List<Job>> GetJobsAsync()
{ {
List<Job> jobs = await _http.GetJsonAsync<List<Job>>(Apiurl); List<Job> jobs = await GetJsonAsync<List<Job>>(Apiurl);
return jobs.OrderBy(item => item.Name).ToList(); return jobs.OrderBy(item => item.Name).ToList();
} }
public async Task<Job> GetJobAsync(int jobId) public async Task<Job> GetJobAsync(int jobId)
{ {
return await _http.GetJsonAsync<Job>($"{Apiurl}/{jobId.ToString()}"); return await GetJsonAsync<Job>($"{Apiurl}/{jobId.ToString()}");
} }
public async Task<Job> AddJobAsync(Job job) public async Task<Job> AddJobAsync(Job job)
{ {
return await _http.PostJsonAsync<Job>(Apiurl, job); return await PostJsonAsync<Job>(Apiurl, job);
} }
public async Task<Job> UpdateJobAsync(Job job) public async Task<Job> UpdateJobAsync(Job job)
{ {
return await _http.PutJsonAsync<Job>($"{Apiurl}/{job.JobId.ToString()}", job); return await PutJsonAsync<Job>($"{Apiurl}/{job.JobId.ToString()}", job);
} }
public async Task DeleteJobAsync(int jobId) public async Task DeleteJobAsync(int jobId)
{ {
await _http.DeleteAsync($"{Apiurl}/{jobId.ToString()}"); await DeleteAsync($"{Apiurl}/{jobId.ToString()}");
} }
public async Task StartJobAsync(int jobId) public async Task StartJobAsync(int jobId)
{ {
await _http.GetAsync($"{Apiurl}/start/{jobId.ToString()}"); await GetAsync($"{Apiurl}/start/{jobId.ToString()}");
} }
public async Task StopJobAsync(int jobId) public async Task StopJobAsync(int jobId)
{ {
await _http.GetAsync($"{Apiurl}/stop/{jobId.ToString()}"); await GetAsync($"{Apiurl}/stop/{jobId.ToString()}");
} }
} }
} }

View File

@ -12,13 +12,13 @@ namespace Oqtane.Services
{ {
public class LogService : ServiceBase, ILogService public class LogService : ServiceBase, ILogService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public LogService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public LogService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -30,12 +30,12 @@ namespace Oqtane.Services
public async Task<List<Log>> GetLogsAsync(int siteId, string level, string function, int rows) 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()}"); return await GetJsonAsync<List<Log>>($"{Apiurl}?siteid={siteId.ToString()}&level={level}&function={function}&rows={rows.ToString()}");
} }
public async Task<Log> GetLogAsync(int logId) public async Task<Log> GetLogAsync(int logId)
{ {
return await _http.GetJsonAsync<Log>($"{Apiurl}/{logId.ToString()}"); return await 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) 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)
@ -69,7 +69,7 @@ namespace Oqtane.Services
log.Message = message; log.Message = message;
log.MessageTemplate = ""; log.MessageTemplate = "";
log.Properties = JsonSerializer.Serialize(args); log.Properties = JsonSerializer.Serialize(args);
await _http.PostJsonAsync(CreateCrossTenantUrl(Apiurl, alias), log); await PostJsonAsync(CreateCrossTenantUrl(Apiurl, alias), log);
} }
} }
} }

View File

@ -17,7 +17,7 @@ namespace Oqtane.Services
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public ModuleDefinitionService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public ModuleDefinitionService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http; _http = http;
_siteState = siteState; _siteState = siteState;
@ -31,28 +31,28 @@ namespace Oqtane.Services
public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int siteId) public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int siteId)
{ {
List<ModuleDefinition> moduledefinitions = await _http.GetJsonAsync<List<ModuleDefinition>>($"{Apiurl}?siteid={siteId.ToString()}"); List<ModuleDefinition> moduledefinitions = await GetJsonAsync<List<ModuleDefinition>>($"{Apiurl}?siteid={siteId.ToString()}");
return moduledefinitions.OrderBy(item => item.Name).ToList(); return moduledefinitions.OrderBy(item => item.Name).ToList();
} }
public async Task<ModuleDefinition> GetModuleDefinitionAsync(int moduleDefinitionId, int siteId) public async Task<ModuleDefinition> GetModuleDefinitionAsync(int moduleDefinitionId, int siteId)
{ {
return await _http.GetJsonAsync<ModuleDefinition>($"{Apiurl}/{moduleDefinitionId.ToString()}?siteid={siteId.ToString()}"); return await GetJsonAsync<ModuleDefinition>($"{Apiurl}/{moduleDefinitionId.ToString()}?siteid={siteId.ToString()}");
} }
public async Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition) public async Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition)
{ {
await _http.PutJsonAsync($"{Apiurl}/{moduleDefinition.ModuleDefinitionId.ToString()}", moduleDefinition); await PutJsonAsync($"{Apiurl}/{moduleDefinition.ModuleDefinitionId.ToString()}", moduleDefinition);
} }
public async Task InstallModuleDefinitionsAsync() public async Task InstallModuleDefinitionsAsync()
{ {
await _http.GetJsonAsync<List<string>>($"{Apiurl}/install"); await GetJsonAsync<List<string>>($"{Apiurl}/install");
} }
public async Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId) public async Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId)
{ {
await _http.DeleteAsync($"{Apiurl}/{moduleDefinitionId.ToString()}?siteid={siteId.ToString()}"); await DeleteAsync($"{Apiurl}/{moduleDefinitionId.ToString()}?siteid={siteId.ToString()}");
} }
public async Task LoadModuleDefinitionsAsync(int siteId, Runtime runtime) public async Task LoadModuleDefinitionsAsync(int siteId, Runtime runtime)
@ -94,7 +94,7 @@ namespace Oqtane.Services
} }
public async Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId) public async Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId)
{ {
await _http.PostJsonAsync($"{Apiurl}?moduleid={moduleId.ToString()}", moduleDefinition); await PostJsonAsync($"{Apiurl}?moduleid={moduleId.ToString()}", moduleDefinition);
} }
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class ModuleService : ServiceBase, IModuleService public class ModuleService : ServiceBase, IModuleService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public ModuleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public ModuleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,7 +28,7 @@ namespace Oqtane.Services
public async Task<List<Module>> GetModulesAsync(int siteId) public async Task<List<Module>> GetModulesAsync(int siteId)
{ {
List<Module> modules = await _http.GetJsonAsync<List<Module>>($"{Apiurl}?siteid={siteId.ToString()}"); List<Module> modules = await GetJsonAsync<List<Module>>($"{Apiurl}?siteid={siteId.ToString()}");
modules = modules modules = modules
.OrderBy(item => item.Order) .OrderBy(item => item.Order)
.ToList(); .ToList();
@ -37,32 +37,32 @@ namespace Oqtane.Services
public async Task<Module> GetModuleAsync(int moduleId) public async Task<Module> GetModuleAsync(int moduleId)
{ {
return await _http.GetJsonAsync<Module>($"{Apiurl}/{moduleId.ToString()}"); return await GetJsonAsync<Module>($"{Apiurl}/{moduleId.ToString()}");
} }
public async Task<Module> AddModuleAsync(Module module) public async Task<Module> AddModuleAsync(Module module)
{ {
return await _http.PostJsonAsync<Module>(Apiurl, module); return await PostJsonAsync<Module>(Apiurl, module);
} }
public async Task<Module> UpdateModuleAsync(Module module) public async Task<Module> UpdateModuleAsync(Module module)
{ {
return await _http.PutJsonAsync<Module>($"{Apiurl}/{module.ModuleId.ToString()}", module); return await PutJsonAsync<Module>($"{Apiurl}/{module.ModuleId.ToString()}", module);
} }
public async Task DeleteModuleAsync(int moduleId) public async Task DeleteModuleAsync(int moduleId)
{ {
await _http.DeleteAsync($"{Apiurl}/{moduleId.ToString()}"); await DeleteAsync($"{Apiurl}/{moduleId.ToString()}");
} }
public async Task<bool> ImportModuleAsync(int moduleId, string content) public async Task<bool> ImportModuleAsync(int moduleId, string content)
{ {
return await _http.PostJsonAsync<bool>($"{Apiurl}/import?moduleid={moduleId}", content); return await PostJsonAsync<string,bool>($"{Apiurl}/import?moduleid={moduleId}", content);
} }
public async Task<string> ExportModuleAsync(int moduleId) public async Task<string> ExportModuleAsync(int moduleId)
{ {
return await _http.GetStringAsync($"{Apiurl}/export?moduleid={moduleId.ToString()}"); return await GetStringAsync($"{Apiurl}/export?moduleid={moduleId.ToString()}");
} }
} }
} }

View File

@ -10,13 +10,11 @@ namespace Oqtane.Services
{ {
public class NotificationService : ServiceBase, INotificationService public class NotificationService : ServiceBase, INotificationService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public NotificationService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public NotificationService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,28 +26,29 @@ namespace Oqtane.Services
public async Task<List<Notification>> GetNotificationsAsync(int siteId, string direction, int userId) public async Task<List<Notification>> GetNotificationsAsync(int siteId, string direction, int userId)
{ {
var notifications = await _http.GetJsonAsync<List<Notification>>($"{Apiurl}?siteid={siteId.ToString()}&direction={direction.ToLower()}&userid={userId.ToString()}"); var notifications = await GetJsonAsync<List<Notification>>($"{Apiurl}?siteid={siteId.ToString()}&direction={direction.ToLower()}&userid={userId.ToString()}");
return notifications.OrderByDescending(item => item.CreatedOn).ToList(); return notifications.OrderByDescending(item => item.CreatedOn).ToList();
} }
public async Task<Notification> GetNotificationAsync(int notificationId) public async Task<Notification> GetNotificationAsync(int notificationId)
{ {
return await _http.GetJsonAsync<Notification>($"{Apiurl}/{notificationId.ToString()}"); return await GetJsonAsync<Notification>($"{Apiurl}/{notificationId.ToString()}");
} }
public async Task<Notification> AddNotificationAsync(Notification notification) public async Task<Notification> AddNotificationAsync(Notification notification)
{ {
return await _http.PostJsonAsync<Notification>(Apiurl, notification); return await PostJsonAsync<Notification>(Apiurl, notification);
} }
public async Task<Notification> UpdateNotificationAsync(Notification notification) public async Task<Notification> UpdateNotificationAsync(Notification notification)
{ {
return await _http.PutJsonAsync<Notification>($"{Apiurl}/{notification.NotificationId.ToString()}", notification); return await PutJsonAsync<Notification>($"{Apiurl}/{notification.NotificationId.ToString()}", notification);
} }
public async Task DeleteNotificationAsync(int notificationId) public async Task DeleteNotificationAsync(int notificationId)
{ {
await _http.DeleteAsync($"{Apiurl}/{notificationId.ToString()}"); await DeleteAsync($"{Apiurl}/{notificationId.ToString()}");
} }
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class PackageService : ServiceBase, IPackageService public class PackageService : ServiceBase, IPackageService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public PackageService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public PackageService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,13 +28,13 @@ namespace Oqtane.Services
public async Task<List<Package>> GetPackagesAsync(string tag) public async Task<List<Package>> GetPackagesAsync(string tag)
{ {
List<Package> packages = await _http.GetJsonAsync<List<Package>>($"{Apiurl}?tag={tag}"); List<Package> packages = await GetJsonAsync<List<Package>>($"{Apiurl}?tag={tag}");
return packages.OrderByDescending(item => item.Downloads).ToList(); return packages.OrderByDescending(item => item.Downloads).ToList();
} }
public async Task DownloadPackageAsync(string packageId, string version, string folder) public async Task DownloadPackageAsync(string packageId, string version, string folder)
{ {
await _http.PostJsonAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}", null); await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}");
} }
} }
} }

View File

@ -8,13 +8,13 @@ namespace Oqtane.Services
{ {
public class PageModuleService : ServiceBase, IPageModuleService public class PageModuleService : ServiceBase, IPageModuleService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public PageModuleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public PageModuleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -26,32 +26,32 @@ namespace Oqtane.Services
public async Task<PageModule> GetPageModuleAsync(int pageModuleId) public async Task<PageModule> GetPageModuleAsync(int pageModuleId)
{ {
return await _http.GetJsonAsync<PageModule>($"{Apiurl}/{pageModuleId.ToString()}"); return await GetJsonAsync<PageModule>($"{Apiurl}/{pageModuleId.ToString()}");
} }
public async Task<PageModule> GetPageModuleAsync(int pageId, int moduleId) public async Task<PageModule> GetPageModuleAsync(int pageId, int moduleId)
{ {
return await _http.GetJsonAsync<PageModule>($"{Apiurl}/{pageId.ToString()}/{moduleId.ToString()}"); return await 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 PostJsonAsync<PageModule>(Apiurl, pageModule);
} }
public async Task<PageModule> UpdatePageModuleAsync(PageModule pageModule) public async Task<PageModule> UpdatePageModuleAsync(PageModule pageModule)
{ {
return await _http.PutJsonAsync<PageModule>($"{Apiurl}/{pageModule.PageModuleId.ToString()}", pageModule); return await PutJsonAsync<PageModule>($"{Apiurl}/{pageModule.PageModuleId.ToString()}", pageModule);
} }
public async Task UpdatePageModuleOrderAsync(int pageId, string pane) public async Task UpdatePageModuleOrderAsync(int pageId, string pane)
{ {
await _http.PutJsonAsync($"{Apiurl}/?pageid={pageId.ToString()}&pane={pane}", null); await PutAsync($"{Apiurl}/?pageid={pageId.ToString()}&pane={pane}");
} }
public async Task DeletePageModuleAsync(int pageModuleId) public async Task DeletePageModuleAsync(int pageModuleId)
{ {
await _http.DeleteAsync($"{Apiurl}/{pageModuleId.ToString()}"); await DeleteAsync($"{Apiurl}/{pageModuleId.ToString()}");
} }
} }
} }

View File

@ -12,13 +12,13 @@ namespace Oqtane.Services
{ {
public class PageService : ServiceBase, IPageService public class PageService : ServiceBase, IPageService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public PageService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public PageService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -30,26 +30,26 @@ namespace Oqtane.Services
public async Task<List<Page>> GetPagesAsync(int siteId) public async Task<List<Page>> GetPagesAsync(int siteId)
{ {
List<Page> pages = await _http.GetJsonAsync<List<Page>>($"{Apiurl}?siteid={siteId.ToString()}"); List<Page> pages = await GetJsonAsync<List<Page>>($"{Apiurl}?siteid={siteId.ToString()}");
pages = GetPagesHierarchy(pages); pages = GetPagesHierarchy(pages);
return pages; return pages;
} }
public async Task<Page> GetPageAsync(int pageId) public async Task<Page> GetPageAsync(int pageId)
{ {
return await _http.GetJsonAsync<Page>($"{Apiurl}/{pageId.ToString()}"); return await GetJsonAsync<Page>($"{Apiurl}/{pageId.ToString()}");
} }
public async Task<Page> GetPageAsync(int pageId, int userId) public async Task<Page> GetPageAsync(int pageId, int userId)
{ {
return await _http.GetJsonAsync<Page>($"{Apiurl}/{pageId.ToString()}?userid={userId.ToString()}"); return await GetJsonAsync<Page>($"{Apiurl}/{pageId.ToString()}?userid={userId.ToString()}");
} }
public async Task<Page> GetPageAsync(string path, int siteId) public async Task<Page> GetPageAsync(string path, int siteId)
{ {
try try
{ {
return await _http.GetJsonAsync<Page>($"{Apiurl}/path/{siteId.ToString()}?path={WebUtility.UrlEncode(path)}"); return await GetJsonAsync<Page>($"{Apiurl}/path/{siteId.ToString()}?path={WebUtility.UrlEncode(path)}");
} }
catch catch
{ {
@ -59,17 +59,17 @@ namespace Oqtane.Services
public async Task<Page> AddPageAsync(Page page) public async Task<Page> AddPageAsync(Page page)
{ {
return await _http.PostJsonAsync<Page>(Apiurl, page); return await PostJsonAsync<Page>(Apiurl, page);
} }
public async Task<Page> AddPageAsync(int pageId, int userId) public async Task<Page> AddPageAsync(int pageId, int userId)
{ {
return await _http.PostJsonAsync<Page>($"{Apiurl}/{pageId.ToString()}?userid={userId.ToString()}", null); return await PostJsonAsync<Page>($"{Apiurl}/{pageId.ToString()}?userid={userId.ToString()}", null);
} }
public async Task<Page> UpdatePageAsync(Page page) public async Task<Page> UpdatePageAsync(Page page)
{ {
return await _http.PutJsonAsync<Page>($"{Apiurl}/{page.PageId.ToString()}", page); return await PutJsonAsync<Page>($"{Apiurl}/{page.PageId.ToString()}", page);
} }
public async Task UpdatePageOrderAsync(int siteId, int pageId, int? parentId) public async Task UpdatePageOrderAsync(int siteId, int pageId, int? parentId)
@ -77,12 +77,12 @@ namespace Oqtane.Services
var parent = parentId == null var parent = parentId == null
? string.Empty ? string.Empty
: parentId.ToString(); : parentId.ToString();
await _http.PutJsonAsync($"{Apiurl}/?siteid={siteId.ToString()}&pageid={pageId.ToString()}&parentid={parent}", null); await PutAsync($"{Apiurl}/?siteid={siteId.ToString()}&pageid={pageId.ToString()}&parentid={parent}");
} }
public async Task DeletePageAsync(int pageId) public async Task DeletePageAsync(int pageId)
{ {
await _http.DeleteAsync($"{Apiurl}/{pageId.ToString()}"); await DeleteAsync($"{Apiurl}/{pageId.ToString()}");
} }
private static List<Page> GetPagesHierarchy(List<Page> pages) private static List<Page> GetPagesHierarchy(List<Page> pages)

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class ProfileService : ServiceBase, IProfileService public class ProfileService : ServiceBase, IProfileService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public ProfileService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public ProfileService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,27 +28,27 @@ namespace Oqtane.Services
public async Task<List<Profile>> GetProfilesAsync(int siteId) public async Task<List<Profile>> GetProfilesAsync(int siteId)
{ {
List<Profile> profiles = await _http.GetJsonAsync<List<Profile>>($"{Apiurl}?siteid={siteId.ToString()}"); List<Profile> profiles = await GetJsonAsync<List<Profile>>($"{Apiurl}?siteid={siteId.ToString()}");
return profiles.OrderBy(item => item.ViewOrder).ToList(); return profiles.OrderBy(item => item.ViewOrder).ToList();
} }
public async Task<Profile> GetProfileAsync(int profileId) public async Task<Profile> GetProfileAsync(int profileId)
{ {
return await _http.GetJsonAsync<Profile>($"{Apiurl}/{profileId.ToString()}"); return await GetJsonAsync<Profile>($"{Apiurl}/{profileId.ToString()}");
} }
public async Task<Profile> AddProfileAsync(Profile profile) public async Task<Profile> AddProfileAsync(Profile profile)
{ {
return await _http.PostJsonAsync<Profile>(Apiurl, profile); return await PostJsonAsync<Profile>(Apiurl, profile);
} }
public async Task<Profile> UpdateProfileAsync(Profile profile) public async Task<Profile> UpdateProfileAsync(Profile profile)
{ {
return await _http.PutJsonAsync<Profile>($"{Apiurl}/{profile.SiteId.ToString()}", profile); return await PutJsonAsync<Profile>($"{Apiurl}/{profile.SiteId.ToString()}", profile);
} }
public async Task DeleteProfileAsync(int profileId) public async Task DeleteProfileAsync(int profileId)
{ {
await _http.DeleteAsync($"{Apiurl}/{profileId.ToString()}"); await DeleteAsync($"{Apiurl}/{profileId.ToString()}");
} }
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class RoleService : ServiceBase, IRoleService public class RoleService : ServiceBase, IRoleService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public RoleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public RoleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,27 +28,27 @@ namespace Oqtane.Services
public async Task<List<Role>> GetRolesAsync(int siteId) public async Task<List<Role>> GetRolesAsync(int siteId)
{ {
List<Role> roles = await _http.GetJsonAsync<List<Role>>($"{Apiurl}?siteid={siteId.ToString()}"); List<Role> roles = await GetJsonAsync<List<Role>>($"{Apiurl}?siteid={siteId.ToString()}");
return roles.OrderBy(item => item.Name).ToList(); return roles.OrderBy(item => item.Name).ToList();
} }
public async Task<Role> GetRoleAsync(int roleId) public async Task<Role> GetRoleAsync(int roleId)
{ {
return await _http.GetJsonAsync<Role>($"{Apiurl}/{roleId.ToString()}"); return await GetJsonAsync<Role>($"{Apiurl}/{roleId.ToString()}");
} }
public async Task<Role> AddRoleAsync(Role role) public async Task<Role> AddRoleAsync(Role role)
{ {
return await _http.PostJsonAsync<Role>(Apiurl, role); return await PostJsonAsync<Role>(Apiurl, role);
} }
public async Task<Role> UpdateRoleAsync(Role role) public async Task<Role> UpdateRoleAsync(Role role)
{ {
return await _http.PutJsonAsync<Role>($"{Apiurl}/{role.RoleId.ToString()}", role); return await PutJsonAsync<Role>($"{Apiurl}/{role.RoleId.ToString()}", role);
} }
public async Task DeleteRoleAsync(int roleId) public async Task DeleteRoleAsync(int roleId)
{ {
await _http.DeleteAsync($"{Apiurl}/{roleId.ToString()}"); await DeleteAsync($"{Apiurl}/{roleId.ToString()}");
} }
} }
} }

View File

@ -1,10 +1,139 @@
using System; using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Oqtane.Models; using Oqtane.Models;
namespace Oqtane.Services namespace Oqtane.Services
{ {
public class ServiceBase public class ServiceBase
{ {
private readonly HttpClient _http;
protected ServiceBase(HttpClient client)
{
_http = client;
}
protected async Task GetAsync(string uri)
{
var response = await _http.GetAsync(uri);
CheckResponse(response);
}
protected async Task<string> GetStringAsync(string uri)
{
try
{
return await _http.GetStringAsync(uri);
}
catch (Exception e)
{
//TODO replace with logging
Console.WriteLine(e);
}
return default;
}
protected async Task<byte[]> GetByteArrayAsync(string uri)
{
try
{
return await _http.GetByteArrayAsync(uri);
}
catch (Exception e)
{
Console.WriteLine(e);
}
return default;
}
protected async Task<T> GetJsonAsync<T>(string uri)
{
var response = await _http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None);
if (CheckResponse(response) && ValidateJsonContent(response.Content))
{
return await response.Content.ReadFromJsonAsync<T>();
}
return default;
}
protected async Task PutAsync(string uri)
{
var response = await _http.PutAsync(uri, null);
CheckResponse(response);
}
protected async Task<T> PutJsonAsync<T>(string uri, T value)
{
return await PutJsonAsync<T, T>(uri, value);
}
protected async Task<TResult> PutJsonAsync<TValue, TResult>(string uri, TValue value)
{
var response = await _http.PutAsJsonAsync(uri, value);
if (CheckResponse(response) && ValidateJsonContent(response.Content))
{
var result = await response.Content.ReadFromJsonAsync<TResult>();
return result;
}
return default;
}
protected async Task PostAsync(string uri)
{
var response = await _http.PostAsync(uri, null);
CheckResponse(response);
}
protected async Task<T> PostJsonAsync<T>(string uri, T value)
{
return await PostJsonAsync<T, T>(uri, value);
}
protected async Task<TResult> PostJsonAsync<TValue, TResult>(string uri, TValue value)
{
var response = await _http.PostAsJsonAsync(uri, value);
if (CheckResponse(response) && ValidateJsonContent(response.Content))
{
var result = await response.Content.ReadFromJsonAsync<TResult>();
return result;
}
return default;
}
protected async Task DeleteAsync(string uri)
{
var response = await _http.DeleteAsync(uri);
CheckResponse(response);
}
private bool CheckResponse(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode) return true;
if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.NotFound)
{
//TODO: Log errors here
Console.WriteLine($"Response status: {response.StatusCode} {response.ReasonPhrase}");
}
return false;
}
private static bool ValidateJsonContent(HttpContent content)
{
var mediaType = content?.Headers.ContentType?.MediaType;
return mediaType != null && mediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase);
//TODO Missing content JSON validation
}
public static string CreateApiUrl(Alias alias, string absoluteUri, string serviceName) public static string CreateApiUrl(Alias alias, string absoluteUri, string serviceName)
{ {
@ -25,6 +154,7 @@ namespace Oqtane.Services
// build a url which ignores any subfolder for multi-tenancy // build a url which ignores any subfolder for multi-tenancy
apiurl = $"{uri.Scheme}://{uri.Authority}/~/"; apiurl = $"{uri.Scheme}://{uri.Authority}/~/";
} }
apiurl += $"api/{serviceName}"; apiurl += $"api/{serviceName}";
return apiurl; return apiurl;
@ -37,6 +167,7 @@ namespace Oqtane.Services
url += (url.Contains("?")) ? "&" : "?"; url += (url.Contains("?")) ? "&" : "?";
url += "aliasid=" + alias.AliasId.ToString(); url += "aliasid=" + alias.AliasId.ToString();
} }
return url; return url;
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class SettingService : ServiceBase, ISettingService public class SettingService : ServiceBase, ISettingService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public SettingService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public SettingService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -99,7 +99,7 @@ namespace Oqtane.Services
public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId) public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId)
{ {
var dictionary = new Dictionary<string, string>(); var dictionary = new Dictionary<string, string>();
var settings = await _http.GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId.ToString()}"); var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId.ToString()}");
foreach(Setting setting in settings.OrderBy(item => item.SettingName).ToList()) foreach(Setting setting in settings.OrderBy(item => item.SettingName).ToList())
{ {
@ -110,7 +110,7 @@ namespace Oqtane.Services
public async Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId) public async Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId)
{ {
var settingsList = await _http.GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId.ToString()}"); var settingsList = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId.ToString()}");
foreach (KeyValuePair<string, string> kvp in settings) foreach (KeyValuePair<string, string> kvp in settings)
{ {
@ -138,22 +138,22 @@ namespace Oqtane.Services
public async Task<Setting> GetSettingAsync(int settingId) public async Task<Setting> GetSettingAsync(int settingId)
{ {
return await _http.GetJsonAsync<Setting>($"{Apiurl}/{settingId.ToString()}"); return await GetJsonAsync<Setting>($"{Apiurl}/{settingId.ToString()}");
} }
public async Task<Setting> AddSettingAsync(Setting setting) public async Task<Setting> AddSettingAsync(Setting setting)
{ {
return await _http.PostJsonAsync<Setting>(Apiurl, setting); return await PostJsonAsync<Setting>(Apiurl, setting);
} }
public async Task<Setting> UpdateSettingAsync(Setting setting) public async Task<Setting> UpdateSettingAsync(Setting setting)
{ {
return await _http.PutJsonAsync<Setting>($"{Apiurl}/{setting.SettingId.ToString()}", setting); return await PutJsonAsync<Setting>($"{Apiurl}/{setting.SettingId.ToString()}", setting);
} }
public async Task DeleteSettingAsync(int settingId) public async Task DeleteSettingAsync(int settingId)
{ {
await _http.DeleteAsync($"{Apiurl}/{settingId.ToString()}"); await DeleteAsync($"{Apiurl}/{settingId.ToString()}");
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class SiteService : ServiceBase, ISiteService public class SiteService : ServiceBase, ISiteService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public SiteService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public SiteService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,28 +28,28 @@ namespace Oqtane.Services
public async Task<List<Site>> GetSitesAsync(Alias alias) public async Task<List<Site>> GetSitesAsync(Alias alias)
{ {
List<Site> sites = await _http.GetJsonAsync<List<Site>>(CreateCrossTenantUrl(Apiurl, alias)); List<Site> sites = await GetJsonAsync<List<Site>>(CreateCrossTenantUrl(Apiurl, alias));
return sites.OrderBy(item => item.Name).ToList(); return sites.OrderBy(item => item.Name).ToList();
} }
public async Task<Site> GetSiteAsync(int siteId, Alias alias) public async Task<Site> GetSiteAsync(int siteId, Alias alias)
{ {
return await _http.GetJsonAsync<Site>(CreateCrossTenantUrl($"{Apiurl}/{siteId.ToString()}", alias)); return await GetJsonAsync<Site>(CreateCrossTenantUrl($"{Apiurl}/{siteId.ToString()}", alias));
} }
public async Task<Site> AddSiteAsync(Site site, Alias alias) public async Task<Site> AddSiteAsync(Site site, Alias alias)
{ {
return await _http.PostJsonAsync<Site>(CreateCrossTenantUrl(Apiurl, alias), site); return await PostJsonAsync<Site>(CreateCrossTenantUrl(Apiurl, alias), site);
} }
public async Task<Site> UpdateSiteAsync(Site site, Alias alias) public async Task<Site> UpdateSiteAsync(Site site, Alias alias)
{ {
return await _http.PutJsonAsync<Site>(CreateCrossTenantUrl($"{Apiurl}/{site.SiteId.ToString()}", alias), site); return await PutJsonAsync<Site>(CreateCrossTenantUrl($"{Apiurl}/{site.SiteId.ToString()}", alias), site);
} }
public async Task DeleteSiteAsync(int siteId, Alias alias) public async Task DeleteSiteAsync(int siteId, Alias alias)
{ {
await _http.DeleteAsync(CreateCrossTenantUrl($"{Apiurl}/{siteId.ToString()}", alias)); await DeleteAsync(CreateCrossTenantUrl($"{Apiurl}/{siteId.ToString()}", alias));
} }
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class SiteTemplateService : ServiceBase, ISiteTemplateService public class SiteTemplateService : ServiceBase, ISiteTemplateService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public SiteTemplateService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public SiteTemplateService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,7 +28,7 @@ namespace Oqtane.Services
public async Task<List<SiteTemplate>> GetSiteTemplatesAsync() public async Task<List<SiteTemplate>> GetSiteTemplatesAsync()
{ {
List<SiteTemplate> siteTemplates = await _http.GetJsonAsync<List<SiteTemplate>>(Apiurl); List<SiteTemplate> siteTemplates = await GetJsonAsync<List<SiteTemplate>>(Apiurl);
return siteTemplates.OrderBy(item => item.Name).ToList(); return siteTemplates.OrderBy(item => item.Name).ToList();
} }
} }

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class SqlService : ServiceBase, ISqlService public class SqlService : ServiceBase, ISqlService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public SqlService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public SqlService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,7 +28,7 @@ namespace Oqtane.Services
public async Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery) public async Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery)
{ {
return await _http.PostJsonAsync<SqlQuery>(Apiurl, sqlquery); return await PostJsonAsync<SqlQuery>(Apiurl, sqlquery);
} }
} }
} }

View File

@ -0,0 +1,32 @@
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
using System.Collections.Generic;
namespace Oqtane.Services
{
public class SystemService : ServiceBase, ISystemService
{
private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager;
public SystemService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{
_siteState = siteState;
_navigationManager = navigationManager;
}
private string Apiurl
{
get { return CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "System"); }
}
public async Task<Dictionary<string, string>> GetSystemInfoAsync()
{
return await GetJsonAsync<Dictionary<string, string>>(Apiurl);
}
}
}

View File

@ -10,13 +10,13 @@ namespace Oqtane.Services
{ {
public class TenantService : ServiceBase, ITenantService public class TenantService : ServiceBase, ITenantService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public TenantService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public TenantService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -28,28 +28,28 @@ namespace Oqtane.Services
public async Task<List<Tenant>> GetTenantsAsync() public async Task<List<Tenant>> GetTenantsAsync()
{ {
List<Tenant> tenants = await _http.GetJsonAsync<List<Tenant>>(Apiurl); List<Tenant> tenants = await GetJsonAsync<List<Tenant>>(Apiurl);
return tenants.OrderBy(item => item.Name).ToList(); return tenants.OrderBy(item => item.Name).ToList();
} }
public async Task<Tenant> GetTenantAsync(int tenantId) public async Task<Tenant> GetTenantAsync(int tenantId)
{ {
return await _http.GetJsonAsync<Tenant>($"{Apiurl}/{tenantId.ToString()}"); return await GetJsonAsync<Tenant>($"{Apiurl}/{tenantId.ToString()}");
} }
public async Task<Tenant> AddTenantAsync(Tenant tenant) public async Task<Tenant> AddTenantAsync(Tenant tenant)
{ {
return await _http.PostJsonAsync<Tenant>(Apiurl, tenant); return await PostJsonAsync<Tenant>(Apiurl, tenant);
} }
public async Task<Tenant> UpdateTenantAsync(Tenant tenant) public async Task<Tenant> UpdateTenantAsync(Tenant tenant)
{ {
return await _http.PutJsonAsync<Tenant>($"{Apiurl}/{tenant.TenantId.ToString()}", tenant); return await PutJsonAsync<Tenant>($"{Apiurl}/{tenant.TenantId.ToString()}", tenant);
} }
public async Task DeleteTenantAsync(int tenantId) public async Task DeleteTenantAsync(int tenantId)
{ {
await _http.DeleteAsync($"{Apiurl}/{tenantId.ToString()}"); await DeleteAsync($"{Apiurl}/{tenantId.ToString()}");
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace Oqtane.Services
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public ThemeService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public ThemeService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http; _http = http;
_siteState = siteState; _siteState = siteState;
@ -30,7 +30,7 @@ namespace Oqtane.Services
public async Task<List<Theme>> GetThemesAsync() public async Task<List<Theme>> GetThemesAsync()
{ {
List<Theme> themes = await _http.GetJsonAsync<List<Theme>>(Apiurl); List<Theme> themes = await GetJsonAsync<List<Theme>>(Apiurl);
// get list of loaded assemblies // get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
@ -105,12 +105,12 @@ namespace Oqtane.Services
public async Task InstallThemesAsync() public async Task InstallThemesAsync()
{ {
await _http.GetJsonAsync<List<string>>($"{Apiurl}/install"); await GetJsonAsync<List<string>>($"{Apiurl}/install");
} }
public async Task DeleteThemeAsync(string themeName) public async Task DeleteThemeAsync(string themeName)
{ {
await _http.DeleteAsync($"{Apiurl}/{themeName}"); await DeleteAsync($"{Apiurl}/{themeName}");
} }
} }
} }

View File

@ -9,13 +9,13 @@ namespace Oqtane.Services
{ {
public class UserRoleService : ServiceBase, IUserRoleService public class UserRoleService : ServiceBase, IUserRoleService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public UserRoleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public UserRoleService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -27,27 +27,27 @@ namespace Oqtane.Services
public async Task<List<UserRole>> GetUserRolesAsync(int siteId) public async Task<List<UserRole>> GetUserRolesAsync(int siteId)
{ {
return await _http.GetJsonAsync<List<UserRole>>($"{Apiurl}?siteid={siteId.ToString()}"); return await GetJsonAsync<List<UserRole>>($"{Apiurl}?siteid={siteId.ToString()}");
} }
public async Task<UserRole> GetUserRoleAsync(int userRoleId) public async Task<UserRole> GetUserRoleAsync(int userRoleId)
{ {
return await _http.GetJsonAsync<UserRole>($"{Apiurl}/{userRoleId.ToString()}"); return await GetJsonAsync<UserRole>($"{Apiurl}/{userRoleId.ToString()}");
} }
public async Task<UserRole> AddUserRoleAsync(UserRole userRole) public async Task<UserRole> AddUserRoleAsync(UserRole userRole)
{ {
return await _http.PostJsonAsync<UserRole>(Apiurl, userRole); return await PostJsonAsync<UserRole>(Apiurl, userRole);
} }
public async Task<UserRole> UpdateUserRoleAsync(UserRole userRole) public async Task<UserRole> UpdateUserRoleAsync(UserRole userRole)
{ {
return await _http.PutJsonAsync<UserRole>($"{Apiurl}/{userRole.UserRoleId.ToString()}", userRole); return await PutJsonAsync<UserRole>($"{Apiurl}/{userRole.UserRoleId.ToString()}", userRole);
} }
public async Task DeleteUserRoleAsync(int userRoleId) public async Task DeleteUserRoleAsync(int userRoleId)
{ {
await _http.DeleteAsync($"{Apiurl}/{userRoleId.ToString()}"); await DeleteAsync($"{Apiurl}/{userRoleId.ToString()}");
} }
} }
} }

View File

@ -8,13 +8,11 @@ namespace Oqtane.Services
{ {
public class UserService : ServiceBase, IUserService public class UserService : ServiceBase, IUserService
{ {
private readonly HttpClient _http;
private readonly SiteState _siteState; private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
public UserService(HttpClient http, SiteState siteState, NavigationManager navigationManager) public UserService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http)
{ {
_http = http;
_siteState = siteState; _siteState = siteState;
_navigationManager = navigationManager; _navigationManager = navigationManager;
} }
@ -26,72 +24,58 @@ namespace Oqtane.Services
public async Task<User> GetUserAsync(int userId, int siteId) public async Task<User> GetUserAsync(int userId, int siteId)
{ {
return await _http.GetJsonAsync<User>($"{Apiurl}/{userId.ToString()}?siteid={siteId.ToString()}"); return await GetJsonAsync<User>($"{Apiurl}/{userId}?siteid={siteId}");
} }
public async Task<User> GetUserAsync(string username, int siteId) public async Task<User> GetUserAsync(string username, int siteId)
{ {
return await _http.GetJsonAsync<User>($"{Apiurl}/name/{username}?siteid={siteId.ToString()}"); return await GetJsonAsync<User>($"{Apiurl}/name/{username}?siteid={siteId}");
} }
public async Task<User> AddUserAsync(User user) public async Task<User> AddUserAsync(User user)
{ {
try return await PostJsonAsync<User>(Apiurl, user);
{
return await _http.PostJsonAsync<User>(Apiurl, user);
}
catch
{
return null;
}
} }
public async Task<User> AddUserAsync(User user, Alias alias) public async Task<User> AddUserAsync(User user, Alias alias)
{ {
try return await PostJsonAsync<User>(CreateCrossTenantUrl(Apiurl, alias), user);
{
return await _http.PostJsonAsync<User>(CreateCrossTenantUrl(Apiurl, alias), user);
}
catch
{
return null;
}
} }
public async Task<User> UpdateUserAsync(User user) public async Task<User> UpdateUserAsync(User user)
{ {
return await _http.PutJsonAsync<User>($"{Apiurl}/{user.UserId.ToString()}", user); return await PutJsonAsync<User>($"{Apiurl}/{user.UserId}", user);
} }
public async Task DeleteUserAsync(int userId) public async Task DeleteUserAsync(int userId)
{ {
await _http.DeleteAsync($"{Apiurl}/{userId.ToString()}"); await DeleteAsync($"{Apiurl}/{userId}");
} }
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 PostJsonAsync<User>($"{Apiurl}/login?setcookie={setCookie}&persistent={isPersistent}", user);
} }
public async Task LogoutUserAsync(User user) 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", user); await PostJsonAsync($"{Apiurl}/logout", user);
} }
public async Task<User> VerifyEmailAsync(User user, string token) public async Task<User> VerifyEmailAsync(User user, string token)
{ {
return await _http.PostJsonAsync<User>($"{Apiurl}/verify?token={token}", user); return await PostJsonAsync<User>($"{Apiurl}/verify?token={token}", user);
} }
public async Task ForgotPasswordAsync(User user) public async Task ForgotPasswordAsync(User user)
{ {
await _http.PostJsonAsync($"{Apiurl}/forgot", user); await PostJsonAsync($"{Apiurl}/forgot", user);
} }
public async Task<User> ResetPasswordAsync(User user, string token) public async Task<User> ResetPasswordAsync(User user, string token)
{ {
return await _http.PostJsonAsync<User>($"{Apiurl}/reset?token={token}", user); return await PostJsonAsync<User>($"{Apiurl}/reset?token={token}", user);
} }
} }
} }

View File

@ -1,14 +1,27 @@
@namespace Oqtane.Themes.BlazorTheme @namespace Oqtane.Themes.BlazorTheme
@inherits ThemeBase @inherits ThemeBase
<div class="breadcrumbs">
<Breadcrumbs />
</div>
<div class="sidebar"> <div class="sidebar">
<div align="center"><Logo /></div> <nav class="navbar">
<Logo />
<button class="navbar-toggler" aria-expanded="false" aria-controls="navbarSupportedContent"
aria-label="Toggle navigation" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<Menu Orientation="Vertical" /> <Menu Orientation="Vertical" />
</div> </div>
</nav>
</div>
<div class="main"> <div class="main">
<div class="top-row px-4"> <div class="top-row px-4">
<Breadcrumbs /> <div class="ml-md-auto"><UserProfile /> <Login /> <ControlPanel /></div> <div class="ml-md-auto"><UserProfile /> <Login /> <ControlPanel /></div>
</div> </div>
<div class="container"> <div class="container">
<div class="row px-4"> <div class="row px-4">

View File

@ -1,32 +1,34 @@
@namespace Oqtane.Themes.Controls @namespace Oqtane.Themes.Controls
@inherits ThemeControlBase @inherits ThemeControlBase
@if (breadcrumbs != string.Empty) @if (BreadCrumbPages.Any())
{ {
@((MarkupString)breadcrumbs) <ol class="breadcrumb">
@foreach (var p in BreadCrumbPages)
{
<li class="breadcrumb-item @ActiveClass(p)">
<a href="@NavigateUrl(p.Path)">@p.Name</a>
</li>
}
</ol>
} }
@code { @code {
string breadcrumbs = string.Empty;
protected override void OnParametersSet() protected IEnumerable<Page> BreadCrumbPages => GetBreadCrumbPages().Reverse().ToList();
protected string ActiveClass(Page page)
{ {
breadcrumbs = string.Empty; return (page.PageId == PageState.Page.PageId) ? " active" : string.Empty;
int? pageid = PageState.Page.PageId;
for (int i = PageState.Pages.Count - 1; i >= 0; i--)
{
var p = PageState.Pages[i];
if (p.PageId == pageid)
{
breadcrumbs = "<li class=\"breadcrumb-item" + ((p.PageId == PageState.Page.PageId) ? " active" : string.Empty) +
"\"><a href=\"" + NavigateUrl(p.Path) + "\">" + p.Name + "</a></li>" + breadcrumbs;
pageid = p.ParentId;
}
} }
if (breadcrumbs != "") private IEnumerable<Page> GetBreadCrumbPages()
{ {
breadcrumbs = "<ol class=\"breadcrumb\">" + breadcrumbs + "</ol>"; var page = PageState.Page;
} do
{
yield return page;
page = PageState.Pages.FirstOrDefault(p => page != null && p.PageId == page.ParentId);
} while (page != null);
} }
} }

View File

@ -87,14 +87,27 @@
@if (_moduleDefinitions != null) @if (_moduleDefinitions != null)
{ {
<select class="form-control" @onchange="(e => CategoryChanged(e))"> <select class="form-control" @onchange="(e => CategoryChanged(e))">
<option value="-">&lt;Common Modules&gt;</option>
@foreach (var category in _categories) @foreach (var category in _categories)
{ {
<option value="@category">@category</option> if (category == _category)
{
<option value="@category" selected>@category Modules</option>
}
else
{
<option value="@category">@category Modules</option>
}
} }
</select> </select>
<select class="form-control" @bind="@_moduleDefinitionName"> <select class="form-control" @onchange="(e => ModuleChanged(e))">
@if (_moduleDefinitionName == "-")
{
<option value="-" selected>&lt;Select Module&gt;</option>
}
else
{
<option value="-">&lt;Select Module&gt;</option> <option value="-">&lt;Select Module&gt;</option>
}
@foreach (var moduledefinition in _moduleDefinitions) @foreach (var moduledefinition in _moduleDefinitions)
{ {
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions)) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
@ -103,6 +116,7 @@
} }
} }
</select> </select>
@((MarkupString)@_description)
} }
} }
else else
@ -191,7 +205,7 @@
@if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions)) @if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions))
{ {
<button type="button" class="btn @ButtonClass" @onclick="ShowControlPanel"> <button type="button" class="btn @ButtonClass" @onclick="ShowControlPanel">
<span class="oi oi-menu"></span> <span class="oi oi-cog"></span>
</button> </button>
} }
@ -207,6 +221,8 @@
private List<Module> _modules = new List<Module>(); private List<Module> _modules = new List<Module>();
private Dictionary<string, string> _containers = new Dictionary<string, string>(); private Dictionary<string, string> _containers = new Dictionary<string, string>();
private string _moduleDefinitionName = "-"; private string _moduleDefinitionName = "-";
private string _category = "Common";
private string _description = "";
private string _pane = ""; private string _pane = "";
private string _title = ""; private string _title = "";
private string _containerType = ""; private string _containerType = "";
@ -267,6 +283,7 @@
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
_categories = new List<string>();
foreach (ModuleDefinition moduledefinition in _allModuleDefinitions) foreach (ModuleDefinition moduledefinition in _allModuleDefinitions)
{ {
if (moduledefinition.Categories != "") if (moduledefinition.Categories != "")
@ -281,23 +298,34 @@
} }
} }
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories == "").ToList(); _category = "Common";
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
_moduleDefinitionName = "-";
_description = "";
} }
} }
private void CategoryChanged(ChangeEventArgs e) private void CategoryChanged(ChangeEventArgs e)
{ {
var category = (string) e.Value; _category = (string) e.Value;
if (category == "-") _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
_moduleDefinitionName = "-";
_description = "";
StateHasChanged();
}
private void ModuleChanged(ChangeEventArgs e)
{ {
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories == "").ToList(); _moduleDefinitionName = (string)e.Value;
if (_moduleDefinitionName != "-")
{
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == _moduleDefinitionName);
_description = "<br /><div class=\"alert alert-info\" role=\"alert\">" + moduleDefinition.Description + "</div>";
} }
else else
{ {
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(category)).ToList(); _description = "";
} }
_moduleDefinitionName = "-";
StateHasChanged(); StateHasChanged();
} }
@ -371,6 +399,7 @@
_message = "<br /><div class=\"alert alert-success\" role=\"alert\">Module Added To Page</div>"; _message = "<br /><div class=\"alert alert-success\" role=\"alert\">Module Added To Page</div>";
_moduleDefinitionName = "-"; _moduleDefinitionName = "-";
_description = "";
_pane = ""; _pane = "";
_title = ""; _title = "";
_containerType = ""; _containerType = "";

View File

@ -1,9 +1,5 @@
@namespace Oqtane.Themes.Controls @namespace Oqtane.Themes.Controls
@inherits ThemeControlBase @inherits LoginBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IJSRuntime jsRuntime
@inject IServiceProvider ServiceProvider
<AuthorizeView> <AuthorizeView>
<Authorizing> <Authorizing>
@ -16,38 +12,3 @@
<button type="button" class="btn btn-primary" @onclick="LoginUser">Login</button> <button type="button" class="btn btn-primary" @onclick="LoginUser">Login</button>
</NotAuthorized> </NotAuthorized>
</AuthorizeView> </AuthorizeView>
@code {
private void LoginUser()
{
var returnurl = PageState.Alias.Path;
if (PageState.Page.Path != "/")
{
returnurl += "/" + PageState.Page.Path;
}
NavigationManager.NavigateTo(NavigateUrl("login", "returnurl=" + returnurl));
}
private async Task LogoutUser()
{
await UserService.LogoutUserAsync(PageState.User);
if (PageState.Runtime == Runtime.Server)
{
// server-side Blazor
var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, returnurl = (PageState.Alias.Path + "/" + PageState.Page.Path) };
await interop.SubmitForm("/pages/logout/", fields);
}
else
{
// client-side Blazor
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload"));
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Oqtane.Providers;
using Oqtane.Services;
using Oqtane.UI;
namespace Oqtane.Themes.Controls
{
public class LoginBase : ThemeControlBase
{
[Inject] public NavigationManager NavigationManager {get;set;}
[Inject]public IUserService UserService {get;set;}
[Inject]public IJSRuntime jsRuntime {get;set;}
[Inject]public IServiceProvider ServiceProvider {get;set;}
protected void LoginUser()
{
var returnurl = PageState.Alias.Path;
if (PageState.Page.Path != "/")
{
returnurl += "/" + PageState.Page.Path;
}
NavigationManager.NavigateTo(NavigateUrl("login", "returnurl=" + returnurl));
}
protected async Task LogoutUser()
{
await UserService.LogoutUserAsync(PageState.User);
if (PageState.Runtime == Runtime.Server)
{
// server-side Blazor
var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, returnurl = (PageState.Alias.Path + "/" + PageState.Page.Path) };
await interop.SubmitForm("/pages/logout/", fields);
}
else
{
// client-side Blazor
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload"));
}
}
}
}

View File

@ -2,17 +2,20 @@
@inherits ThemeControlBase @inherits ThemeControlBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@((MarkupString)logo) @if (PageState.Site.LogoFileId != null)
{
<a href="@Href">
<img class="img-fluid" src="@ContentUrl(PageState.Site.LogoFileId.Value)" alt="@PageState.Site.Name"/>
</a>
}
@code { @code {
string logo = ""; string Href
protected override void OnParametersSet()
{ {
if (PageState.Site.LogoFileId != null) get
{ {
var uri = new Uri(NavigationManager.Uri); var uri = new Uri(NavigationManager.Uri);
logo = "<a href=\"" + uri.Scheme + "://" + uri.Authority + "\"><img src=\"" + ContentUrl(PageState.Site.LogoFileId.Value) + "\" alt=\"" + PageState.Site.Name + "\"/></a>"; return $"{uri.Scheme}://{uri.Authority}";
} }
} }
} }

View File

@ -1,133 +1,20 @@
@namespace Oqtane.Themes.Controls @namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@if (menu != string.Empty) @switch (Orientation)
{ {
<div class="app-menu"> case "Horizontal":
@((MarkupString)menu) <MenuHorizontal/>
</div> break;
default: // Vertical
{
<MenuVertical/>
break;
}
} }
@code{ @code{
private string menu = string.Empty;
[Parameter] [Parameter]
public string Orientation { get; set; } public string Orientation { get; set; }
protected override void OnParametersSet()
{
switch (Orientation)
{
case "Horizontal":
CreateHorizontalMenu();
break;
default: // Vertical
CreateVerticalMenu();
break;
}
}
private void CreateVerticalMenu()
{
var level = -1;
var securitylevel = int.MaxValue;
menu = "<ul class=\"nav flex-column\">\n";
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted))
{
if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions) && p.Level <= securitylevel)
{
securitylevel = int.MaxValue;
menu += "<li class=\"nav-item px-3\">";
if (string.IsNullOrEmpty(p.Url))
{
menu += "<a href=\"" + NavigateUrl(p.Path) + "\" class=\"nav-link\" style=\"padding-left: " + ((p.Level + 1) * 15).ToString() + "px !important;\">";
}
else
{
string target = String.Empty;
if (p.Url.StartsWith("http"))
{
target = " target=\"_new\"";
}
menu += "<a href=\"" + p.Url + "\" class=\"nav-link\" style=\"padding-left: " + ((p.Level + 1) * 15).ToString() + "px !important;\"" + target + ">";
}
if (p.HasChildren)
{
menu += "<i class=\"oi oi-chevron-right\"></i>";
}
if (p.Icon != string.Empty)
{
menu += "<span class=\"oi oi-" + p.Icon + "\" aria-hidden=\"true\"></span>";
}
menu += p.Name;
menu += "</a>\n";
menu += "</li>\n";
level = p.Level;
}
else
{
if (securitylevel == int.MaxValue)
{
securitylevel = p.Level;
}
}
}
menu += "</ul>";
}
private void CreateHorizontalMenu()
{
var url = String.Empty;
var target = String.Empty;
menu = "<button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#Menu\" aria-controls=\"Menu\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"><span class=\"navbar-toggler-icon\"></span></button>";
menu += "<div class=\"collapse navbar-collapse\" id=\"Menu\">";
menu += "<ul class=\"navbar-nav mr-auto\">";
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted))
{
if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions) && p.ParentId == PageState.Page.ParentId && p.Level == PageState.Page.Level)
{
if (string.IsNullOrEmpty(p.Url))
{
url = NavigateUrl(p.Path);
target = String.Empty;
}
else
{
url = p.Url;
if (p.Url.StartsWith("http"))
{
target = " target=\"_new\"";
}
}
if (p.PageId == PageState.Page.PageId)
{
menu += "<li class=\"nav-item active\">" +
"<a class=\"nav-link\" href=\"" + NavigateUrl(p.Path) + "\">" +
((p.Icon != string.Empty) ? "<span class=\"oi oi-" + p.Icon + "\" aria-hidden=\"true\"></span> " : string.Empty) +
p.Name + " <span class=\"sr-only\">(current)</span></a></li>";
}
else
{
menu += "<li class=\"nav-item\">" +
"<a class=\"nav-link\" href=\"" + NavigateUrl(p.Path) + "\">" +
((p.Icon != string.Empty) ? "<span class=\"oi oi-" + p.Icon + "\" aria-hidden=\"true\"></span> " : string.Empty) +
p.Name + "</a></li>";
}
}
}
menu += "</ul>";
menu += "</div>";
}
} }

View File

@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using Oqtane.Models;
using Oqtane.Security;
using Oqtane.Shared;
namespace Oqtane.Themes.Controls
{
public class MenuBase : ThemeControlBase
{
protected IEnumerable<Page> MenuPages => GetMenuPages().ToList();
protected string GetTarget(Page page)
{
return page.Url != null && page.Url.StartsWith("http") ? "_new" : string.Empty;
}
protected string GetUrl(Page page)
{
return string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
}
private IEnumerable<Page> GetMenuPages()
{
var securityLevel = int.MaxValue;
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted))
{
if (p.Level <= securityLevel && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
securityLevel = int.MaxValue;
yield return p;
}
else
{
if (securityLevel == int.MaxValue)
{
securityLevel = p.Level;
}
}
}
}
}
}

View File

@ -0,0 +1,42 @@
@namespace Oqtane.Themes.Controls
@inherits MenuBase
@if (MenuPages.Any())
{
<div class="app-menu">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#Menu" aria-controls="Menu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="Menu">
<ul class="navbar-nav mr-auto">
@foreach (var p in MenuPages)
{
if (p.PageId == PageState.Page.PageId)
{
<li class="nav-item active">
<a class="nav-link" href="@NavigateUrl(p.Path)">
@if (p.Icon != string.Empty)
{
<span class="oi oi-@p.Icon" aria-hidden="true"></span>
}
@p.Name<span class="sr-only">(current)</span>
</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link" href="@NavigateUrl(p.Path)">
@if (p.Icon != string.Empty)
{
<span class="oi oi-@p.Icon" aria-hidden="true"></span>
}
@p.Name
</a>
</li>
}
}
</ul>
</div>
</div>
}

View File

@ -0,0 +1,27 @@
@namespace Oqtane.Themes.Controls
@inherits MenuBase
@if (MenuPages.Any())
{
<div class="app-menu">
<ul class="nav flex-column">
@foreach (var p in MenuPages)
{
<li class="nav-item px-3">
<a href="@GetUrl(p)" class="nav-link" style="padding-left:@((p.Level + 1) * 15)px !important;" target="@GetTarget(p)">
@if (p.HasChildren)
{
<i class="oi oi-chevron-right"></i>
}
@if (p.Icon != string.Empty)
{
<span class="oi oi-@p.Icon" aria-hidden="true"></span>
}
@p.Name
</a>
</li>
}
</ul>
</div>
}

View File

@ -1,135 +1,20 @@
@namespace Oqtane.Themes.Controls @namespace Oqtane.Themes.Controls
@inherits ContainerBase @inherits ModuleActionsBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IPageModuleService PageModuleService
@if (PageState.EditMode && !PageState.Page.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions)) @if (PageState.EditMode && !PageState.Page.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{ {
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a> <a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
<div class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 37px, 0px);"> <div class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 37px, 0px);">
@foreach (var action in actions) @foreach (var action in Actions)
{ {
if (action.Action != "") if (string.IsNullOrEmpty(action.Name))
{ {
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action.Action))">@action.Name</a> <div class="dropdown-divider"></div>
} }
else else
{ {
<div class="dropdown-divider"></div> <a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">@action.Name</a>
} }
} }
</div> </div>
} }
@code {
private List<ActionViewModel> actions;
protected override void OnParametersSet()
{
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{
actions = new List<ActionViewModel>();
actions.Add(new ActionViewModel { Action = "settings", Name = "Manage Settings" });
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerAssemblyName != "")
{
actions.Add(new ActionViewModel { Action = "import", Name = "Import Content" });
actions.Add(new ActionViewModel { Action = "export", Name = "Export Content" });
}
actions.Add(new ActionViewModel { Action = "delete", Name = "Delete Module" });
actions.Add(new ActionViewModel { Action = "", Name = "" });
if (ModuleState.PaneModuleIndex > 0)
{
actions.Add(new ActionViewModel { Action = "<<", Name = "Move To Top" });
}
if (ModuleState.PaneModuleIndex > 0)
{
actions.Add(new ActionViewModel { Action = "<", Name = "Move Up" });
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actions.Add(new ActionViewModel { Action = ">", Name = "Move Down" });
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actions.Add(new ActionViewModel { Action = ">>", Name = "Move To Bottom" });
}
foreach (string pane in PageState.Page.Panes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
if (pane != ModuleState.Pane)
{
actions.Add(new ActionViewModel { Action = pane, Name = "Move To " + pane + " Pane" });
}
}
}
}
protected async Task ModuleAction(string action)
{
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
string url = NavigateUrl();
switch (action)
{
case "<<":
pagemodule.Order = 0;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case "<":
pagemodule.Order -= 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case ">":
pagemodule.Order += 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case ">>":
pagemodule.Order = int.MaxValue;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case "settings":
url = EditUrl(pagemodule.ModuleId, "Settings");
break;
case "import":
url = EditUrl(pagemodule.ModuleId, "Import");
break;
case "export":
url = EditUrl(pagemodule.ModuleId, "Export");
break;
case "delete":
pagemodule.IsDeleted = true;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
default: // move to pane
string pane = pagemodule.Pane;
pagemodule.Pane = action;
pagemodule.Order = int.MaxValue; // add to bottom of pane
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pane);
break;
}
NavigationManager.NavigateTo(url);
}
}
public class ActionViewModel
{
public string Action { set; get; }
public string Name { set; get; }
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Models;
using Oqtane.Security;
using Oqtane.Services;
using Oqtane.Shared;
// ReSharper disable UnassignedGetOnlyAutoProperty
// ReSharper disable MemberCanBePrivate.Global
namespace Oqtane.Themes.Controls
{
public class ModuleActionsBase : ContainerBase
{
[Inject] public NavigationManager NavigationManager { get; set; }
[Inject] public IPageModuleService PageModuleService { get; set; }
protected List<ActionViewModel> Actions;
protected override void OnParametersSet()
{
Actions = GetActions();
}
protected virtual List<ActionViewModel> GetActions()
{
var actionList = new List<ActionViewModel>();
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions))
{
actionList.Add(new ActionViewModel {Name = "Manage Settings", Action = async (u, m) => await Settings(u, m)});
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "")
{
actionList.Add(new ActionViewModel {Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import")});
actionList.Add(new ActionViewModel {Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export")});
}
actionList.Add(new ActionViewModel {Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m)});
actionList.Add(new ActionViewModel {Name = ""});
if (ModuleState.PaneModuleIndex > 0)
{
actionList.Add(new ActionViewModel {Name = "Move To Top", Action = async (s, m) => await MoveTop(s, m)});
}
if (ModuleState.PaneModuleIndex > 0)
{
actionList.Add(new ActionViewModel {Name = "Move Up", Action = async (s, m) => await MoveUp(s, m)});
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actionList.Add(new ActionViewModel {Name = "Move Down", Action = async (s, m) => await MoveDown(s, m)});
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actionList.Add(new ActionViewModel {Name = "Move To Bottom", Action = async (s, m) => await MoveBottom(s, m)});
}
foreach (string pane in PageState.Page.Panes.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries))
{
if (pane != ModuleState.Pane)
{
actionList.Add(new ActionViewModel {Name = "Move To " + pane + " Pane", Action = async (s, m) => await MoveToPane(s, pane, m)});
}
}
}
return actionList;
}
private async Task<string> EditUrlAsync(string url, int moduleId, string import)
{
await Task.Yield();
EditUrl(moduleId, import);
return url;
}
protected async Task ModuleAction(ActionViewModel action)
{
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions))
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
string url = NavigateUrl();
if (action.Action != null)
{
url = await action.Action(url, pagemodule);
}
NavigationManager.NavigateTo(url);
}
}
private async Task<string> MoveToPane(string url, string newPane, PageModule pagemodule)
{
string oldPane = pagemodule.Pane;
pagemodule.Pane = newPane;
pagemodule.Order = int.MaxValue; // add to bottom of pane
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, oldPane);
return url;
}
private async Task<string> DeleteModule(string url, PageModule pagemodule)
{
pagemodule.IsDeleted = true;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return url;
}
private async Task<string> Settings(string url, PageModule pagemodule)
{
await Task.Yield();
url = EditUrl(pagemodule.ModuleId, "Settings");
return url;
}
private async Task<string> MoveTop(string s, PageModule pagemodule)
{
pagemodule.Order = 0;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
private async Task<string> MoveBottom(string s, PageModule pagemodule)
{
pagemodule.Order = int.MaxValue;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
private async Task<string> MoveUp(string s, PageModule pagemodule)
{
pagemodule.Order -= 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
private async Task<string> MoveDown(string s, PageModule pagemodule)
{
pagemodule.Order += 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
public class ActionViewModel
{
public string Name { set; get; }
public Func<string, PageModule, Task<string>> Action { set; get; }
}
}
}

View File

@ -146,7 +146,7 @@
private async Task Install() private async Task Install()
{ {
if (_hostUsername != "" && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && _hostEmail != "") if (_serverName != "" && _databaseName != "" && _hostUsername != "" && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && _hostEmail != "")
{ {
_loadingDisplay = ""; _loadingDisplay = "";
StateHasChanged(); StateHasChanged();
@ -169,42 +169,24 @@
} }
} }
Uri uri = new Uri(NavigationManager.Uri);
var config = new InstallConfig var config = new InstallConfig
{ {
ConnectionString = connectionstring, ConnectionString = connectionstring,
HostUser = _hostUsername, Aliases = uri.Authority,
HostEmail = _hostEmail, HostEmail = _hostEmail,
Password = _hostPassword, HostPassword = _hostPassword,
IsMaster = true, HostName = Constants.HostUser,
TenantName = Constants.MasterTenant,
IsNewTenant = true,
SiteName = Constants.DefaultSite
}; };
var installation = await InstallationService.Install(config); var installation = await InstallationService.Install(config);
//TODO: Should be moved to Database manager
if (installation.Success) if (installation.Success)
{ {
Site site = new Site(); NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
site.TenantId = -1; // will be populated on server
site.Name = "Default Site";
site.LogoFileId = null;
site.FaviconFileId = null;
site.DefaultThemeType = Constants.DefaultTheme;
site.DefaultLayoutType = Constants.DefaultLayout;
site.DefaultContainerType = Constants.DefaultContainer;
site.PwaIsEnabled = false;
site.PwaAppIconFileId = null;
site.PwaSplashIconFileId = null;
site.AllowRegistration = false;
site = await SiteService.AddSiteAsync(site, null);
User user = new User();
user.SiteId = site.SiteId;
user.Username = _hostUsername;
user.Password = _hostPassword;
user.Email = _hostEmail;
user.DisplayName = _hostUsername;
user = await UserService.AddUserAsync(user);
NavigationManager.NavigateTo("", true);
} }
else else
{ {

View File

@ -73,13 +73,13 @@ namespace Oqtane.UI
} }
} }
public Task IncludeLink(string id, string rel, string url, string type) public Task IncludeLink(string id, string rel, string url, string type, string integrity, string crossorigin)
{ {
try try
{ {
_jsRuntime.InvokeAsync<string>( _jsRuntime.InvokeAsync<string>(
"interop.includeLink", "interop.includeLink",
id, rel, url, type); id, rel, url, type, integrity, crossorigin);
return Task.CompletedTask; return Task.CompletedTask;
} }
catch catch
@ -88,13 +88,13 @@ namespace Oqtane.UI
} }
} }
public Task IncludeScript(string id, string src, string content, string location) public Task IncludeScript(string id, string src, string content, string location, string integrity, string crossorigin)
{ {
try try
{ {
_jsRuntime.InvokeAsync<string>( _jsRuntime.InvokeAsync<string>(
"interop.includeScript", "interop.includeScript",
id, src, content, location); id, src, content, location, integrity, crossorigin);
return Task.CompletedTask; return Task.CompletedTask;
} }
catch catch

View File

@ -22,7 +22,7 @@
} }
if (PageState.Site.FaviconFileId != null) if (PageState.Site.FaviconFileId != null)
{ {
await interop.IncludeLink("fav-icon", "shortcut icon", Utilities.ContentUrl(PageState.Alias.Path, PageState.Site.FaviconFileId.Value), "image/x-icon"); await interop.IncludeLink("fav-icon", "shortcut icon", Utilities.ContentUrl(PageState.Alias.Path, PageState.Site.FaviconFileId.Value), "image/x-icon", "", "");
} }
if (PageState.Site.PwaIsEnabled) if (PageState.Site.PwaIsEnabled)
{ {
@ -74,7 +74,7 @@
"document.getElementById('pwa-manifest').setAttribute('href', url); " + "document.getElementById('pwa-manifest').setAttribute('href', url); " +
"} " + "} " +
", 1000);"; ", 1000);";
await interop.IncludeScript("pwa-manifestscript", "", manifest, "body"); await interop.IncludeScript("pwa-manifestscript", "", manifest, "body", "", "");
// service worker must be in root of site // service worker must be in root of site
string serviceworker = "if ('serviceWorker' in navigator) { " + string serviceworker = "if ('serviceWorker' in navigator) { " +
@ -84,6 +84,6 @@
"console.log('ServiceWorker Registration Failed ', err); " + "console.log('ServiceWorker Registration Failed ', err); " +
"}); " + "}); " +
"}"; "}";
await interop.IncludeScript("pwa-serviceworker", "", serviceworker, "body"); await interop.IncludeScript("pwa-serviceworker", "", serviceworker, "body", "", "");
} }
} }

View File

@ -1,176 +0,0 @@
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
app {
position: relative;
display: flex;
flex-direction: column;
}
/* Control Panel */
.app-controlpanel {
height: 100%;
width: 0%;
position: fixed; /* Stay in place */
z-index: 9999; /* Sit on top */
right: 0;
top: 0;
overflow-x: hidden; /* Disable horizontal scroll */
transition: 0.5s; /* 0.5 second transition effect to slide in or slide down the overlay (height or width, depending on reveal) */
}
/* Position the content inside the overlay */
.app-controlpanel .card-body {
position: relative;
width: 100%; /* 100% width */
}
/* Pad the navigation links */
.app-controlpanel .nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.app-controlpanel .card-body .control-label {
color: white;
}
/* Admin Modal */
.app-admin-modal .modal {
position: fixed; /* Stay in place */
z-index: 9999; /* Sit on top */
left: 0;
top: 0;
display: block;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background: rgba(0,0,0,0.3); /* Dim background */
}
.app-admin-modal .modal-dialog {
width: 100%; /* Full width */
height: 100%; /* Full height */
max-width: none; /* Override default of 500px */
}
.app-admin-modal .modal-content {
margin: 5% auto; /* 5% from the top and centered */
width: 80%; /* Could be more or less, depending on screen size */
}
.app-pane-admin-border {
width: 100%;
border-width: 1px;
border-style: dashed;
border-color: gray;
}
.app-pane-admin-title {
width: 100%;
text-align: center;
color: gray;
}
.app-progress-indicator {
background: rgba(0,0,0,0.2) url('../loading.gif') no-repeat 50% 50%;
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 9999; /* Sit on top */
}
.app-rule {
width: 100%;
color: gray;
height: 1px;
background-color: gray;
}
.app-link-unstyled, .app-link-unstyled:visited, .app-link-unstyled:hover, .app-link-unstyled:active, .app-link-unstyled:focus, .app-link-unstyled:active:hover {
font-style: inherit;
color: inherit;
background-color: transparent;
font-size: inherit;
text-decoration: none;
font-variant: inherit;
font-weight: inherit;
line-height: inherit;
font-family: inherit;
border-radius: inherit;
border: inherit;
outline: inherit;
box-shadow: inherit;
padding: inherit;
vertical-align: inherit;
}
/* Tooltips */
.app-tooltip {
cursor: help;
position: relative;
}
.app-tooltip::before,
.app-tooltip::after {
left: 50%;
opacity: 0;
position: absolute;
z-index: -100;
}
.app-tooltip:hover::before,
.app-tooltip:focus::before,
.app-tooltip:hover::after,
.app-tooltip:focus::after {
opacity: 1;
transform: scale(1) translateY(0);
z-index: 100;
}
.app-tooltip::before {
border-style: solid;
border-width: 1em 0.75em 0 0.75em;
border-color: #3E474F transparent transparent transparent;
bottom: 100%;
content: "";
margin-left: -0.5em;
transition: all .65s cubic-bezier(.84,-0.18,.31,1.26), opacity .65s .5s;
transform: scale(.6) translateY(-90%);
}
.app-tooltip:hover::before,
.app-tooltip:focus::before {
transition: all .65s cubic-bezier(.84,-0.18,.31,1.26) .2s;
}
.app-tooltip::after {
background: #3E474F;
border-radius: .25em;
bottom: 180%;
color: #EDEFF0;
content: attr(data-tip);
margin-left: -8.75em;
padding: 1em;
transition: all .65s cubic-bezier(.84,-0.18,.31,1.26) .2s;
transform: scale(.6) translateY(50%);
width: 17.5em;
}
.app-tooltip:hover::after,
.app-tooltip:focus::after {
transition: all .65s cubic-bezier(.84,-0.18,.31,1.26);
}
@media (max-width: 760px) {
.app-tooltip::after {
font-size: .75em;
margin-left: -5em;
width: 10em;
}
}

View File

@ -1,86 +0,0 @@
SIL OPEN FONT LICENSE Version 1.1
Copyright (c) 2014 Waybury
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

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