Compare commits
97 Commits
v0.9.1-bet
...
v1.0.0
Author | SHA1 | Date | |
---|---|---|---|
19fb3120d3 | |||
4154bd0988 | |||
35b26c7525 | |||
52b2c876a4 | |||
b7eeda7562 | |||
b59e2533ea | |||
a8ec5e1265 | |||
61ff097f51 | |||
b82f69b8b0 | |||
263b045c75 | |||
a160597f6f | |||
f0fe6551dd | |||
09b17e142e | |||
b8ce634f85 | |||
1532eb7586 | |||
9b65cd0e07 | |||
b4596cb624 | |||
5e23448618 | |||
96c2a59551 | |||
6ae019336d | |||
0c236682b9 | |||
9b74262c76 | |||
a13208e65d | |||
f8ab886750 | |||
84b011224e | |||
c426302242 | |||
814e2100b2 | |||
54d4447d23 | |||
93942d7cdd | |||
0afd7d9ca4 | |||
3a19ced2d1 | |||
d5811a20e9 | |||
1b2600c6c4 | |||
f9cdc6d70c | |||
fbdf21320b | |||
96f5668a3b | |||
13adebb36c | |||
8a1e83ff7f | |||
e698ea4d36 | |||
f5ce00ae7d | |||
3cbb6e3e6e | |||
9394e77fd5 | |||
ac03afb146 | |||
51c27ae0e5 | |||
0ea4c4d723 | |||
b3dee737b4 | |||
24ca9f4ded | |||
9850e249fc | |||
5e04cb18a4 | |||
39641804f1 | |||
edc356292d | |||
78f4af6b70 | |||
e98b8801f3 | |||
caabac3e74 | |||
422f360807 | |||
6e28fa47a2 | |||
b4f3c4ae56 | |||
bafe2c6666 | |||
5eec442442 | |||
def12489e6 | |||
82429c2545 | |||
aa97dd4d0d | |||
cba5865e81 | |||
8afe8e7474 | |||
a9630e715b | |||
6824b3f1b5 | |||
1cca18c4d2 | |||
a886ae12cc | |||
560c995564 | |||
69a5077eda | |||
3efd39c74f | |||
bbcb054f7a | |||
88cf30f7c6 | |||
4c188b782d | |||
196e3d5865 | |||
6fd0efbb73 | |||
9eec0fd86b | |||
ad70128747 | |||
ee55b4e3cf | |||
53f454e370 | |||
f05c7d79e3 | |||
598b433cd2 | |||
6ac4ba4617 | |||
f4710f90c0 | |||
6f3fe8d933 | |||
da73d519d7 | |||
7f157582cc | |||
4d7ec16f36 | |||
7c814a67b3 | |||
c83496d814 | |||
83d47376cc | |||
a1449fb2dd | |||
2362faaee1 | |||
7ca1f92f52 | |||
c30ee60433 | |||
e627e14233 | |||
4a6b12b6f9 |
@ -1,4 +1,5 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Files
|
@namespace Oqtane.Modules.Admin.Files
|
||||||
|
@using System.IO
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@ -12,7 +13,7 @@
|
|||||||
<Label For="upload" HelpText="Upload the file you want">Upload: </Label>
|
<Label For="upload" HelpText="Upload the file you want">Upload: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager UploadMultiple="true" ShowFiles="false" FolderId="@_folderId.ToString()" />
|
<FileManager UploadMultiple="true" ShowFiles="false" FolderId="@_folderId" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -70,19 +71,33 @@
|
|||||||
|
|
||||||
private async Task Download()
|
private async Task Download()
|
||||||
{
|
{
|
||||||
try
|
if (url == string.Empty || _folderId == -1)
|
||||||
{
|
{
|
||||||
if (url != string.Empty && _folderId != -1)
|
AddModuleMessage("You Must Enter A Url And Select A Folder", MessageType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1);
|
||||||
|
|
||||||
|
if (!Constants.UploadableFiles.Split(',')
|
||||||
|
.Contains(Path.GetExtension(filename).ToLower().Replace(".", "")))
|
||||||
|
{
|
||||||
|
AddModuleMessage("File Could Not Be Downloaded From Url Due To Its File Extension", MessageType.Warning);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filename.IsPathOrFileValid())
|
||||||
|
{
|
||||||
|
AddModuleMessage("You Must Enter A Url With A Valid File Name", MessageType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await FileService.UploadFileAsync(url, _folderId);
|
await FileService.UploadFileAsync(url, _folderId);
|
||||||
await logger.LogInformation("File Downloaded Successfully From Url {Url}", url);
|
await logger.LogInformation("File Downloaded Successfully From Url {Url}", url);
|
||||||
AddModuleMessage("File Downloaded Successfully From Url", MessageType.Success);
|
AddModuleMessage("File Downloaded Successfully From Url", MessageType.Success);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage("You Must Enter A Url And Select A Folder", MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Downloading File From Url {Url} {Error}", url, ex.Message);
|
await logger.LogError(ex, "Error Downloading File From Url {Url} {Error}", url, ex.Message);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label for="name" HelpText="Enter the file name">Name: </Label>
|
<Label for="name" HelpText="Enter the folder name">Name: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="name" class="form-control" @bind="@_name" />
|
<input id="name" class="form-control" @bind="@_name" />
|
||||||
@ -112,9 +112,19 @@
|
|||||||
|
|
||||||
private async Task SaveFolder()
|
private async Task SaveFolder()
|
||||||
{
|
{
|
||||||
try
|
if (_name == string.Empty || _parentId == -1)
|
||||||
{
|
{
|
||||||
if (_name != string.Empty && _parentId != -1)
|
AddModuleMessage("Folders Must Have A Parent And A Name", MessageType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_name.IsPathOrFileValid())
|
||||||
|
{
|
||||||
|
AddModuleMessage("Folder Name Not Valid.", MessageType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Folder folder;
|
Folder folder;
|
||||||
if (_folderId != -1)
|
if (_folderId != -1)
|
||||||
@ -150,13 +160,15 @@
|
|||||||
folder = await FolderService.AddFolderAsync(folder);
|
folder = await FolderService.AddFolderAsync(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
await FolderService.UpdateFolderOrderAsync(folder.SiteId, folder.FolderId, folder.ParentId);
|
await FolderService.UpdateFolderOrderAsync(folder.SiteId, folder.FolderId, folder.ParentId);
|
||||||
await logger.LogInformation("Folder Saved {Folder}", folder);
|
await logger.LogInformation("Folder Saved {Folder}", folder);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage("Folders Must Have A Parent And A Name", MessageType.Warning);
|
AddModuleMessage("An Error Was Encountered Saving The Folder", MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IModuleDefinitionService ModuleDefinitionService
|
@inject IModuleDefinitionService ModuleDefinitionService
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
|
@inject ISystemService SystemService
|
||||||
|
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.">Owner Name: </Label>
|
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.">Owner Name: </Label>
|
||||||
@ -34,14 +35,25 @@
|
|||||||
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the Oqtane solution. External modules are created outside of the Oqtane solution.">Template: </Label>
|
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the Oqtane solution. External modules are created outside of the Oqtane solution.">Template: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="template" class="form-control" @bind="@_template">
|
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
|
||||||
<option value=""><Select Template></option>
|
<option value="-"><Select Template></option>
|
||||||
<option value="internal">Internal</option>
|
<option value="internal">Internal</option>
|
||||||
<option value="external">External</option>
|
<option value="external">External</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
@if (!string.IsNullOrEmpty(_location))
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="location" HelpText="Location where the module will be created">Location: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input id="module" class="form-control" @bind="@_location" readonly />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
|
||||||
<button type="button" class="btn btn-success" @onclick="CreateModule">Create Module</button>
|
<button type="button" class="btn btn-success" @onclick="CreateModule">Create Module</button>
|
||||||
|
|
||||||
@ -49,7 +61,8 @@
|
|||||||
private string _owner = string.Empty;
|
private string _owner = string.Empty;
|
||||||
private string _module = string.Empty;
|
private string _module = string.Empty;
|
||||||
private string _description = string.Empty;
|
private string _description = string.Empty;
|
||||||
private string _template = string.Empty;
|
private string _template = "-";
|
||||||
|
private string _location = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
@ -62,9 +75,9 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_owner) && !string.IsNullOrEmpty(_module) && !string.IsNullOrEmpty(_template))
|
if (!string.IsNullOrEmpty(_owner) && !string.IsNullOrEmpty(_module) && _template != "-")
|
||||||
{
|
{
|
||||||
var moduleDefinition = new ModuleDefinition { Owner = _owner.Replace(" ",""), Name = _module.Replace(" ", ""), Description = _description, Template = _template };
|
var moduleDefinition = new ModuleDefinition { Owner = _owner.Replace(" ", ""), Name = _module.Replace(" ", ""), Description = _description, Template = _template };
|
||||||
await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition, ModuleState.ModuleId);
|
await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition, ModuleState.ModuleId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -77,4 +90,35 @@
|
|||||||
await logger.LogError(ex, "Error Creating Module");
|
await logger.LogError(ex, "Error Creating Module");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void TemplateChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_location = string.Empty;
|
||||||
|
_template = (string)e.Value;
|
||||||
|
if (_template != "-")
|
||||||
|
{
|
||||||
|
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
|
||||||
|
if (systeminfo != null)
|
||||||
|
{
|
||||||
|
string[] path = systeminfo["serverpath"].Split('\\');
|
||||||
|
if (_template == "internal")
|
||||||
|
{
|
||||||
|
_location = string.Join("\\", path, 0, path.Length - 1) + "\\Oqtane.Client\\Modules\\" + _owner + "." + _module + "s";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_location = string.Join("\\", path, 0, path.Length - 2) + "\\" + _owner + "." + _module + "s";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Getting System Info {Error}", ex.Message);
|
||||||
|
AddModuleMessage("Error Getting System Info", MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
@using [Owner].[Module]s.Services
|
@using [Owner].[Module]s.Services
|
||||||
@using [Owner].[Module]s.Models
|
@using [Owner].[Module]s.Models
|
||||||
|
|
||||||
@namespace [Owner].[Module]s.Modules
|
@namespace [Owner].[Module]s
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
@inject I[Module]Service [Module]Service
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject HttpClient http
|
|
||||||
@inject SiteState sitestate
|
|
||||||
|
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
@ -29,9 +28,14 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
public override string Actions => "Add,Edit";
|
public override string Actions => "Add,Edit";
|
||||||
|
|
||||||
I[Module]Service [Module]Service;
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
|
{
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||||
|
};
|
||||||
|
|
||||||
int _id;
|
int _id;
|
||||||
string _name;
|
string _name;
|
||||||
string _createdby;
|
string _createdby;
|
||||||
@ -43,7 +47,6 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
[Module]Service = new [Module]Service(http, sitestate);
|
|
||||||
if (PageState.Action == "Edit")
|
if (PageState.Action == "Edit")
|
||||||
{
|
{
|
||||||
_id = Int32.Parse(PageState.QueryString["id"]);
|
_id = Int32.Parse(PageState.QueryString["id"]);
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
@using [Owner].[Module]s.Services
|
@using [Owner].[Module]s.Services
|
||||||
@using [Owner].[Module]s.Models
|
@using [Owner].[Module]s.Models
|
||||||
|
|
||||||
@namespace [Owner].[Module]s.Modules
|
@namespace [Owner].[Module]s
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
@inject I[Module]Service [Module]Service
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject HttpClient http
|
|
||||||
@inject SiteState sitestate
|
|
||||||
|
|
||||||
@if (_[Module]s == null)
|
@if (_[Module]s == null)
|
||||||
{
|
{
|
||||||
@ -62,8 +61,9 @@ 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\[Owner].[Module].1.0.0.sql - database schema definition script<br /><br />
|
- Scripts\[Owner].[Module]s.1.0.0.sql - database schema definition script<br />
|
||||||
- Scripts\[Owner].[Module].Uninstall.sql - database uninstall script<br /><br />
|
- Scripts\[Owner].[Module]s.Uninstall.sql - database uninstall script<br />
|
||||||
|
- wwwroot\Module.css - module style sheet<br /><br />
|
||||||
[RootPath]Shared\<br />
|
[RootPath]Shared\<br />
|
||||||
- [Owner].[Module]s.csproj - shared project<br />
|
- [Owner].[Module]s.csproj - shared project<br />
|
||||||
- Models\[Module].cs - model definition<br /><br />
|
- Models\[Module].cs - model definition<br /><br />
|
||||||
@ -71,14 +71,17 @@ else
|
|||||||
<!-- The content above is for informational purposes only and can be safely removed -->
|
<!-- The content above is for informational purposes only and can be safely removed -->
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
I[Module]Service [Module]Service;
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
|
{
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||||
|
};
|
||||||
|
|
||||||
List<[Module]> _[Module]s;
|
List<[Module]> _[Module]s;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
[Module]Service = new [Module]Service(http, sitestate);
|
|
||||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
|
|
||||||
namespace [Owner].[Module]s.Modules
|
namespace [Owner].[Module]s
|
||||||
{
|
{
|
||||||
public class ModuleInfo : IModule
|
public class ModuleInfo : IModule
|
||||||
{
|
{
|
||||||
@ -10,7 +10,6 @@ namespace [Owner].[Module]s.Modules
|
|||||||
Name = "[Module]",
|
Name = "[Module]",
|
||||||
Description = "[Module]",
|
Description = "[Module]",
|
||||||
Version = "1.0.0",
|
Version = "1.0.0",
|
||||||
Dependencies = "[Owner].[Module]s.Shared.Oqtane",
|
|
||||||
ServerManagerType = "[ServerManagerType]",
|
ServerManagerType = "[ServerManagerType]",
|
||||||
ReleaseVersions = "1.0.0"
|
ReleaseVersions = "1.0.0"
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@namespace [Owner].[Module]s.Modules
|
@namespace [Owner].[Module]s
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
|
||||||
|
@ -16,3 +16,5 @@
|
|||||||
@using Oqtane.Shared
|
@using Oqtane.Shared
|
||||||
@using Oqtane.Themes
|
@using Oqtane.Themes
|
||||||
@using Oqtane.Themes.Controls
|
@using Oqtane.Themes.Controls
|
||||||
|
@using Oqtane.UI
|
||||||
|
@using Oqtane.Enums
|
@ -26,6 +26,7 @@
|
|||||||
<file src="..\Server\bin\Release\netcoreapp3.1\[Owner].[Module]s.Server.Oqtane.pdb" target="lib" />
|
<file src="..\Server\bin\Release\netcoreapp3.1\[Owner].[Module]s.Server.Oqtane.pdb" target="lib" />
|
||||||
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.dll" target="lib" />
|
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.dll" target="lib" />
|
||||||
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.pdb" target="lib" />
|
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.pdb" target="lib" />
|
||||||
<file src="..\wwwroot\**\*.*" target="wwwroot" />
|
<file src="..\Server\wwwroot\**\*.*" target="wwwroot" />
|
||||||
|
<file src="..\Server\content\**\*.*" target="content" />
|
||||||
</files>
|
</files>
|
||||||
</package>
|
</package>
|
@ -23,12 +23,12 @@ namespace [Owner].[Module]s.Manager
|
|||||||
|
|
||||||
public bool Install(Tenant tenant, string version)
|
public bool Install(Tenant tenant, string version)
|
||||||
{
|
{
|
||||||
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]." + version + ".sql");
|
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]s." + version + ".sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Uninstall(Tenant tenant)
|
public bool Uninstall(Tenant tenant)
|
||||||
{
|
{
|
||||||
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module].Uninstall.sql");
|
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]s.Uninstall.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ExportModule(Module module)
|
public string ExportModule(Module module)
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Scripts\[Owner].[Module].1.0.0.sql" />
|
<EmbeddedResource Include="Scripts\[Owner].[Module]s.1.0.0.sql" />
|
||||||
<EmbeddedResource Include="Scripts\[Owner].[Module].Uninstall.sql" />
|
<EmbeddedResource Include="Scripts\[Owner].[Module]s.Uninstall.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
1
Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/content/resources.txt
vendored
Normal file
1
Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/content/resources.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is the location where static resources for third party libraries should be located ( the third party library assemblies will be included in the /lib folder ). They should be placed in subfolders which match the naming convention of the third party library. When the module package is deployed the static resource subfolders will be extracted under the web root.
|
1
Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/wwwroot/Module.css
vendored
Normal file
1
Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/wwwroot/Module.css
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/* Module Custom Styles */
|
1
Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/wwwroot/resources.txt
vendored
Normal file
1
Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/wwwroot/resources.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is the location where static resources such as images, style sheets, or scripts for this module will be located. Static assets can be organized in subfolders. When the module package is deployed the assets will be extracted under the web root in a folder that matches the module namespace.
|
@ -2,11 +2,10 @@
|
|||||||
@using [Owner].[Module]s.Services
|
@using [Owner].[Module]s.Services
|
||||||
@using [Owner].[Module]s.Models
|
@using [Owner].[Module]s.Models
|
||||||
|
|
||||||
@namespace [Owner].[Module]s.Modules
|
@namespace [Owner].[Module]s
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
@inject I[Module]Service [Module]Service
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject HttpClient http
|
|
||||||
@inject SiteState sitestate
|
|
||||||
|
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
@ -31,7 +30,6 @@
|
|||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Actions => "Add,Edit";
|
public override string Actions => "Add,Edit";
|
||||||
|
|
||||||
I[Module]Service [Module]Service;
|
|
||||||
int _id;
|
int _id;
|
||||||
string _name;
|
string _name;
|
||||||
string _createdby;
|
string _createdby;
|
||||||
@ -43,7 +41,6 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
[Module]Service = new [Module]Service(http, sitestate);
|
|
||||||
if (PageState.Action == "Edit")
|
if (PageState.Action == "Edit")
|
||||||
{
|
{
|
||||||
_id = Int32.Parse(PageState.QueryString["id"]);
|
_id = Int32.Parse(PageState.QueryString["id"]);
|
@ -1,11 +1,10 @@
|
|||||||
@using [Owner].[Module]s.Services
|
@using [Owner].[Module]s.Services
|
||||||
@using [Owner].[Module]s.Models
|
@using [Owner].[Module]s.Models
|
||||||
|
|
||||||
@namespace [Owner].[Module]s.Modules
|
@namespace [Owner].[Module]s
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
@inject I[Module]Service [Module]Service
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject HttpClient http
|
|
||||||
@inject SiteState sitestate
|
|
||||||
|
|
||||||
@if (_[Module]s == null)
|
@if (_[Module]s == null)
|
||||||
{
|
{
|
||||||
@ -54,22 +53,20 @@ 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\[Owner].[Module].1.0.0.sql - database schema definition script<br /><br />
|
- Scripts\[Owner].[Module]s.1.0.0.sql - database schema definition script<br />
|
||||||
- Scripts\[Owner].[Module].Uninstall.sql - database uninstall script<br /><br />
|
- Scripts\[Owner].[Module]s.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 />
|
||||||
|
|
||||||
<!-- The content above is for informational purposes only and can be safely removed -->
|
<!-- The content above is for informational purposes only and can be safely removed -->
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
I[Module]Service [Module]Service;
|
|
||||||
List<[Module]> _[Module]s;
|
List<[Module]> _[Module]s;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
[Module]Service = new [Module]Service(http, sitestate);
|
|
||||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
@ -1,7 +1,7 @@
|
|||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
|
|
||||||
namespace [Owner].[Module]s.Modules
|
namespace [Owner].[Module]s
|
||||||
{
|
{
|
||||||
public class ModuleInfo : IModule
|
public class ModuleInfo : IModule
|
||||||
{
|
{
|
||||||
@ -10,7 +10,6 @@ namespace [Owner].[Module]s.Modules
|
|||||||
Name = "[Module]",
|
Name = "[Module]",
|
||||||
Description = "[Module]",
|
Description = "[Module]",
|
||||||
Version = "1.0.0",
|
Version = "1.0.0",
|
||||||
Dependencies = "[Owner].[Module]s.Module.Shared",
|
|
||||||
ServerManagerType = "[ServerManagerType]",
|
ServerManagerType = "[ServerManagerType]",
|
||||||
ReleaseVersions = "1.0.0"
|
ReleaseVersions = "1.0.0"
|
||||||
};
|
};
|
@ -1,4 +1,4 @@
|
|||||||
@namespace [Owner].[Module]s.Modules
|
@namespace [Owner].[Module]s
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
|
@ -10,25 +10,13 @@ using [Owner].[Module]s.Repository;
|
|||||||
|
|
||||||
namespace [Owner].[Module]s.Manager
|
namespace [Owner].[Module]s.Manager
|
||||||
{
|
{
|
||||||
public class [Module]Manager : IInstallable, IPortable
|
public class [Module]Manager : IPortable
|
||||||
{
|
{
|
||||||
private I[Module]Repository _[Module]s;
|
private I[Module]Repository _[Module]s;
|
||||||
private ISqlRepository _sql;
|
|
||||||
|
|
||||||
public [Module]Manager(I[Module]Repository [Module]s, ISqlRepository sql)
|
public [Module]Manager(I[Module]Repository [Module]s)
|
||||||
{
|
{
|
||||||
_[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)
|
@ -35,7 +35,7 @@
|
|||||||
<Label HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation.">Module: </Label>
|
<Label HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation.">Module: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager Filter="nupkg" ShowFiles="false" Folder="Modules" UploadMultiple="True" />
|
<FileManager Filter="nupkg" ShowFiles="false" Folder="Modules" UploadMultiple="true" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="container" class="form-control" @bind="@_containerType">
|
<select id="container" class="form-control" @bind="@_containerType">
|
||||||
<option value=""><Select Container></option>
|
<option value="-"><Inherit From Page Or Site></option>
|
||||||
@foreach (KeyValuePair<string, string> container in _containers)
|
@foreach (KeyValuePair<string, string> container in _containers)
|
||||||
{
|
{
|
||||||
<option value="@container.Key">@container.Value</option>
|
<option value="@container.Key">@container.Value</option>
|
||||||
@ -107,6 +107,14 @@
|
|||||||
_title = ModuleState.Title;
|
_title = ModuleState.Title;
|
||||||
_containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync());
|
_containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync());
|
||||||
_containerType = ModuleState.ContainerType;
|
_containerType = ModuleState.ContainerType;
|
||||||
|
if (!string.IsNullOrEmpty(PageState.Page.DefaultContainerType) && _containerType == PageState.Page.DefaultContainerType)
|
||||||
|
{
|
||||||
|
_containerType = "-";
|
||||||
|
}
|
||||||
|
if (_containerType == PageState.Site.DefaultContainerType)
|
||||||
|
{
|
||||||
|
_containerType = "-";
|
||||||
|
}
|
||||||
_allPages = ModuleState.AllPages.ToString();
|
_allPages = ModuleState.AllPages.ToString();
|
||||||
_permissions = ModuleState.Permissions;
|
_permissions = ModuleState.Permissions;
|
||||||
_permissionNames = ModuleState.ModuleDefinition.PermissionNames;
|
_permissionNames = ModuleState.ModuleDefinition.PermissionNames;
|
||||||
@ -115,8 +123,8 @@
|
|||||||
_settingsModuleType = Type.GetType(ModuleState.ModuleType);
|
_settingsModuleType = Type.GetType(ModuleState.ModuleType);
|
||||||
if (_settingsModuleType != null)
|
if (_settingsModuleType != null)
|
||||||
{
|
{
|
||||||
var moduleobject = Activator.CreateInstance(_settingsModuleType);
|
var moduleobject = Activator.CreateInstance(_settingsModuleType) as IModuleControl;
|
||||||
_settingstitle = (string)_settingsModuleType.GetProperty("Title").GetValue(moduleobject, null);
|
_settingstitle = moduleobject.Title;
|
||||||
if (string.IsNullOrEmpty(_settingstitle))
|
if (string.IsNullOrEmpty(_settingstitle))
|
||||||
{
|
{
|
||||||
_settingstitle = "Other Settings";
|
_settingstitle = "Other Settings";
|
||||||
@ -136,7 +144,15 @@
|
|||||||
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||||
pagemodule.PageId = int.Parse(_pageId);
|
pagemodule.PageId = int.Parse(_pageId);
|
||||||
pagemodule.Title = _title;
|
pagemodule.Title = _title;
|
||||||
pagemodule.ContainerType = _containerType;
|
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
||||||
|
{
|
||||||
|
pagemodule.ContainerType = string.Empty;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
|
||||||
|
{
|
||||||
|
pagemodule.ContainerType = string.Empty;
|
||||||
|
}
|
||||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||||
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
||||||
<option value="-"><Select Theme></option>
|
<option value="-"><Inherit From Site></option>
|
||||||
@foreach (KeyValuePair<string, string> item in _themes)
|
@foreach (KeyValuePair<string, string> item in _themes)
|
||||||
{
|
{
|
||||||
if (item.Key == _themetype)
|
if (item.Key == _themetype)
|
||||||
@ -122,7 +122,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Layout" class="form-control" @bind="@_layouttype">
|
<select id="Layout" class="form-control" @bind="@_layouttype">
|
||||||
<option value="-"><Select Layout></option>
|
<option value="-"><Inherit From Site></option>
|
||||||
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
|
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
|
||||||
{
|
{
|
||||||
if (panelayout.Key == _layouttype)
|
if (panelayout.Key == _layouttype)
|
||||||
@ -137,6 +137,20 @@
|
|||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="defaultContainer" HelpText="Select the default container for the page">Default Container: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="defaultContainer" class="form-control" @bind="@_containertype">
|
||||||
|
<option value="-"><Inherit From Site></option>
|
||||||
|
@foreach (KeyValuePair<string, string> container in _containers)
|
||||||
|
{
|
||||||
|
<option value="@container.Key">@container.Value</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
|
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
|
||||||
@ -187,6 +201,7 @@
|
|||||||
@code {
|
@code {
|
||||||
private Dictionary<string, string> _themes;
|
private Dictionary<string, string> _themes;
|
||||||
private Dictionary<string, string> _panelayouts;
|
private Dictionary<string, string> _panelayouts;
|
||||||
|
private Dictionary<string, string> _containers = new Dictionary<string, string>();
|
||||||
private List<Theme> _themeList;
|
private List<Theme> _themeList;
|
||||||
private List<Page> _pageList;
|
private List<Page> _pageList;
|
||||||
private string _name;
|
private string _name;
|
||||||
@ -202,6 +217,7 @@
|
|||||||
private string _mode = "view";
|
private string _mode = "view";
|
||||||
private string _themetype = "-";
|
private string _themetype = "-";
|
||||||
private string _layouttype = "-";
|
private string _layouttype = "-";
|
||||||
|
private string _containertype = "-";
|
||||||
private string _icon = string.Empty;
|
private string _icon = string.Empty;
|
||||||
private string _permissions = string.Empty;
|
private string _permissions = string.Empty;
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
@ -216,11 +232,9 @@
|
|||||||
_pageList = PageState.Pages;
|
_pageList = PageState.Pages;
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||||
|
|
||||||
_themetype = PageState.Site.DefaultThemeType;
|
|
||||||
_layouttype = PageState.Site.DefaultLayoutType;
|
|
||||||
|
|
||||||
_themes = ThemeService.GetThemeTypes(_themeList);
|
_themes = ThemeService.GetThemeTypes(_themeList);
|
||||||
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
|
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
|
||||||
|
_containers = ThemeService.GetContainerTypes(_themeList);
|
||||||
|
|
||||||
_permissions = string.Empty;
|
_permissions = string.Empty;
|
||||||
}
|
}
|
||||||
@ -351,16 +365,20 @@
|
|||||||
page.Url = _url;
|
page.Url = _url;
|
||||||
page.EditMode = (_mode == "edit" ? true : false);
|
page.EditMode = (_mode == "edit" ? true : false);
|
||||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||||
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
|
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||||
if (page.ThemeType == PageState.Site.DefaultThemeType)
|
|
||||||
{
|
{
|
||||||
page.ThemeType = string.Empty;
|
page.ThemeType = string.Empty;
|
||||||
}
|
}
|
||||||
|
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
|
||||||
if (page.LayoutType == PageState.Site.DefaultLayoutType)
|
if (!string.IsNullOrEmpty(page.LayoutType) && page.LayoutType == PageState.Site.DefaultLayoutType)
|
||||||
{
|
{
|
||||||
page.LayoutType = string.Empty;
|
page.LayoutType = string.Empty;
|
||||||
}
|
}
|
||||||
|
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||||
|
{
|
||||||
|
page.DefaultContainerType = string.Empty;
|
||||||
|
}
|
||||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||||
page.Permissions = _permissionGrid.GetPermissions();
|
page.Permissions = _permissionGrid.GetPermissions();
|
||||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||||
|
@ -112,7 +112,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
||||||
<option value="-"><Select Theme></option>
|
<option value="-"><Inherit From Site></option>
|
||||||
@foreach (KeyValuePair<string, string> item in _themes)
|
@foreach (KeyValuePair<string, string> item in _themes)
|
||||||
{
|
{
|
||||||
if (item.Key == _themetype)
|
if (item.Key == _themetype)
|
||||||
@ -133,7 +133,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Layout" class="form-control" @bind="@_layouttype">
|
<select id="Layout" class="form-control" @bind="@_layouttype">
|
||||||
<option value="-"><Select Layout></option>
|
<option value="-"><Inherit From Site></option>
|
||||||
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
|
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
|
||||||
{
|
{
|
||||||
if (panelayout.Key == _layouttype)
|
if (panelayout.Key == _layouttype)
|
||||||
@ -148,6 +148,20 @@
|
|||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="defaultContainer" HelpText="Select the default container for the page">Default Container: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="defaultContainer" class="form-control" @bind="@_containertype">
|
||||||
|
<option value="-"><Inherit From Site></option>
|
||||||
|
@foreach (KeyValuePair<string, string> container in _containers)
|
||||||
|
{
|
||||||
|
<option value="@container.Key">@container.Value</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
|
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
|
||||||
@ -200,6 +214,7 @@
|
|||||||
@code {
|
@code {
|
||||||
private Dictionary<string, string> _themes;
|
private Dictionary<string, string> _themes;
|
||||||
private Dictionary<string, string> _panelayouts;
|
private Dictionary<string, string> _panelayouts;
|
||||||
|
private Dictionary<string, string> _containers = new Dictionary<string, string>();
|
||||||
private List<Theme> _themeList;
|
private List<Theme> _themeList;
|
||||||
private List<Page> _pageList;
|
private List<Page> _pageList;
|
||||||
private int _pageId;
|
private int _pageId;
|
||||||
@ -217,6 +232,7 @@
|
|||||||
private string _mode;
|
private string _mode;
|
||||||
private string _themetype = "-";
|
private string _themetype = "-";
|
||||||
private string _layouttype = "-";
|
private string _layouttype = "-";
|
||||||
|
private string _containertype = "-";
|
||||||
private string _icon;
|
private string _icon;
|
||||||
private string _permissions;
|
private string _permissions;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
@ -241,6 +257,7 @@
|
|||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||||
|
|
||||||
_themes = ThemeService.GetThemeTypes(_themeList);
|
_themes = ThemeService.GetThemeTypes(_themeList);
|
||||||
|
_containers = ThemeService.GetContainerTypes(_themeList);
|
||||||
|
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||||
@ -270,16 +287,21 @@
|
|||||||
_ispersonalizable = page.IsPersonalizable.ToString();
|
_ispersonalizable = page.IsPersonalizable.ToString();
|
||||||
_mode = (page.EditMode) ? "edit" : "view";
|
_mode = (page.EditMode) ? "edit" : "view";
|
||||||
_themetype = page.ThemeType;
|
_themetype = page.ThemeType;
|
||||||
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
|
|
||||||
_layouttype = page.LayoutType;
|
|
||||||
if (_themetype == PageState.Site.DefaultThemeType)
|
if (_themetype == PageState.Site.DefaultThemeType)
|
||||||
{
|
{
|
||||||
_themetype = "-";
|
_themetype = "-";
|
||||||
}
|
}
|
||||||
|
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
|
||||||
|
_layouttype = page.LayoutType;
|
||||||
if (_layouttype == PageState.Site.DefaultLayoutType)
|
if (_layouttype == PageState.Site.DefaultLayoutType)
|
||||||
{
|
{
|
||||||
_layouttype = "-";
|
_layouttype = "-";
|
||||||
}
|
}
|
||||||
|
_containertype = page.DefaultContainerType;
|
||||||
|
if (string.IsNullOrEmpty(_containertype))
|
||||||
|
{
|
||||||
|
_containertype = "-";
|
||||||
|
}
|
||||||
_icon = page.Icon;
|
_icon = page.Icon;
|
||||||
_permissions = page.Permissions;
|
_permissions = page.Permissions;
|
||||||
_createdby = page.CreatedBy;
|
_createdby = page.CreatedBy;
|
||||||
@ -426,15 +448,20 @@
|
|||||||
page.Url = _url;
|
page.Url = _url;
|
||||||
page.EditMode = (_mode == "edit");
|
page.EditMode = (_mode == "edit");
|
||||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||||
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
|
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||||
if (page.ThemeType == PageState.Site.DefaultThemeType)
|
|
||||||
{
|
{
|
||||||
page.ThemeType = string.Empty;
|
page.ThemeType = string.Empty;
|
||||||
}
|
}
|
||||||
if (page.LayoutType == PageState.Site.DefaultLayoutType)
|
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(page.LayoutType) && page.LayoutType == PageState.Site.DefaultLayoutType)
|
||||||
{
|
{
|
||||||
page.LayoutType = string.Empty;
|
page.LayoutType = string.Empty;
|
||||||
}
|
}
|
||||||
|
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||||
|
{
|
||||||
|
page.DefaultContainerType = string.Empty;
|
||||||
|
}
|
||||||
page.Icon = _icon ?? string.Empty;
|
page.Icon = _icon ?? string.Empty;
|
||||||
page.Permissions = _permissionGrid.GetPermissions();
|
page.Permissions = _permissionGrid.GetPermissions();
|
||||||
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<Label For="logo" HelpText="Upload a logo for the site">Logo: </Label>
|
<Label For="logo" HelpText="Upload a logo for the site">Logo: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager FileId="@_logofileid.ToString()" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<Label For="favicon" HelpText="Select Your default icon">Favicon: </Label>
|
<Label For="favicon" HelpText="Select Your default icon">Favicon: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager FileId="@_faviconfileid.ToString()" Filter="ico" @ref="_faviconfilemanager" />
|
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -185,7 +185,7 @@
|
|||||||
<Label For="appIcon" HelpText="Include an application icon for your PWA. It should be a PNG which is 192 X 192 pixels in dimension.">App Icon: </Label>
|
<Label For="appIcon" HelpText="Include an application icon for your PWA. It should be a PNG which is 192 X 192 pixels in dimension.">App Icon: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager FileId="@_pwaappiconfileid.ToString()" Filter="png" @ref="_pwaappiconfilemanager" />
|
<FileManager FileId="@_pwaappiconfileid" Filter="png" @ref="_pwaappiconfilemanager" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -193,7 +193,7 @@
|
|||||||
<Label For="splashIcon" HelpText="Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.">Splash Icon: </Label>
|
<Label For="splashIcon" HelpText="Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.">Splash Icon: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager FileId="@_pwasplashiconfileid.ToString()" Filter="png" @ref="_pwasplashiconfilemanager" />
|
<FileManager FileId="@_pwasplashiconfileid" Filter="png" @ref="_pwasplashiconfilemanager" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<Label For="version" HelpText="Framework Version">Framework Version: </Label>
|
<Label For="version" HelpText="Framework Version">Framework Version: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
<input id="version" class="form-control" @bind="@_version" readonly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<Label For="runtime" HelpText="Blazor Runtime (Server or WebAssembly)">Blazor Runtime: </Label>
|
<Label For="runtime" HelpText="Blazor Runtime (Server or WebAssembly)">Blazor Runtime: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="runtime" class="form-control" @bind="@_runtime" disabled />
|
<input id="runtime" class="form-control" @bind="@_runtime" readonly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<Label For="clrversion" HelpText="Common Language Runtime Version">CLR Version: </Label>
|
<Label For="clrversion" HelpText="Common Language Runtime Version">CLR Version: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="clrversion" class="form-control" @bind="@_clrversion" disabled />
|
<input id="clrversion" class="form-control" @bind="@_clrversion" readonly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<Label For="osversion" HelpText="Operating System Version">OS Version: </Label>
|
<Label For="osversion" HelpText="Operating System Version">OS Version: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="osversion" class="form-control" @bind="@_osversion" disabled />
|
<input id="osversion" class="form-control" @bind="@_osversion" readonly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<Label For="serverpath" HelpText="Server Path">Server Path: </Label>
|
<Label For="serverpath" HelpText="Server Path">Server Path: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="serverpath" class="form-control" @bind="@_serverpath" disabled />
|
<input id="serverpath" class="form-control" @bind="@_serverpath" readonly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<Label For="servertime" HelpText="Server Time">Server Time: </Label>
|
<Label For="servertime" HelpText="Server Time">Server Time: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="servertime" class="form-control" @bind="@_servertime" disabled />
|
<input id="servertime" class="form-control" @bind="@_servertime" readonly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<Label HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation.">Theme: </Label>
|
<Label HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation.">Theme: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager Filter="nupkg" ShowFiles="false" Folder="Themes" UploadMultiple="True" />
|
<FileManager Filter="nupkg" ShowFiles="false" Folder="Themes" UploadMultiple="@true" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -64,7 +64,7 @@ else
|
|||||||
<label for="Name" class="control-label">Photo: </label>
|
<label for="Name" class="control-label">Photo: </label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager FileId="@photofileid.ToString()" @ref="filemanager" />
|
<FileManager FileId="@photofileid" @ref="filemanager" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -63,7 +63,7 @@ else
|
|||||||
<label class="control-label">Photo: </label>
|
<label class="control-label">Photo: </label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<FileManager FileId="@photofileid.ToString()" @ref="filemanager" />
|
<FileManager FileId="@photofileid" @ref="filemanager" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -109,8 +109,8 @@
|
|||||||
Type moduleType = Type.GetType(typename);
|
Type moduleType = Type.GetType(typename);
|
||||||
if (moduleType != null)
|
if (moduleType != null)
|
||||||
{
|
{
|
||||||
var moduleobject = Activator.CreateInstance(moduleType);
|
var moduleobject = Activator.CreateInstance(moduleType) as IModuleControl;
|
||||||
security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
|
security = moduleobject.SecurityAccessLevel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -101,8 +101,8 @@
|
|||||||
var moduleType = Type.GetType(typename);
|
var moduleType = Type.GetType(typename);
|
||||||
if (moduleType != null)
|
if (moduleType != null)
|
||||||
{
|
{
|
||||||
var moduleobject = Activator.CreateInstance(moduleType);
|
var moduleobject = Activator.CreateInstance(moduleType) as IModuleControl;
|
||||||
security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
|
security = moduleobject.SecurityAccessLevel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
|
||||||
@attribute [OqtaneIgnore]
|
@attribute [OqtaneIgnore]
|
||||||
@inject IFolderService FolderService
|
@inject IFolderService FolderService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@ -10,6 +11,8 @@
|
|||||||
<div id="@Id" class="container-fluid px-0">
|
<div id="@Id" class="container-fluid px-0">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
@if (ShowFolders || FolderId <= 0)
|
||||||
|
{
|
||||||
<div>
|
<div>
|
||||||
<select class="form-control" @onchange="(e => FolderChanged(e))">
|
<select class="form-control" @onchange="(e => FolderChanged(e))">
|
||||||
@if (string.IsNullOrEmpty(Folder))
|
@if (string.IsNullOrEmpty(Folder))
|
||||||
@ -18,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
@foreach (Folder folder in _folders)
|
@foreach (Folder folder in _folders)
|
||||||
{
|
{
|
||||||
if (folder.FolderId == _folderid)
|
if (folder.FolderId == FolderId)
|
||||||
{
|
{
|
||||||
<option value="@(folder.FolderId)" selected>@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
<option value="@(folder.FolderId)" selected>@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
||||||
}
|
}
|
||||||
@ -29,14 +32,15 @@
|
|||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@if (_showfiles)
|
}
|
||||||
|
@if (ShowFiles)
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<select class="form-control" @onchange="(e => FileChanged(e))">
|
<select class="form-control" @onchange="(e => FileChanged(e))">
|
||||||
<option value="-1"><Select File></option>
|
<option value="-1"><Select File></option>
|
||||||
@foreach (File file in _files)
|
@foreach (File file in _files)
|
||||||
{
|
{
|
||||||
if (file.FileId == _fileid)
|
if (file.FileId == FileId)
|
||||||
{
|
{
|
||||||
<option value="@(file.FileId)" selected>@(file.Name)</option>
|
<option value="@(file.FileId)" selected>@(file.Name)</option>
|
||||||
}
|
}
|
||||||
@ -48,16 +52,16 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (_haseditpermission)
|
@if (ShowUpload && _haseditpermission)
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
@if (_uploadmultiple)
|
@if (UploadMultiple)
|
||||||
{
|
{
|
||||||
<input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple />
|
<input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple/>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input type="file" id="@_fileinputid" name="file" accept="@_filter" />
|
<input type="file" id="@_fileinputid" name="file" accept="@_filter"/>
|
||||||
}
|
}
|
||||||
<span id="@_progressinfoid"></span><progress id="@_progressbarid" style="width: 150px; visibility: hidden;"></progress>
|
<span id="@_progressinfoid"></span><progress id="@_progressbarid" style="width: 150px; visibility: hidden;"></progress>
|
||||||
<span class="float-right">
|
<span class="float-right">
|
||||||
@ -68,13 +72,13 @@
|
|||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@((MarkupString)_message)
|
|
||||||
}
|
}
|
||||||
|
@((MarkupString) _message)
|
||||||
</div>
|
</div>
|
||||||
@if (_image != string.Empty)
|
@if (_image != string.Empty)
|
||||||
{
|
{
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@((MarkupString)_image)
|
@((MarkupString) _image)
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -84,15 +88,12 @@
|
|||||||
@code {
|
@code {
|
||||||
private string _id;
|
private string _id;
|
||||||
private List<Folder> _folders;
|
private List<Folder> _folders;
|
||||||
private int _folderid = -1;
|
|
||||||
private List<File> _files = new List<File>();
|
private List<File> _files = new List<File>();
|
||||||
private int _fileid = -1;
|
|
||||||
private bool _showfiles = true;
|
private bool _showfiles = true;
|
||||||
private string _fileinputid = string.Empty;
|
private string _fileinputid = string.Empty;
|
||||||
private string _progressinfoid = string.Empty;
|
private string _progressinfoid = string.Empty;
|
||||||
private string _progressbarid = string.Empty;
|
private string _progressbarid = string.Empty;
|
||||||
private string _filter = "*";
|
private string _filter = "*";
|
||||||
private bool _uploadmultiple = false;
|
|
||||||
private bool _haseditpermission = false;
|
private bool _haseditpermission = false;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private string _image = string.Empty;
|
private string _image = string.Empty;
|
||||||
@ -105,19 +106,25 @@
|
|||||||
public string Folder { get; set; } // optional - for setting a specific folder by default
|
public string Folder { get; set; } // optional - for setting a specific folder by default
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string FolderId { get; set; } // optional - for setting a specific folderid by default
|
public int FolderId { get; set; } = -1; // optional - for setting a specific folderid by default
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ShowFiles { get; set; } // optional - for indicating whether a list of files should be displayed - default is true
|
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string FileId { get; set; } // optional - for setting a specific file by default
|
public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int FileId { get; set; } = -1; // optional - for setting a specific file by default
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string UploadMultiple { get; set; } // optional - enable multiple file uploads - default false
|
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@ -129,42 +136,30 @@
|
|||||||
if (!string.IsNullOrEmpty(Folder))
|
if (!string.IsNullOrEmpty(Folder))
|
||||||
{
|
{
|
||||||
_folders = new List<Folder> {new Folder {FolderId = -1, Name = Folder}};
|
_folders = new List<Folder> {new Folder {FolderId = -1, Name = Folder}};
|
||||||
_folderid = -1;
|
FolderId = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||||
if (!string.IsNullOrEmpty(FolderId))
|
|
||||||
{
|
|
||||||
_folderid = int.Parse(FolderId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(FileId))
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
_fileid = int.Parse(FileId);
|
File file = await FileService.GetFileAsync(FileId);
|
||||||
if (_fileid != -1)
|
|
||||||
{
|
|
||||||
File file = await FileService.GetFileAsync(int.Parse(FileId));
|
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
_folderid = file.FolderId;
|
FolderId = file.FolderId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_fileid = -1; // file does not exist
|
FileId = -1; // file does not exist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await SetImage();
|
await SetImage();
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(ShowFiles))
|
|
||||||
{
|
|
||||||
_showfiles = bool.Parse(ShowFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Filter))
|
if (!string.IsNullOrEmpty(Filter))
|
||||||
{
|
{
|
||||||
_filter = "." + Filter.Replace(",",",.");
|
_filter = "." + Filter.Replace(",", ",.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
@ -174,11 +169,6 @@
|
|||||||
_fileinputid = _guid + "FileInput";
|
_fileinputid = _guid + "FileInput";
|
||||||
_progressinfoid = _guid + "ProgressInfo";
|
_progressinfoid = _guid + "ProgressInfo";
|
||||||
_progressbarid = _guid + "ProgressBar";
|
_progressbarid = _guid + "ProgressBar";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(UploadMultiple))
|
|
||||||
{
|
|
||||||
_uploadmultiple = bool.Parse(UploadMultiple);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetFiles()
|
private async Task GetFiles()
|
||||||
@ -191,11 +181,11 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Folder folder = _folders.FirstOrDefault(item => item.FolderId == _folderid);
|
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, folder.Permissions);
|
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions);
|
||||||
_files = await FileService.GetFilesAsync(_folderid);
|
_files = await FileService.GetFilesAsync(FolderId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -222,9 +212,9 @@
|
|||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_folderid = int.Parse((string)e.Value);
|
FolderId = int.Parse((string) e.Value);
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
_fileid = -1;
|
FileId = -1;
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
@ -238,7 +228,7 @@
|
|||||||
private async Task FileChanged(ChangeEventArgs e)
|
private async Task FileChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
_fileid = int.Parse((string)e.Value);
|
FileId = int.Parse((string) e.Value);
|
||||||
|
|
||||||
await SetImage();
|
await SetImage();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -247,19 +237,19 @@
|
|||||||
private async Task SetImage()
|
private async Task SetImage()
|
||||||
{
|
{
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
if (_fileid != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
File file = await FileService.GetFileAsync(_fileid);
|
File file = await FileService.GetFileAsync(FileId);
|
||||||
if (file != null && file.ImageHeight != 0 && file.ImageWidth != 0)
|
if (file != null && file.ImageHeight != 0 && file.ImageWidth != 0)
|
||||||
{
|
{
|
||||||
var maxwidth = 200;
|
var maxwidth = 200;
|
||||||
var maxheight = 200;
|
var maxheight = 200;
|
||||||
|
|
||||||
var ratioX = (double)maxwidth / (double)file.ImageWidth;
|
var ratioX = (double) maxwidth / (double) file.ImageWidth;
|
||||||
var ratioY = (double)maxheight / (double)file.ImageHeight;
|
var ratioY = (double) maxheight / (double) file.ImageHeight;
|
||||||
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
||||||
|
|
||||||
_image = "<img src=\"" + ContentUrl(_fileid) + "\" alt=\"" + file.Name +
|
_image = "<img src=\"" + ContentUrl(FileId) + "\" alt=\"" + file.Name +
|
||||||
"\" width=\"" + Convert.ToInt32(file.ImageWidth * ratio).ToString() +
|
"\" width=\"" + Convert.ToInt32(file.ImageWidth * ratio).ToString() +
|
||||||
"\" height=\"" + Convert.ToInt32(file.ImageHeight * ratio).ToString() + "\" />";
|
"\" height=\"" + Convert.ToInt32(file.ImageHeight * ratio).ToString() + "\" />";
|
||||||
}
|
}
|
||||||
@ -281,7 +271,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = await FileService.UploadFilesAsync(_folderid, upload, _guid);
|
result = await FileService.UploadFilesAsync(FolderId, upload, _guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == string.Empty)
|
if (result == string.Empty)
|
||||||
@ -295,7 +285,7 @@
|
|||||||
var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
|
var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
_fileid = file.FileId;
|
FileId = file.FileId;
|
||||||
await SetImage();
|
await SetImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,21 +315,21 @@
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await FileService.DeleteFileAsync(_fileid);
|
await FileService.DeleteFileAsync(FileId);
|
||||||
await logger.LogInformation("File Deleted {File}", _fileid);
|
await logger.LogInformation("File Deleted {File}", FileId);
|
||||||
_message = "<br /><div class=\"alert alert-success\" role=\"alert\">File Deleted</div>";
|
_message = "<br /><div class=\"alert alert-success\" role=\"alert\">File Deleted</div>";
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
_fileid = -1;
|
FileId = -1;
|
||||||
await SetImage();
|
await SetImage();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting File {File} {Error}", _fileid, ex.Message);
|
await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message);
|
||||||
_message = "<br /><div class=\"alert alert-danger\" role=\"alert\">Error Deleting File</div>";
|
_message = "<br /><div class=\"alert alert-danger\" role=\"alert\">Error Deleting File</div>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetFileId() => _fileid;
|
public int GetFileId() => FileId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
@using Oqtane.Modules.Controls
|
@using Oqtane.Modules.Controls
|
||||||
@namespace Oqtane.Modules.HtmlText
|
@namespace Oqtane.Modules.HtmlText
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
@inject IHtmlTextService HtmlTextService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject HttpClient http
|
|
||||||
@inject SiteState sitestate
|
|
||||||
|
|
||||||
@if (_content != null)
|
@if (_content != null)
|
||||||
{
|
{
|
||||||
@ -14,12 +13,28 @@
|
|||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
|
||||||
@if (!string.IsNullOrEmpty(_content))
|
@if (!string.IsNullOrEmpty(_content))
|
||||||
{
|
{
|
||||||
<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 {
|
||||||
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
|
public override string Title => "Edit Html/Text";
|
||||||
|
|
||||||
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
|
{
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
||||||
|
// the following resources should be declared in the RichTextEditor component however the framework currently only supports resource management for modules and themes
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.bubble.css" },
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.snow.css" },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Url = "js/quill1.3.6.min.js" },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Url = "js/quill-blot-formatter.min.js" },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Url = "js/quill-interop.js" }
|
||||||
|
};
|
||||||
|
|
||||||
private RichTextEditor RichTextEditorHtml;
|
private RichTextEditor RichTextEditorHtml;
|
||||||
private string _content = null;
|
private string _content = null;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
@ -27,16 +42,11 @@
|
|||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
private DateTime _modifiedon;
|
private DateTime _modifiedon;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
|
||||||
|
|
||||||
public override string Title => "Edit Html/Text";
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var htmltextservice = new HtmlTextService(http, sitestate);
|
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||||
var htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
|
|
||||||
if (htmltext != null)
|
if (htmltext != null)
|
||||||
{
|
{
|
||||||
_content = htmltext.Content;
|
_content = htmltext.Content;
|
||||||
@ -65,19 +75,18 @@
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var htmltextservice = new HtmlTextService(http, sitestate);
|
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||||
var htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
|
|
||||||
if (htmltext != null)
|
if (htmltext != null)
|
||||||
{
|
{
|
||||||
htmltext.Content = content;
|
htmltext.Content = content;
|
||||||
await htmltextservice.UpdateHtmlTextAsync(htmltext);
|
await HtmlTextService.UpdateHtmlTextAsync(htmltext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
htmltext = new HtmlTextInfo();
|
htmltext = new HtmlTextInfo();
|
||||||
htmltext.ModuleId = ModuleState.ModuleId;
|
htmltext.ModuleId = ModuleState.ModuleId;
|
||||||
htmltext.Content = content;
|
htmltext.Content = content;
|
||||||
await htmltextservice.AddHtmlTextAsync(htmltext);
|
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||||
}
|
}
|
||||||
|
|
||||||
await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
|
await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
|
||||||
|
@ -1,32 +1,28 @@
|
|||||||
@using Oqtane.Modules.HtmlText.Services
|
@using Oqtane.Modules.HtmlText.Services
|
||||||
@using Oqtane.Modules.HtmlText.Models
|
|
||||||
@namespace Oqtane.Modules.HtmlText
|
@namespace Oqtane.Modules.HtmlText
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject IHtmlTextService HtmlTextService
|
||||||
@inject HttpClient http
|
|
||||||
@inject SiteState sitestate
|
|
||||||
|
|
||||||
@((MarkupString)content)
|
@((MarkupString)content)
|
||||||
|
|
||||||
@if (PageState.EditMode)
|
@if (PageState.EditMode)
|
||||||
{
|
{
|
||||||
<br />
|
<br /><ActionLink Action="Edit" /><br /><br />
|
||||||
}
|
|
||||||
<ActionLink Action="Edit" />
|
|
||||||
@if (PageState.EditMode)
|
|
||||||
{
|
|
||||||
<br /><br />
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
|
{
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||||
|
};
|
||||||
|
|
||||||
private string content = "";
|
private string content = "";
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var htmltextservice = new HtmlTextService(http, sitestate);
|
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||||
var htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
|
|
||||||
if (htmltext != null)
|
if (htmltext != null)
|
||||||
{
|
{
|
||||||
content = htmltext.Content;
|
content = htmltext.Content;
|
||||||
|
@ -8,7 +8,7 @@ using Oqtane.Shared;
|
|||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Services
|
namespace Oqtane.Modules.HtmlText.Services
|
||||||
{
|
{
|
||||||
public class HtmlTextService : ServiceBase, IHtmlTextService
|
public class HtmlTextService : ServiceBase, IHtmlTextService, IService
|
||||||
{
|
{
|
||||||
private readonly SiteState _siteState;
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
|
@ -6,10 +6,11 @@ using Oqtane.Services;
|
|||||||
using System;
|
using System;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using Oqtane.UI;
|
using Oqtane.UI;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Oqtane.Modules
|
namespace Oqtane.Modules
|
||||||
{
|
{
|
||||||
public class ModuleBase : ComponentBase, IModuleControl
|
public abstract class ModuleBase : ComponentBase, IModuleControl
|
||||||
{
|
{
|
||||||
private Logger _logger;
|
private Logger _logger;
|
||||||
|
|
||||||
@ -37,6 +38,9 @@ namespace Oqtane.Modules
|
|||||||
|
|
||||||
public virtual bool UseAdminContainer { get { return true; } }
|
public virtual bool UseAdminContainer { get { return true; } }
|
||||||
|
|
||||||
|
public virtual List<Resource> Resources { get; set; }
|
||||||
|
|
||||||
|
|
||||||
// path method
|
// path method
|
||||||
|
|
||||||
public string ModulePath()
|
public string ModulePath()
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<LangVersion>7.3</LangVersion>
|
<LangVersion>7.3</LangVersion>
|
||||||
<RazorLangVersion>3.0</RazorLangVersion>
|
<RazorLangVersion>3.0</RazorLangVersion>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>0.9.1</Version>
|
<Version>1.0.0</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -27,10 +27,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-rc1.20223.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-rc1.20223.4" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.0-rc1.20217.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.4" />
|
||||||
|
<PackageReference Include="System.Net.Http.Json" Version="3.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -4,12 +4,16 @@ using System.Threading.Tasks;
|
|||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.Providers;
|
using Oqtane.Providers;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Oqtane.Client
|
namespace Oqtane.Client
|
||||||
{
|
{
|
||||||
@ -19,10 +23,9 @@ namespace Oqtane.Client
|
|||||||
{
|
{
|
||||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||||
builder.RootComponents.Add<App>("app");
|
builder.RootComponents.Add<App>("app");
|
||||||
|
HttpClient httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)};
|
||||||
|
|
||||||
builder.Services.AddSingleton(
|
builder.Services.AddSingleton(httpClient);
|
||||||
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }
|
|
||||||
);
|
|
||||||
builder.Services.AddOptions();
|
builder.Services.AddOptions();
|
||||||
|
|
||||||
// register auth services
|
// register auth services
|
||||||
@ -57,14 +60,16 @@ namespace Oqtane.Client
|
|||||||
builder.Services.AddScoped<ISqlService, SqlService>();
|
builder.Services.AddScoped<ISqlService, SqlService>();
|
||||||
builder.Services.AddScoped<ISystemService, SystemService>();
|
builder.Services.AddScoped<ISystemService, SystemService>();
|
||||||
|
|
||||||
|
await LoadClientAssemblies(httpClient);
|
||||||
|
|
||||||
// dynamically register module contexts and repository services
|
// dynamically register module contexts and repository services
|
||||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
foreach (Assembly assembly in assemblies)
|
foreach (Assembly assembly in assemblies)
|
||||||
{
|
{
|
||||||
Type[] implementationtypes = assembly.GetTypes()
|
var implementationTypes = assembly.GetTypes()
|
||||||
.Where(item => item.GetInterfaces().Contains(typeof(IService)))
|
.Where(item => item.GetInterfaces().Contains(typeof(IService)));
|
||||||
.ToArray();
|
|
||||||
foreach (Type implementationtype in implementationtypes)
|
foreach (Type implementationtype in implementationTypes)
|
||||||
{
|
{
|
||||||
Type servicetype = Type.GetType(implementationtype.AssemblyQualifiedName.Replace(implementationtype.Name, "I" + implementationtype.Name));
|
Type servicetype = Type.GetType(implementationtype.AssemblyQualifiedName.Replace(implementationtype.Name, "I" + implementationtype.Name));
|
||||||
if (servicetype != null)
|
if (servicetype != null)
|
||||||
@ -76,9 +81,62 @@ namespace Oqtane.Client
|
|||||||
builder.Services.AddScoped(implementationtype, implementationtype); // no interface defined for service
|
builder.Services.AddScoped(implementationtype, implementationtype); // no interface defined for service
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assembly.GetInstances<IClientStartup>()
|
||||||
|
.ToList()
|
||||||
|
.ForEach(x => x.ConfigureServices(builder.Services));
|
||||||
}
|
}
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
await builder.Build().RunAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task LoadClientAssemblies(HttpClient http)
|
||||||
|
{
|
||||||
|
// get list of loaded assemblies on the client
|
||||||
|
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToList();
|
||||||
|
|
||||||
|
// get assemblies from server and load into client app domain
|
||||||
|
var zip = await http.GetByteArrayAsync($"/~/api/Installation/load");
|
||||||
|
|
||||||
|
// asemblies and debug symbols are packaged in a zip file
|
||||||
|
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
|
||||||
|
{
|
||||||
|
Dictionary<string, byte[]> dlls = new Dictionary<string, byte[]>();
|
||||||
|
Dictionary<string, byte[]> pdbs = new Dictionary<string, byte[]>();
|
||||||
|
|
||||||
|
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||||
|
{
|
||||||
|
if (!assemblies.Contains(Path.GetFileNameWithoutExtension(entry.Name)))
|
||||||
|
{
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
entry.Open().CopyTo(memoryStream);
|
||||||
|
byte[] file = memoryStream.ToArray();
|
||||||
|
switch (Path.GetExtension(entry.Name))
|
||||||
|
{
|
||||||
|
case ".dll":
|
||||||
|
dlls.Add(entry.Name, file);
|
||||||
|
break;
|
||||||
|
case ".pdb":
|
||||||
|
pdbs.Add(entry.Name, file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in dlls)
|
||||||
|
{
|
||||||
|
if (pdbs.ContainsKey(item.Key))
|
||||||
|
{
|
||||||
|
Assembly.Load(item.Value, pdbs[item.Key]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assembly.Load(item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,21 @@ using System.Linq;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System;
|
using System;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
public class AliasService : ServiceBase, IAliasService
|
public class AliasService : ServiceBase, IAliasService
|
||||||
{
|
{
|
||||||
|
|
||||||
public AliasService(HttpClient http) :base(http) { }
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Alias");
|
public AliasService(HttpClient http, SiteState siteState) : base(http)
|
||||||
|
{
|
||||||
|
_siteState = siteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl(_siteState.Alias, "Alias");
|
||||||
|
|
||||||
public async Task<List<Alias>> GetAliasesAsync()
|
public async Task<List<Alias>> GetAliasesAsync()
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,6 @@ namespace Oqtane.Services
|
|||||||
Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
|
Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
|
||||||
Task InstallModuleDefinitionsAsync();
|
Task InstallModuleDefinitionsAsync();
|
||||||
Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId);
|
Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId);
|
||||||
Task LoadModuleDefinitionsAsync(int siteId, Runtime runtime);
|
|
||||||
Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId);
|
Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,20 @@ using System.Threading.Tasks;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
public class JobLogService : ServiceBase, IJobLogService
|
public class JobLogService : ServiceBase, IJobLogService
|
||||||
{
|
{
|
||||||
public JobLogService(HttpClient http) :base(http) { }
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("JobLog");
|
public JobLogService(HttpClient http, SiteState siteState) : base(http)
|
||||||
|
{
|
||||||
|
_siteState = siteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl(_siteState.Alias, "JobLog");
|
||||||
|
|
||||||
public async Task<List<JobLog>> GetJobLogsAsync()
|
public async Task<List<JobLog>> GetJobLogsAsync()
|
||||||
{
|
{
|
||||||
|
@ -3,14 +3,20 @@ using System.Threading.Tasks;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
public class JobService : ServiceBase, IJobService
|
public class JobService : ServiceBase, IJobService
|
||||||
{
|
{
|
||||||
public JobService(HttpClient http) : base(http) { }
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Job");
|
public JobService(HttpClient http, SiteState siteState) : base(http)
|
||||||
|
{
|
||||||
|
_siteState = siteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl(_siteState.Alias, "Job");
|
||||||
|
|
||||||
public async Task<List<Job>> GetJobsAsync()
|
public async Task<List<Job>> GetJobsAsync()
|
||||||
{
|
{
|
||||||
|
@ -49,46 +49,9 @@ namespace Oqtane.Services
|
|||||||
await DeleteAsync($"{Apiurl}/{moduleDefinitionId}?siteid={siteId}");
|
await DeleteAsync($"{Apiurl}/{moduleDefinitionId}?siteid={siteId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LoadModuleDefinitionsAsync(int siteId, Runtime runtime)
|
|
||||||
{
|
|
||||||
// get list of modules from the server
|
|
||||||
List<ModuleDefinition> moduledefinitions = await GetModuleDefinitionsAsync(siteId);
|
|
||||||
|
|
||||||
// download assemblies to browser when running client-side Blazor
|
|
||||||
if (runtime == Runtime.WebAssembly)
|
|
||||||
{
|
|
||||||
// get list of loaded assemblies on the client ( in the client-side hosting module the browser client has its own app domain )
|
|
||||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
|
||||||
|
|
||||||
foreach (ModuleDefinition moduledefinition in moduledefinitions)
|
|
||||||
{
|
|
||||||
// if a module has dependencies, check if they are loaded
|
|
||||||
if (moduledefinition.Dependencies != "")
|
|
||||||
{
|
|
||||||
foreach (string dependency in moduledefinition.Dependencies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
{
|
|
||||||
string assemblyname = dependency.Replace(".dll", "");
|
|
||||||
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
|
|
||||||
{
|
|
||||||
// download assembly from server and load
|
|
||||||
var bytes = await _http.GetByteArrayAsync($"{Apiurl}/load/{assemblyname}.dll");
|
|
||||||
Assembly.Load(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if the module assembly is loaded
|
|
||||||
if (assemblies.Where(item => item.FullName.StartsWith(moduledefinition.AssemblyName + ",")).FirstOrDefault() == null)
|
|
||||||
{
|
|
||||||
// download assembly from server and load
|
|
||||||
var bytes = await _http.GetByteArrayAsync($"{Apiurl}/load/{moduledefinition.AssemblyName}.dll");
|
|
||||||
Assembly.Load(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId)
|
public async Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId)
|
||||||
{
|
{
|
||||||
await PostJsonAsync($"{Apiurl}?moduleid={moduleId.ToString()}", moduleDefinition);
|
await PostJsonAsync($"{Apiurl}?moduleid={moduleId}", moduleDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,13 +135,13 @@ namespace Oqtane.Services
|
|||||||
//TODO Missing content JSON validation
|
//TODO Missing content JSON validation
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an API Url which is tenant agnostic ( for use with entities in the MasterDB )
|
// create an API Url which is tenant agnostic ( for use during installation )
|
||||||
public string CreateApiUrl(string serviceName)
|
public string CreateApiUrl(string serviceName)
|
||||||
{
|
{
|
||||||
return CreateApiUrl(null, serviceName);
|
return CreateApiUrl(null, serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an API Url which is tenant aware ( for use with entities in the TenantDB )
|
// create an API Url which is tenant aware ( for use with repositories )
|
||||||
public string CreateApiUrl(Alias alias, string serviceName)
|
public string CreateApiUrl(Alias alias, string serviceName)
|
||||||
{
|
{
|
||||||
string apiurl = "/";
|
string apiurl = "/";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Oqtane.Models;
|
using System;
|
||||||
|
using Oqtane.Models;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -106,7 +107,7 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
foreach (KeyValuePair<string, string> kvp in settings)
|
foreach (KeyValuePair<string, string> kvp in settings)
|
||||||
{
|
{
|
||||||
Setting setting = settingsList.FirstOrDefault(item => item.SettingName == kvp.Key);
|
Setting setting = settingsList.FirstOrDefault(item => item.SettingName.Equals(kvp.Key,StringComparison.OrdinalIgnoreCase));
|
||||||
if (setting == null)
|
if (setting == null)
|
||||||
{
|
{
|
||||||
setting = new Setting();
|
setting = new Setting();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -6,9 +7,14 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
public class SqlService : ServiceBase, ISqlService
|
public class SqlService : ServiceBase, ISqlService
|
||||||
{
|
{
|
||||||
public SqlService(HttpClient http) : base(http) { }
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Sql");
|
public SqlService(HttpClient http, SiteState siteState) : base(http)
|
||||||
|
{
|
||||||
|
_siteState = siteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl(_siteState.Alias, "Sql");
|
||||||
|
|
||||||
public async Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery)
|
public async Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery)
|
||||||
{
|
{
|
||||||
|
@ -3,14 +3,20 @@ using System.Net.Http;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
public class TenantService : ServiceBase, ITenantService
|
public class TenantService : ServiceBase, ITenantService
|
||||||
{
|
{
|
||||||
public TenantService(HttpClient http) : base(http) { }
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Tenant");
|
public TenantService(HttpClient http, SiteState siteState) : base(http)
|
||||||
|
{
|
||||||
|
_siteState = siteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl(_siteState.Alias, "Tenant");
|
||||||
|
|
||||||
public async Task<List<Tenant>> GetTenantsAsync()
|
public async Task<List<Tenant>> GetTenantsAsync()
|
||||||
{
|
{
|
||||||
|
@ -23,33 +23,6 @@ namespace Oqtane.Services
|
|||||||
public async Task<List<Theme>> GetThemesAsync()
|
public async Task<List<Theme>> GetThemesAsync()
|
||||||
{
|
{
|
||||||
List<Theme> themes = await GetJsonAsync<List<Theme>>(Apiurl);
|
List<Theme> themes = await GetJsonAsync<List<Theme>>(Apiurl);
|
||||||
|
|
||||||
// get list of loaded assemblies
|
|
||||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
|
||||||
|
|
||||||
foreach (Theme theme in themes)
|
|
||||||
{
|
|
||||||
if (theme.Dependencies != "")
|
|
||||||
{
|
|
||||||
foreach (string dependency in theme.Dependencies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
{
|
|
||||||
string assemblyname = dependency.Replace(".dll", "");
|
|
||||||
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
|
|
||||||
{
|
|
||||||
// download assembly from server and load
|
|
||||||
var bytes = await _http.GetByteArrayAsync($"{Apiurl}/load/{assemblyname}.dll");
|
|
||||||
Assembly.Load(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (assemblies.Where(item => item.FullName.StartsWith(theme.AssemblyName + ",")).FirstOrDefault() == null)
|
|
||||||
{
|
|
||||||
// download assembly from server and load
|
|
||||||
var bytes = await _http.GetByteArrayAsync($"{Apiurl}/load/{theme.AssemblyName}.dll");
|
|
||||||
Assembly.Load(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return themes.OrderBy(item => item.Name).ToList();
|
return themes.OrderBy(item => item.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,8 @@
|
|||||||
@code {
|
@code {
|
||||||
public override string Panes => "Content";
|
public override string Panes => "Content";
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
await IncludeCSS("Theme.css");
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -17,7 +17,6 @@ namespace Oqtane.Themes
|
|||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
protected Module ModuleState { get; set; }
|
protected Module ModuleState { get; set; }
|
||||||
|
|
||||||
public virtual string Name { get; set; }
|
|
||||||
|
|
||||||
public string ThemePath()
|
public string ThemePath()
|
||||||
{
|
{
|
||||||
|
@ -149,7 +149,7 @@
|
|||||||
<label for="Pane" class="control-label">Pane: </label>
|
<label for="Pane" class="control-label">Pane: </label>
|
||||||
<select class="form-control" @bind="@_pane">
|
<select class="form-control" @bind="@_pane">
|
||||||
<option value=""><Select Pane></option>
|
<option value=""><Select Pane></option>
|
||||||
@foreach (string pane in PageState.Page.Panes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
@foreach (string pane in PageState.Page.Panes)
|
||||||
{
|
{
|
||||||
<option value="@pane">@pane Pane</option>
|
<option value="@pane">@pane Pane</option>
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var panes = PageState.Page.Panes.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
|
var panes = PageState.Page.Panes;
|
||||||
_pane = panes.Count() == 1 ? panes.SingleOrDefault() : "";
|
_pane = panes.Count() == 1 ? panes.SingleOrDefault() : "";
|
||||||
var themes = await ThemeService.GetThemesAsync();
|
var themes = await ThemeService.GetThemesAsync();
|
||||||
_containers = ThemeService.GetContainerTypes(themes);
|
_containers = ThemeService.GetContainerTypes(themes);
|
||||||
|
@ -60,7 +60,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
actionList.Add(new ActionViewModel {Name = "Move To Bottom", Action = async (s, m) => await MoveBottom(s, m)});
|
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))
|
foreach (string pane in PageState.Page.Panes)
|
||||||
{
|
{
|
||||||
if (pane != ModuleState.Pane)
|
if (pane != ModuleState.Pane)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,5 @@
|
|||||||
{
|
{
|
||||||
public interface IContainerControl
|
public interface IContainerControl
|
||||||
{
|
{
|
||||||
string Name { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,12 @@
|
|||||||
@code {
|
@code {
|
||||||
public override string Panes => string.Empty;
|
public override string Panes => string.Empty;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
// go to https://www.bootstrapcdn.com/bootswatch/ and take your favorite theme
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "BootswatchCyborg.css" },
|
||||||
//<link href="https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css" rel="stylesheet" integrity="sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM" crossorigin="anonymous">
|
// remote stylesheets can be linked using the format below, however we want the default theme to display properly in local development scenarios where an Internet connection is not available
|
||||||
await LoadBootstrapTheme("https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css","sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM");
|
//new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css", Integrity = "sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM", CrossOrigin = "anonymous" },
|
||||||
await IncludeCSS("Theme.css");
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
9
Oqtane.Client/Themes/OqtaneTheme/NoTitle.razor
Normal file
9
Oqtane.Client/Themes/OqtaneTheme/NoTitle.razor
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
<div class="container">
|
||||||
|
@if (PageState.EditMode)
|
||||||
|
{
|
||||||
|
<ModuleActions />
|
||||||
|
}
|
||||||
|
<ModuleInstance />
|
||||||
|
</div>
|
@ -1,7 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.UI;
|
using Oqtane.UI;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Oqtane.Themes
|
namespace Oqtane.Themes
|
||||||
@ -11,31 +13,21 @@ namespace Oqtane.Themes
|
|||||||
[Inject]
|
[Inject]
|
||||||
protected IJSRuntime JSRuntime { get; set; }
|
protected IJSRuntime JSRuntime { get; set; }
|
||||||
|
|
||||||
|
// optional interface properties
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
protected PageState PageState { get; set; }
|
protected PageState PageState { get; set; }
|
||||||
public virtual string Panes { get; set; }
|
public virtual string Panes { get; set; }
|
||||||
|
public virtual List<Resource> Resources { get; set; }
|
||||||
|
|
||||||
|
// path method
|
||||||
|
|
||||||
public string ThemePath()
|
public string ThemePath()
|
||||||
{
|
{
|
||||||
return "Themes/" + GetType().Namespace + "/";
|
return "Themes/" + GetType().Namespace + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task IncludeCSS(string Url)
|
// url methods
|
||||||
{
|
|
||||||
if (!Url.StartsWith("http"))
|
|
||||||
{
|
|
||||||
Url = ThemePath() + Url;
|
|
||||||
}
|
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
await interop.IncludeCSS("Theme", Url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task LoadBootstrapTheme(string url, string integrity = null)
|
|
||||||
{
|
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
string crossorigin = string.IsNullOrEmpty(integrity) ? string.Empty : "anonymous";
|
|
||||||
await interop.IncludeLink("bootstrap", "stylesheet", url, "text/css", integrity, crossorigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string NavigateUrl()
|
public string NavigateUrl()
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="mx-auto text-center">
|
<div class="mx-auto text-center">
|
||||||
<img src="oqtane.png" />
|
<img src="oqtane-black.png" />
|
||||||
|
<div style="font-weight: bold">Version: @Constants.Version</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
|
@ -118,6 +118,22 @@ namespace Oqtane.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task RemoveElementsById(string prefix, string first, string last)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_jsRuntime.InvokeAsync<string>(
|
||||||
|
"interop.removeElementsById",
|
||||||
|
prefix, first, last);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public ValueTask<string> GetElementByName(string name)
|
public ValueTask<string> GetElementByName(string name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_paneadminborder = "";
|
_paneadminborder = "container";
|
||||||
_panetitle = "";
|
_panetitle = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
@inject IPageService PageService
|
@inject IPageService PageService
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
@inject IModuleDefinitionService ModuleDefinitionService
|
|
||||||
@inject ILogService LogService
|
@inject ILogService LogService
|
||||||
@implements IHandleAfterRender
|
@implements IHandleAfterRender
|
||||||
|
|
||||||
@ -157,7 +156,6 @@
|
|||||||
|
|
||||||
if (PageState == null || reload >= Reload.Site)
|
if (PageState == null || reload >= Reload.Site)
|
||||||
{
|
{
|
||||||
await ModuleDefinitionService.LoadModuleDefinitionsAsync(site.SiteId, runtime);
|
|
||||||
pages = await PageService.GetPagesAsync(site.SiteId);
|
pages = await PageService.GetPagesAsync(site.SiteId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -181,7 +179,7 @@
|
|||||||
// extract admin route elements from path
|
// extract admin route elements from path
|
||||||
var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
int result;
|
int result;
|
||||||
// check if path has moduleid and control specification ie. page/moduleid/control/
|
// check if path has moduleid and action specification ie. pagename/moduleid/action/
|
||||||
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
|
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
|
||||||
{
|
{
|
||||||
action = segments[segments.Length - 1];
|
action = segments[segments.Length - 1];
|
||||||
@ -190,7 +188,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check if path has only moduleid specification ie. page/moduleid/
|
// check if path has moduleid specification ie. pagename/moduleid/
|
||||||
if (segments.Length >= 1 && int.TryParse(segments[segments.Length - 1], out result))
|
if (segments.Length >= 1 && int.TryParse(segments[segments.Length - 1], out result))
|
||||||
{
|
{
|
||||||
moduleid = result;
|
moduleid = result;
|
||||||
@ -240,21 +238,7 @@
|
|||||||
{
|
{
|
||||||
page = await ProcessPage(page, site, user);
|
page = await ProcessPage(page, site, user);
|
||||||
|
|
||||||
_pagestate = new PageState
|
if (PageState != null && (PageState.ModuleId != moduleid || PageState.Action != action))
|
||||||
{
|
|
||||||
Alias = alias,
|
|
||||||
Site = site,
|
|
||||||
Pages = pages,
|
|
||||||
Page = page,
|
|
||||||
User = user,
|
|
||||||
Uri = new Uri(_absoluteUri, UriKind.Absolute),
|
|
||||||
QueryString = querystring,
|
|
||||||
ModuleId = moduleid,
|
|
||||||
Action = action,
|
|
||||||
Runtime = runtime
|
|
||||||
};
|
|
||||||
|
|
||||||
if (PageState != null && (PageState.ModuleId != _pagestate.ModuleId || PageState.Action != _pagestate.Action))
|
|
||||||
{
|
{
|
||||||
reload = Reload.Page;
|
reload = Reload.Page;
|
||||||
}
|
}
|
||||||
@ -262,15 +246,29 @@
|
|||||||
if (PageState == null || reload >= Reload.Page)
|
if (PageState == null || reload >= Reload.Page)
|
||||||
{
|
{
|
||||||
modules = await ModuleService.GetModulesAsync(site.SiteId);
|
modules = await ModuleService.GetModulesAsync(site.SiteId);
|
||||||
modules = ProcessModules(modules, page.PageId, _pagestate.ModuleId, _pagestate.Action, page.Panes, site.DefaultContainerType);
|
(page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
modules = PageState.Modules;
|
modules = PageState.Modules;
|
||||||
}
|
}
|
||||||
_pagestate.Modules = modules;
|
|
||||||
_pagestate.EditMode = editmode;
|
_pagestate = new PageState
|
||||||
_pagestate.LastSyncDate = lastsyncdate;
|
{
|
||||||
|
Alias = alias,
|
||||||
|
Site = site,
|
||||||
|
Pages = pages,
|
||||||
|
Page = page,
|
||||||
|
User = user,
|
||||||
|
Modules = modules,
|
||||||
|
Uri = new Uri(_absoluteUri, UriKind.Absolute),
|
||||||
|
QueryString = querystring,
|
||||||
|
ModuleId = moduleid,
|
||||||
|
Action = action,
|
||||||
|
EditMode = editmode,
|
||||||
|
LastSyncDate = lastsyncdate,
|
||||||
|
Runtime = runtime
|
||||||
|
};
|
||||||
|
|
||||||
OnStateChange?.Invoke(_pagestate);
|
OnStateChange?.Invoke(_pagestate);
|
||||||
}
|
}
|
||||||
@ -357,19 +355,30 @@
|
|||||||
page.ThemeType = site.DefaultThemeType;
|
page.ThemeType = site.DefaultThemeType;
|
||||||
page.LayoutType = site.DefaultLayoutType;
|
page.LayoutType = site.DefaultLayoutType;
|
||||||
}
|
}
|
||||||
Type type;
|
|
||||||
|
page.Panes = new List<string>();
|
||||||
|
page.Resources = new List<Resource>();
|
||||||
|
|
||||||
|
string panes = "";
|
||||||
|
Type themetype = Type.GetType(page.ThemeType);
|
||||||
|
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||||
|
if (themeobject != null)
|
||||||
|
{
|
||||||
|
panes = themeobject.Panes;
|
||||||
|
page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(page.LayoutType))
|
if (!string.IsNullOrEmpty(page.LayoutType))
|
||||||
{
|
{
|
||||||
type = Type.GetType(page.LayoutType);
|
Type layouttype = Type.GetType(page.LayoutType);
|
||||||
}
|
var layoutobject = Activator.CreateInstance(layouttype) as ILayoutControl;
|
||||||
else
|
if (layoutobject != null)
|
||||||
{
|
{
|
||||||
type = Type.GetType(page.ThemeType);
|
panes = layoutobject.Panes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var property = type.GetProperty("Panes");
|
page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
page.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -379,12 +388,12 @@
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Module> ProcessModules(List<Module> modules, int pageid, int moduleid, string control, string panes, string defaultcontainertype)
|
private (Page Page, List<Module> Modules) ProcessModules(Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype)
|
||||||
{
|
{
|
||||||
var paneindex = new Dictionary<string, int>();
|
var paneindex = new Dictionary<string, int>();
|
||||||
foreach (Module module in modules)
|
foreach (Module module in modules)
|
||||||
{
|
{
|
||||||
if (module.PageId == pageid || module.ModuleId == moduleid)
|
if (module.PageId == page.PageId || module.ModuleId == moduleid)
|
||||||
{
|
{
|
||||||
var typename = string.Empty;
|
var typename = string.Empty;
|
||||||
if (module.ModuleDefinition != null)
|
if (module.ModuleDefinition != null)
|
||||||
@ -396,63 +405,72 @@
|
|||||||
typename = Constants.ErrorModule;
|
typename = Constants.ErrorModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.ModuleId == moduleid && control != "")
|
if (module.ModuleId == moduleid && action != "")
|
||||||
{
|
{
|
||||||
// check if the module defines custom routes
|
// check if the module defines custom routes
|
||||||
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
||||||
{
|
{
|
||||||
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (route.StartsWith(control + "="))
|
if (route.StartsWith(action + "="))
|
||||||
{
|
{
|
||||||
typename = route.Replace(control + "=", "");
|
typename = route.Replace(action + "=", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.ModuleType = typename.Replace(Constants.ActionToken, control);
|
module.ModuleType = typename.Replace(Constants.ActionToken, action);
|
||||||
|
|
||||||
// admin controls need to load additional metadata from the IModuleControl interface
|
|
||||||
if (moduleid == module.ModuleId)
|
|
||||||
{
|
|
||||||
typename = module.ModuleType;
|
|
||||||
// check for core module actions component
|
|
||||||
if (Constants.DefaultModuleActions.Contains(control))
|
|
||||||
{
|
|
||||||
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, control);
|
|
||||||
}
|
|
||||||
Type moduletype = Type.GetType(typename);
|
|
||||||
if (moduletype != null)
|
|
||||||
{
|
|
||||||
var moduleobject = Activator.CreateInstance(moduletype);
|
|
||||||
module.SecurityAccessLevel = (SecurityAccessLevel)moduletype.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
|
|
||||||
module.ControlTitle = (string)moduletype.GetProperty("Title").GetValue(moduleobject);
|
|
||||||
module.Actions = (string)moduletype.GetProperty("Actions").GetValue(moduleobject);
|
|
||||||
module.UseAdminContainer = (bool)moduletype.GetProperty("UseAdminContainer").GetValue(moduleobject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
module.ModuleType = typename.Replace(Constants.ActionToken, Constants.DefaultAction);
|
module.ModuleType = typename.Replace(Constants.ActionToken, Constants.DefaultAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get additional metadata from IModuleControl interface
|
||||||
|
typename = module.ModuleType;
|
||||||
|
if (Constants.DefaultModuleActions.Contains(action))
|
||||||
|
{
|
||||||
|
// core framework module action components
|
||||||
|
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
|
||||||
|
}
|
||||||
|
Type moduletype = Type.GetType(typename);
|
||||||
|
|
||||||
|
// ensure component implements IModuleControl
|
||||||
|
if (moduletype != null && !moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
|
||||||
|
{
|
||||||
|
module.ModuleType = "";
|
||||||
|
}
|
||||||
|
if (moduletype != null && module.ModuleType != "")
|
||||||
|
{
|
||||||
|
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
|
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
|
||||||
|
|
||||||
|
// additional metadata needed for admin components
|
||||||
|
if (module.ModuleId == moduleid && action != "")
|
||||||
|
{
|
||||||
|
module.SecurityAccessLevel = moduleobject.SecurityAccessLevel;
|
||||||
|
module.ControlTitle = moduleobject.Title;
|
||||||
|
module.Actions = moduleobject.Actions;
|
||||||
|
module.UseAdminContainer = moduleobject.UseAdminContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ensure module's pane exists in current page and if not, assign it to the Admin pane
|
// ensure module's pane exists in current page and if not, assign it to the Admin pane
|
||||||
if (panes == null || !panes.ToLower().Contains(module.Pane.ToLower()))
|
if (page.Panes == null || page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
|
||||||
{
|
{
|
||||||
module.Pane = Constants.AdminPane;
|
module.Pane = Constants.AdminPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate module position within pane
|
// calculate module position within pane
|
||||||
if (paneindex.ContainsKey(module.Pane))
|
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||||
{
|
{
|
||||||
paneindex[module.Pane] += 1;
|
paneindex[module.Pane.ToLower()] += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
paneindex.Add(module.Pane, 0);
|
paneindex.Add(module.Pane.ToLower(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.PaneModuleIndex = paneindex[module.Pane];
|
module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(module.ContainerType))
|
if (string.IsNullOrEmpty(module.ContainerType))
|
||||||
{
|
{
|
||||||
@ -461,16 +479,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Module module in modules.Where(item => item.PageId == pageid))
|
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
||||||
{
|
{
|
||||||
module.PaneModuleCount = paneindex[module.Pane] + 1;
|
module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return modules;
|
return (page, modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources)
|
||||||
|
{
|
||||||
|
if (resources != null)
|
||||||
|
{
|
||||||
|
foreach (var resource in resources)
|
||||||
|
{
|
||||||
|
// ensure resource does not exist already
|
||||||
|
if (pageresources.Find(item => item.Url == resource.Url) == null)
|
||||||
|
{
|
||||||
|
pageresources.Add(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pageresources;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runtime GetRuntime()
|
private Runtime GetRuntime()
|
||||||
=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"))
|
=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"))
|
||||||
? Runtime.WebAssembly
|
? Runtime.WebAssembly
|
||||||
: Runtime.Server;
|
: Runtime.Server;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
var interop = new Interop(JsRuntime);
|
var interop = new Interop(JsRuntime);
|
||||||
|
|
||||||
|
// set page title
|
||||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||||
{
|
{
|
||||||
await interop.UpdateTitle(PageState.Page.Title);
|
await interop.UpdateTitle(PageState.Page.Title);
|
||||||
@ -20,10 +22,34 @@
|
|||||||
{
|
{
|
||||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update page resources
|
||||||
|
int stylesheet = 0;
|
||||||
|
int script = 0;
|
||||||
|
foreach (Resource resource in PageState.Page.Resources)
|
||||||
|
{
|
||||||
|
switch (resource.ResourceType)
|
||||||
|
{
|
||||||
|
case ResourceType.Stylesheet:
|
||||||
|
stylesheet += 1;
|
||||||
|
await interop.IncludeLink("app-stylesheet" + stylesheet.ToString("00"), "stylesheet", resource.Url, "text/css", resource.Integrity ?? "", resource.CrossOrigin ?? "");
|
||||||
|
break;
|
||||||
|
case ResourceType.Script:
|
||||||
|
script += 1;
|
||||||
|
await interop.IncludeScript("app-script" + script.ToString("00"), resource.Url, "", "body", resource.Integrity ?? "", resource.CrossOrigin ?? "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove any page resources references which are no longer required for this page
|
||||||
|
await interop.RemoveElementsById("app-stylesheet", "app-stylesheet" + (stylesheet + 1).ToString("00"), "");
|
||||||
|
await interop.RemoveElementsById("app-script", "app-script" + (script + 1).ToString("00"), "");
|
||||||
|
|
||||||
|
// add favicon
|
||||||
if (PageState.Site.FaviconFileId != null)
|
if (PageState.Site.FaviconFileId != null)
|
||||||
{
|
{
|
||||||
await interop.IncludeLink("fav-icon", "shortcut icon", Utilities.ContentUrl(PageState.Alias, PageState.Site.FaviconFileId.Value), "image/x-icon", "", "");
|
await interop.IncludeLink("fav-icon", "shortcut icon", Utilities.ContentUrl(PageState.Alias, PageState.Site.FaviconFileId.Value), "image/x-icon", "", "");
|
||||||
}
|
}
|
||||||
|
// add PWA support
|
||||||
if (PageState.Site.PwaIsEnabled)
|
if (PageState.Site.PwaIsEnabled)
|
||||||
{
|
{
|
||||||
await InitializePwa(interop);
|
await InitializePwa(interop);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>0.9.1</version>
|
<version>1.0.0</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
@ -16,6 +16,7 @@ using System.Net;
|
|||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
|
|
||||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
foreach (string file in Directory.GetFiles(folder))
|
foreach (string file in Directory.GetFiles(folder))
|
||||||
{
|
{
|
||||||
files.Add(new Models.File {Name = Path.GetFileName(file), Extension = Path.GetExtension(file)?.Replace(".", "")});
|
files.Add(new Models.File { Name = Path.GetFileName(file), Extension = Path.GetExtension(file)?.Replace(".", "") });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,14 +189,37 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
Models.File file = null;
|
Models.File file = null;
|
||||||
Folder folder = _folders.GetFolder(int.Parse(folderid));
|
Folder folder = _folders.GetFolder(int.Parse(folderid));
|
||||||
if (folder != null && _userPermissions.IsAuthorized(User, PermissionNames.Edit, folder.Permissions))
|
|
||||||
|
if (folder == null || !_userPermissions.IsAuthorized(User, PermissionNames.Edit, folder.Permissions))
|
||||||
{
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||||
|
"User Not Authorized To Download File {Url} {FolderId}", url, folderid);
|
||||||
|
HttpContext.Response.StatusCode = 401;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
string folderPath = GetFolderPath(folder);
|
string folderPath = GetFolderPath(folder);
|
||||||
CreateDirectory(folderPath);
|
CreateDirectory(folderPath);
|
||||||
|
|
||||||
string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1);
|
string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1);
|
||||||
// check for allowable file extensions
|
// check for allowable file extensions
|
||||||
if (Constants.UploadableFiles.Contains(Path.GetExtension(filename).Replace(".", "")))
|
if (!Constants.UploadableFiles.Split(',')
|
||||||
|
.Contains(Path.GetExtension(filename).ToLower().Replace(".", "")))
|
||||||
{
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||||
|
"File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filename.IsPathOrFileValid())
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||||
|
$"File Could Not Be Downloaded From Url Due To Its File Name Not Allowed {url}");
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var client = new WebClient();
|
var client = new WebClient();
|
||||||
@ -207,22 +231,12 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
client.DownloadFile(url, targetPath);
|
client.DownloadFile(url, targetPath);
|
||||||
_files.AddFile(CreateFile(filename, folder.FolderId, targetPath));
|
file = _files.AddFile(CreateFile(filename, folder.FolderId, targetPath));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url {Url}", url);
|
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||||
}
|
"File Could Not Be Downloaded From Url {Url}", url);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Download File {Url} {FolderId}", url, folderid);
|
|
||||||
HttpContext.Response.StatusCode = 401;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
@ -232,14 +246,24 @@ namespace Oqtane.Controllers
|
|||||||
[HttpPost("upload")]
|
[HttpPost("upload")]
|
||||||
public async Task UploadFile(string folder, IFormFile file)
|
public async Task UploadFile(string folder, IFormFile file)
|
||||||
{
|
{
|
||||||
if (file.Length > 0)
|
if (file.Length <= 0)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.FileName.IsPathOrFileValid())
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string folderPath = "";
|
string folderPath = "";
|
||||||
|
|
||||||
if (int.TryParse(folder, out int folderId))
|
if (int.TryParse(folder, out int folderId))
|
||||||
{
|
{
|
||||||
Folder virtualFolder = _folders.GetFolder(folderId);
|
Folder virtualFolder = _folders.GetFolder(folderId);
|
||||||
if (virtualFolder != null && _userPermissions.IsAuthorized(User, PermissionNames.Edit, virtualFolder.Permissions))
|
if (virtualFolder != null &&
|
||||||
|
_userPermissions.IsAuthorized(User, PermissionNames.Edit, virtualFolder.Permissions))
|
||||||
{
|
{
|
||||||
folderPath = GetFolderPath(virtualFolder);
|
folderPath = GetFolderPath(virtualFolder);
|
||||||
}
|
}
|
||||||
@ -268,11 +292,11 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Upload File {Folder} {File}", folder, file);
|
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||||
|
"User Not Authorized To Upload File {Folder} {File}", folder, file);
|
||||||
HttpContext.Response.StatusCode = 401;
|
HttpContext.Response.StatusCode = 401;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> MergeFile(string folder, string filename)
|
private async Task<string> MergeFile(string folder, string filename)
|
||||||
{
|
{
|
||||||
@ -282,7 +306,8 @@ namespace Oqtane.Controllers
|
|||||||
string token = ".part_";
|
string token = ".part_";
|
||||||
string parts = Path.GetExtension(filename)?.Replace(token, ""); // returns "x_y"
|
string parts = Path.GetExtension(filename)?.Replace(token, ""); // returns "x_y"
|
||||||
int totalparts = int.Parse(parts?.Substring(parts.IndexOf("_") + 1));
|
int totalparts = int.Parse(parts?.Substring(parts.IndexOf("_") + 1));
|
||||||
filename = filename?.Substring(0, filename.IndexOf(token)); // base filename
|
|
||||||
|
filename = Path.GetFileNameWithoutExtension(filename); // base filename
|
||||||
string[] fileParts = Directory.GetFiles(folder, filename + token + "*"); // list of all file parts
|
string[] fileParts = Directory.GetFiles(folder, filename + token + "*"); // list of all file parts
|
||||||
|
|
||||||
// if all of the file parts exist ( note that file parts can arrive out of order )
|
// if all of the file parts exist ( note that file parts can arrive out of order )
|
||||||
@ -317,7 +342,7 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for allowable file extensions
|
// check for allowable file extensions
|
||||||
if (!Constants.UploadableFiles.Contains(Path.GetExtension(filename)?.Replace(".", "")))
|
if (!Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(filename)?.ToLower().Replace(".", "")))
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(Path.Combine(folder, filename + ".tmp"));
|
System.IO.File.Delete(Path.Combine(folder, filename + ".tmp"));
|
||||||
}
|
}
|
||||||
@ -339,13 +364,15 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// clean up file parts which are more than 2 hours old ( which can happen if a prior file upload failed )
|
// clean up file parts which are more than 2 hours old ( which can happen if a prior file upload failed )
|
||||||
fileParts = Directory.GetFiles(folder, "*" + token + "*");
|
var cleanupFiles = Directory.EnumerateFiles(folder, "*" + token + "*")
|
||||||
foreach (string filepart in fileParts)
|
.Where(f => Path.GetExtension(f).StartsWith(token));
|
||||||
|
|
||||||
|
foreach (var file in cleanupFiles)
|
||||||
{
|
{
|
||||||
DateTime createddate = System.IO.File.GetCreationTime(filepart).ToUniversalTime();
|
var createdDate = System.IO.File.GetCreationTime(file).ToUniversalTime();
|
||||||
if (createddate < DateTime.UtcNow.AddHours(-2))
|
if (createdDate < DateTime.UtcNow.AddHours(-2))
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(filepart);
|
System.IO.File.Delete(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,12 +423,13 @@ namespace Oqtane.Controllers
|
|||||||
[HttpGet("download/{id}")]
|
[HttpGet("download/{id}")]
|
||||||
public IActionResult Download(int id)
|
public IActionResult Download(int id)
|
||||||
{
|
{
|
||||||
|
string errorpath = Path.Combine(GetFolderPath("images"), "error.png");
|
||||||
Models.File file = _files.GetFile(id);
|
Models.File file = _files.GetFile(id);
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||||
{
|
{
|
||||||
string filepath = Path.Combine(GetFolderPath(file.Folder) , file.Name);
|
string filepath = Path.Combine(GetFolderPath(file.Folder), file.Name);
|
||||||
if (System.IO.File.Exists(filepath))
|
if (System.IO.File.Exists(filepath))
|
||||||
{
|
{
|
||||||
byte[] filebytes = System.IO.File.ReadAllBytes(filepath);
|
byte[] filebytes = System.IO.File.ReadAllBytes(filepath);
|
||||||
@ -411,22 +439,29 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath);
|
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath);
|
||||||
HttpContext.Response.StatusCode = 404;
|
HttpContext.Response.StatusCode = 404;
|
||||||
return null;
|
if (System.IO.File.Exists(errorpath))
|
||||||
|
{
|
||||||
|
byte[] filebytes = System.IO.File.ReadAllBytes(errorpath);
|
||||||
|
return File(filebytes, "application/octet-stream", file.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {FileId}", id);
|
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {FileId}", id);
|
||||||
HttpContext.Response.StatusCode = 401;
|
HttpContext.Response.StatusCode = 401;
|
||||||
return null;
|
byte[] filebytes = System.IO.File.ReadAllBytes(errorpath);
|
||||||
|
return File(filebytes, "application/octet-stream", file.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id);
|
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id);
|
||||||
HttpContext.Response.StatusCode = 404;
|
HttpContext.Response.StatusCode = 404;
|
||||||
return null;
|
byte[] filebytes = System.IO.File.ReadAllBytes(errorpath);
|
||||||
|
return File(filebytes, "application/octet-stream", "error.png");
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFolderPath(Folder folder)
|
private string GetFolderPath(Folder folder)
|
||||||
@ -448,7 +483,7 @@ namespace Oqtane.Controllers
|
|||||||
string[] folders = folderpath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
|
string[] folders = folderpath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
|
||||||
foreach (string folder in folders)
|
foreach (string folder in folders)
|
||||||
{
|
{
|
||||||
path = Utilities.PathCombine(path, folder,"\\");
|
path = Utilities.PathCombine(path, folder, "\\");
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(path);
|
Directory.CreateDirectory(path);
|
||||||
@ -465,11 +500,11 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
FileInfo fileinfo = new FileInfo(filepath);
|
FileInfo fileinfo = new FileInfo(filepath);
|
||||||
file.Extension = fileinfo.Extension.ToLower().Replace(".", "");
|
file.Extension = fileinfo.Extension.ToLower().Replace(".", "");
|
||||||
file.Size = (int) fileinfo.Length;
|
file.Size = (int)fileinfo.Length;
|
||||||
file.ImageHeight = 0;
|
file.ImageHeight = 0;
|
||||||
file.ImageWidth = 0;
|
file.ImageWidth = 0;
|
||||||
|
|
||||||
if (Constants.ImageFiles.Contains(file.Extension))
|
if (Constants.ImageFiles.Split(',').Contains(file.Extension.ToLower()))
|
||||||
{
|
{
|
||||||
FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read);
|
FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read);
|
||||||
using (var image = Image.FromStream(stream))
|
using (var image = Image.FromStream(stream))
|
||||||
|
@ -10,7 +10,6 @@ using Oqtane.Extensions;
|
|||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@ -33,7 +32,7 @@ namespace Oqtane.Controllers
|
|||||||
public IEnumerable<Folder> Get(string siteid)
|
public IEnumerable<Folder> Get(string siteid)
|
||||||
{
|
{
|
||||||
List<Folder> folders = new List<Folder>();
|
List<Folder> folders = new List<Folder>();
|
||||||
foreach(Folder folder in _folders.GetFolders(int.Parse(siteid)))
|
foreach (Folder folder in _folders.GetFolders(int.Parse(siteid)))
|
||||||
{
|
{
|
||||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||||
{
|
{
|
||||||
@ -104,17 +103,27 @@ namespace Oqtane.Controllers
|
|||||||
new Permission(PermissionNames.Edit, Constants.AdminRole, true),
|
new Permission(PermissionNames.Edit, Constants.AdminRole, true),
|
||||||
}.EncodePermissions();
|
}.EncodePermissions();
|
||||||
}
|
}
|
||||||
if (_userPermissions.IsAuthorized(User,PermissionNames.Edit, permissions))
|
if (_userPermissions.IsAuthorized(User, PermissionNames.Edit, permissions))
|
||||||
|
{
|
||||||
|
if (folder.IsPathValid())
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null)
|
if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null)
|
||||||
{
|
{
|
||||||
Folder parent = _folders.GetFolder(folder.ParentId.Value);
|
Folder parent = _folders.GetFolder(folder.ParentId.Value);
|
||||||
folder.Path = Utilities.PathCombine(parent.Path, folder.Name,"\\");
|
folder.Path = Utilities.PathCombine(parent.Path, folder.Name);
|
||||||
}
|
}
|
||||||
|
folder.Path = Utilities.PathCombine(folder.Path, "\\");
|
||||||
folder = _folders.AddFolder(folder);
|
folder = _folders.AddFolder(folder);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", folder);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", folder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder);
|
||||||
|
HttpContext.Response.StatusCode = 401;
|
||||||
|
folder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Folder {Folder}", folder);
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Folder {Folder}", folder);
|
||||||
HttpContext.Response.StatusCode = 401;
|
HttpContext.Response.StatusCode = 401;
|
||||||
@ -130,16 +139,26 @@ namespace Oqtane.Controllers
|
|||||||
public Folder Put(int id, [FromBody] Folder folder)
|
public Folder Put(int id, [FromBody] Folder folder)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit))
|
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit))
|
||||||
|
{
|
||||||
|
if (folder.IsPathValid())
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null)
|
if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null)
|
||||||
{
|
{
|
||||||
Folder parent = _folders.GetFolder(folder.ParentId.Value);
|
Folder parent = _folders.GetFolder(folder.ParentId.Value);
|
||||||
folder.Path = Utilities.PathCombine(parent.Path, folder.Name,"\\");
|
folder.Path = Utilities.PathCombine(parent.Path, folder.Name);
|
||||||
}
|
}
|
||||||
|
folder.Path = Utilities.PathCombine(folder.Path, "\\");
|
||||||
folder = _folders.UpdateFolder(folder);
|
folder = _folders.UpdateFolder(folder);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", folder);
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", folder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder);
|
||||||
|
HttpContext.Response.StatusCode = 401;
|
||||||
|
folder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Folder {Folder}", folder);
|
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Folder {Folder}", folder);
|
||||||
HttpContext.Response.StatusCode = 401;
|
HttpContext.Response.StatusCode = 401;
|
||||||
|
@ -4,6 +4,11 @@ using Microsoft.Extensions.Configuration;
|
|||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@ -55,5 +60,56 @@ namespace Oqtane.Controllers
|
|||||||
_installationManager.UpgradeFramework();
|
_installationManager.UpgradeFramework();
|
||||||
return installation;
|
return installation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/load
|
||||||
|
[HttpGet("load")]
|
||||||
|
public IActionResult Load()
|
||||||
|
{
|
||||||
|
if (_config.GetSection("Runtime").Value == "WebAssembly")
|
||||||
|
{
|
||||||
|
// get list of assemblies which should be downloaded to browser
|
||||||
|
var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies();
|
||||||
|
var list = assemblies.Select(a => a.GetName().Name).ToList();
|
||||||
|
var deps = assemblies.SelectMany(a => a.GetReferencedAssemblies()).Distinct();
|
||||||
|
list.AddRange(deps.Where(a => a.Name.EndsWith(".oqtane", StringComparison.OrdinalIgnoreCase)).Select(a => a.Name));
|
||||||
|
|
||||||
|
// create zip file containing assemblies and debug symbols
|
||||||
|
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
|
byte[] zipfile;
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
|
||||||
|
{
|
||||||
|
ZipArchiveEntry entry;
|
||||||
|
foreach (string file in list)
|
||||||
|
{
|
||||||
|
entry = archive.CreateEntry(file + ".dll");
|
||||||
|
using (var filestream = new FileStream(Path.Combine(binfolder, file + ".dll"), FileMode.Open, FileAccess.Read))
|
||||||
|
using (var entrystream = entry.Open())
|
||||||
|
{
|
||||||
|
filestream.CopyTo(entrystream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(Path.Combine(binfolder, file + ".pdb")))
|
||||||
|
{
|
||||||
|
entry = archive.CreateEntry(file + ".pdb");
|
||||||
|
using (var filestream = new FileStream(Path.Combine(binfolder, file + ".pdb"), FileMode.Open, FileAccess.Read))
|
||||||
|
using (var entrystream = entry.Open())
|
||||||
|
{
|
||||||
|
filestream.CopyTo(entrystream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zipfile = memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
return File(zipfile, "application/octet-stream", "oqtane.zip");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = 401;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ using Oqtane.Repository;
|
|||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@ -23,20 +24,24 @@ namespace Oqtane.Controllers
|
|||||||
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
||||||
private readonly IModuleRepository _modules;
|
private readonly IModuleRepository _modules;
|
||||||
private readonly ITenantRepository _tenants;
|
private readonly ITenantRepository _tenants;
|
||||||
|
private readonly ISqlRepository _sql;
|
||||||
private readonly IUserPermissions _userPermissions;
|
private readonly IUserPermissions _userPermissions;
|
||||||
private readonly IInstallationManager _installationManager;
|
private readonly IInstallationManager _installationManager;
|
||||||
private readonly IWebHostEnvironment _environment;
|
private readonly IWebHostEnvironment _environment;
|
||||||
|
private readonly IConfigurationRoot _config;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules,ITenantRepository tenants, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ILogManager logger)
|
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules,ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IConfigurationRoot config, IServiceProvider serviceProvider, ILogManager logger)
|
||||||
{
|
{
|
||||||
_moduleDefinitions = moduleDefinitions;
|
_moduleDefinitions = moduleDefinitions;
|
||||||
_modules = modules;
|
_modules = modules;
|
||||||
_tenants = tenants;
|
_tenants = tenants;
|
||||||
|
_sql = sql;
|
||||||
_userPermissions = userPermissions;
|
_userPermissions = userPermissions;
|
||||||
_installationManager = installationManager;
|
_installationManager = installationManager;
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
|
_config = config;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@ -99,76 +104,61 @@ namespace Oqtane.Controllers
|
|||||||
public void Delete(int id, int siteid)
|
public void Delete(int id, int siteid)
|
||||||
{
|
{
|
||||||
ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid);
|
ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid);
|
||||||
if (moduledefinition != null)
|
if (moduledefinition != null )
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
|
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType) && Utilities.GetAssemblyName(moduledefinition.ServerManagerType) != "Oqtane.Server")
|
||||||
{
|
{
|
||||||
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
|
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
|
||||||
if (moduletype != null && moduletype.GetInterface("IInstallable") != null)
|
|
||||||
{
|
|
||||||
foreach (Tenant tenant in _tenants.GetTenants())
|
foreach (Tenant tenant in _tenants.GetTenants())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if (moduletype.GetInterface("IInstallable") != null)
|
||||||
{
|
{
|
||||||
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
||||||
((IInstallable)moduleobject).Uninstall(tenant);
|
((IInstallable)moduleobject).Uninstall(tenant);
|
||||||
}
|
}
|
||||||
catch
|
else
|
||||||
{
|
{
|
||||||
// an error occurred executing the uninstall
|
_sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + ".Uninstall.sql");
|
||||||
}
|
}
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "{ModuleDefinitionName} Uninstalled For Tenant {Tenant}", moduledefinition.ModuleDefinitionName, tenant.Name);
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
}
|
|
||||||
|
|
||||||
// format root assembly name
|
|
||||||
string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName);
|
|
||||||
if (assemblyname != "Oqtane.Client")
|
|
||||||
{
|
{
|
||||||
assemblyname = assemblyname.Replace(".Client", "");
|
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Uninstalling {ModuleDefinitionName} For Tenant {Tenant} {Error}", moduledefinition.ModuleDefinitionName, tenant.Name, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// clean up module static resource folder
|
// clean up module static resource folder
|
||||||
string folder = Path.Combine(_environment.WebRootPath, Path.Combine("Modules",assemblyname));
|
string folder = Path.Combine(_environment.WebRootPath, Path.Combine("Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName)));
|
||||||
if (Directory.Exists(folder))
|
if (Directory.Exists(folder))
|
||||||
{
|
{
|
||||||
Directory.Delete(folder, true);
|
Directory.Delete(folder, true);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {AssemblynName}", assemblyname);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove module assembly from /bin
|
// get root assembly name ( note that this only works if modules follow a specific naming convention for their assemblies )
|
||||||
|
string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName).ToLower();
|
||||||
|
assemblyname = assemblyname.Replace(".client", "").Replace(".oqtane", "");
|
||||||
|
|
||||||
|
// remove module assemblies from /bin
|
||||||
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
foreach (string file in Directory.EnumerateFiles(binfolder, assemblyname + "*.*"))
|
foreach (string file in Directory.EnumerateFiles(binfolder, assemblyname + "*.*"))
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(file);
|
System.IO.File.Delete(file);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly Removed {Filename}", file);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly {Filename} Removed For {ModuleDefinitionName}", file, moduledefinition.ModuleDefinitionName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove module definition
|
// remove module definition
|
||||||
_moduleDefinitions.DeleteModuleDefinition(id, siteid);
|
_moduleDefinitions.DeleteModuleDefinition(id, siteid);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition Deleted {ModuleDefinitionName}", moduledefinition.Name);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
|
||||||
|
|
||||||
// restart application
|
// restart application
|
||||||
_installationManager.RestartApplication();
|
_installationManager.RestartApplication();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET api/<controller>/load/assembyname
|
|
||||||
[HttpGet("load/{assemblyname}")]
|
|
||||||
public IActionResult Load(string assemblyname)
|
|
||||||
{
|
|
||||||
if (Path.GetExtension(assemblyname).ToLower() == ".dll")
|
|
||||||
{
|
|
||||||
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
|
||||||
byte[] file = System.IO.File.ReadAllBytes(Path.Combine(binfolder, assemblyname));
|
|
||||||
return File(file, "application/octet-stream", assemblyname);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Download Assembly {Assembly}", assemblyname);
|
|
||||||
HttpContext.Response.StatusCode = 401;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST api/<controller>?moduleid=x
|
// POST api/<controller>?moduleid=x
|
||||||
@ -185,13 +175,13 @@ namespace Oqtane.Controllers
|
|||||||
if (moduleDefinition.Template == "internal")
|
if (moduleDefinition.Template == "internal")
|
||||||
{
|
{
|
||||||
rootPath = Utilities.PathCombine(rootFolder.FullName,"\\");
|
rootPath = Utilities.PathCombine(rootFolder.FullName,"\\");
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Modules, Oqtane.Client";
|
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + "s, Oqtane.Client";
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name + "s","\\");
|
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name + "s","\\");
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Modules, " + moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Client.Oqtane";
|
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + "s, " + moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Client.Oqtane";
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Server.Oqtane";
|
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Server.Oqtane";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +194,11 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
if (moduleDefinition.Template == "internal")
|
if (moduleDefinition.Template == "internal")
|
||||||
{
|
{
|
||||||
// need logic to add embedded scripts to Oqtane.Server.csproj - also you need to remove them on uninstall
|
// add embedded resources to project
|
||||||
|
List<string> resources = new List<string>();
|
||||||
|
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name + "s", "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + "s.1.0.0.sql"));
|
||||||
|
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name + "s", "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Uninstall.sql"));
|
||||||
|
EmbedResourceFiles(Utilities.PathCombine(rootPath, "Oqtane.Server", "Oqtane.Server.csproj"), resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
_installationManager.RestartApplication();
|
_installationManager.RestartApplication();
|
||||||
@ -253,5 +247,19 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EmbedResourceFiles(string projectfile, List<string> resources)
|
||||||
|
{
|
||||||
|
XDocument project = XDocument.Load(projectfile);
|
||||||
|
var itemGroup = project.Descendants("ItemGroup").Descendants("EmbeddedResource").FirstOrDefault().Parent;
|
||||||
|
if (itemGroup != null)
|
||||||
|
{
|
||||||
|
foreach (var resource in resources)
|
||||||
|
{
|
||||||
|
itemGroup.Add(new XElement("EmbeddedResource", new XAttribute("Include", resource)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
project.Save(projectfile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ namespace Oqtane.Controllers
|
|||||||
page.EditMode = false;
|
page.EditMode = false;
|
||||||
page.ThemeType = parent.ThemeType;
|
page.ThemeType = parent.ThemeType;
|
||||||
page.LayoutType = parent.LayoutType;
|
page.LayoutType = parent.LayoutType;
|
||||||
|
page.DefaultContainerType = parent.DefaultContainerType;
|
||||||
page.Icon = parent.Icon;
|
page.Icon = parent.Icon;
|
||||||
page.Permissions = new List<Permission> {
|
page.Permissions = new List<Permission> {
|
||||||
new Permission(PermissionNames.View, userid, true),
|
new Permission(PermissionNames.View, userid, true),
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@ -17,6 +19,7 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
// GET: api/<controller>
|
// GET: api/<controller>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Authorize(Roles = Constants.HostRole)]
|
||||||
public IEnumerable<SiteTemplate> Get()
|
public IEnumerable<SiteTemplate> Get()
|
||||||
{
|
{
|
||||||
return _siteTemplates.GetSiteTemplates();
|
return _siteTemplates.GetSiteTemplates();
|
||||||
|
@ -54,22 +54,20 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
List<Theme> themes = _themes.GetThemes().ToList();
|
List<Theme> themes = _themes.GetThemes().ToList();
|
||||||
Theme theme = themes.Where(item => item.ThemeName == themename).FirstOrDefault();
|
Theme theme = themes.Where(item => item.ThemeName == themename).FirstOrDefault();
|
||||||
if (theme != null)
|
if (theme != null && Utilities.GetAssemblyName(theme.ThemeName) != "Oqtane.Client")
|
||||||
{
|
{
|
||||||
themename = theme.ThemeName.Substring(0, theme.ThemeName.IndexOf(","));
|
// clean up theme static resource folder
|
||||||
|
string folder = Path.Combine(_environment.WebRootPath, "Themes" , Utilities.GetTypeName(theme.ThemeName));
|
||||||
string folder = Path.Combine(_environment.WebRootPath, "Themes" , themename);
|
|
||||||
if (Directory.Exists(folder))
|
if (Directory.Exists(folder))
|
||||||
{
|
{
|
||||||
Directory.Delete(folder, true);
|
Directory.Delete(folder, true);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Static Resources Removed For {ThemeName}", theme.ThemeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove theme assembly from /bin
|
||||||
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
foreach (string file in Directory.EnumerateFiles(binfolder, themename + "*.dll"))
|
System.IO.File.Delete(Path.Combine(binfolder, Utilities.GetAssemblyName(theme.ThemeName) + ".dll"));
|
||||||
{
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assembly {Filename} Removed For {ThemeName}", Utilities.GetAssemblyName(theme.ThemeName) + ".dll", themename);
|
||||||
System.IO.File.Delete(file);
|
|
||||||
}
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Deleted {ThemeName}", themename);
|
|
||||||
|
|
||||||
_installationManager.RestartApplication();
|
_installationManager.RestartApplication();
|
||||||
}
|
}
|
||||||
|
26
Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs
Normal file
26
Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
|
||||||
|
namespace Oqtane.Extensions
|
||||||
|
{
|
||||||
|
public static class ApplicationBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IApplicationBuilder ConfigureOqtaneAssemblies(this IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
var startUps = AppDomain.CurrentDomain
|
||||||
|
.GetOqtaneAssemblies()
|
||||||
|
.SelectMany(x => x.GetInstances<IServerStartup>());
|
||||||
|
|
||||||
|
foreach (var startup in startUps)
|
||||||
|
{
|
||||||
|
startup.Configure(app, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
|
||||||
// ReSharper disable once CheckNamespace
|
// ReSharper disable once CheckNamespace
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
@ -30,6 +31,22 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return mvcBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static IMvcBuilder ConfigureOqtaneMvc(this IMvcBuilder mvcBuilder)
|
||||||
|
{
|
||||||
|
var startUps = AppDomain.CurrentDomain
|
||||||
|
.GetOqtaneAssemblies()
|
||||||
|
.SelectMany(x => x.GetInstances<IServerStartup>());
|
||||||
|
|
||||||
|
foreach (var startup in startUps)
|
||||||
|
{
|
||||||
|
startup.ConfigureMvc(mvcBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
return mvcBuilder;
|
return mvcBuilder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,21 +8,23 @@ using Microsoft.Extensions.Hosting;
|
|||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
|
using Oqtane.Services;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using Oqtane.UI;
|
||||||
|
|
||||||
// ReSharper disable once CheckNamespace
|
// ReSharper disable once CheckNamespace
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
public static class OqtaneServiceCollectionExtensions
|
public static class OqtaneServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddOqtaneParts(this IServiceCollection services)
|
public static IServiceCollection AddOqtaneParts(this IServiceCollection services, Runtime runtime)
|
||||||
{
|
{
|
||||||
LoadAssemblies();
|
LoadAssemblies();
|
||||||
services.AddOqtaneServices();
|
services.AddOqtaneServices(runtime);
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddOqtaneServices(this IServiceCollection services)
|
private static IServiceCollection AddOqtaneServices(this IServiceCollection services, Runtime runtime)
|
||||||
{
|
{
|
||||||
if (services is null)
|
if (services is null)
|
||||||
{
|
{
|
||||||
@ -53,11 +55,24 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddSingleton(hostedServiceType, serviceType);
|
services.AddSingleton(hostedServiceType, serviceType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var startUps = assembly.GetInstances<IServerStartup>();
|
||||||
|
foreach (var startup in startUps)
|
||||||
|
{
|
||||||
|
startup.ConfigureServices(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (runtime == Runtime.Server)
|
||||||
|
{
|
||||||
|
assembly.GetInstances<IClientStartup>()
|
||||||
|
.ToList()
|
||||||
|
.ForEach(x => x.ConfigureServices(services));
|
||||||
|
}
|
||||||
|
}
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void LoadAssemblies()
|
private static void LoadAssemblies()
|
||||||
{
|
{
|
||||||
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||||
|
@ -332,10 +332,13 @@ namespace Oqtane.Infrastructure
|
|||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
var moduledefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
var moduledefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
||||||
|
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
||||||
foreach (var moduledefinition in moduledefinitions.GetModuleDefinitions())
|
foreach (var moduledefinition in moduledefinitions.GetModuleDefinitions())
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType) && !string.IsNullOrEmpty(moduledefinition.ReleaseVersions))
|
if (!string.IsNullOrEmpty(moduledefinition.ReleaseVersions) && !string.IsNullOrEmpty(moduledefinition.ServerManagerType))
|
||||||
{
|
{
|
||||||
|
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
|
||||||
|
|
||||||
string[] versions = moduledefinition.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
string[] versions = moduledefinition.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
|
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
|
||||||
{
|
{
|
||||||
@ -350,19 +353,22 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
if (index == -1) index = 0;
|
if (index == -1) index = 0;
|
||||||
for (int i = index; i < versions.Length; i++)
|
for (int i = index; i < versions.Length; i++)
|
||||||
{
|
|
||||||
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
|
|
||||||
if (moduletype != null && moduletype.GetInterface("IInstallable") != null)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if (moduletype.GetInterface("IInstallable") != null)
|
||||||
{
|
{
|
||||||
var moduleobject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduletype);
|
var moduleobject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduletype);
|
||||||
((IInstallable)moduleobject).Install(tenant, versions[i]);
|
((IInstallable)moduleobject).Install(tenant, versions[i]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + "." + versions[i] + ".sql");
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " - " + ex.Message.ToString();
|
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " Version " + versions[i] + " - " + ex.Message.ToString();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
var webRootPath = _environment.WebRootPath;
|
var webRootPath = _environment.WebRootPath;
|
||||||
|
|
||||||
var install = UnpackPackages(folders, webRootPath);
|
var install = InstallPackages(folders, webRootPath);
|
||||||
|
|
||||||
if (install && restart)
|
if (install && restart)
|
||||||
{
|
{
|
||||||
@ -36,7 +36,7 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool UnpackPackages(string folders, string webRootPath)
|
public static bool InstallPackages(string folders, string webRootPath)
|
||||||
{
|
{
|
||||||
bool install = false;
|
bool install = false;
|
||||||
string binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
string binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||||
@ -44,14 +44,12 @@ namespace Oqtane.Infrastructure
|
|||||||
foreach (string folder in folders.Split(','))
|
foreach (string folder in folders.Split(','))
|
||||||
{
|
{
|
||||||
string sourceFolder = Path.Combine(webRootPath, folder);
|
string sourceFolder = Path.Combine(webRootPath, folder);
|
||||||
|
|
||||||
// create folder if it does not exist
|
|
||||||
if (!Directory.Exists(sourceFolder))
|
if (!Directory.Exists(sourceFolder))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(sourceFolder);
|
Directory.CreateDirectory(sourceFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate through packages
|
// iterate through Nuget packages in source folder
|
||||||
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
|
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
|
||||||
{
|
{
|
||||||
string name = Path.GetFileNameWithoutExtension(packagename);
|
string name = Path.GetFileNameWithoutExtension(packagename);
|
||||||
@ -89,28 +87,25 @@ namespace Oqtane.Infrastructure
|
|||||||
// deploy to appropriate locations
|
// deploy to appropriate locations
|
||||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||||
{
|
{
|
||||||
|
string foldername = Path.GetDirectoryName(entry.FullName).Split('\\')[0];
|
||||||
string filename = Path.GetFileName(entry.FullName);
|
string filename = Path.GetFileName(entry.FullName);
|
||||||
switch (Path.GetExtension(filename).ToLower())
|
|
||||||
{
|
|
||||||
case ".pdb":
|
|
||||||
case ".dll":
|
|
||||||
if (binFolder != null) entry.ExtractToFile(Path.Combine(binFolder, filename), true);
|
|
||||||
break;
|
|
||||||
case ".png":
|
|
||||||
case ".jpg":
|
|
||||||
case ".jpeg":
|
|
||||||
case ".gif":
|
|
||||||
case ".svg":
|
|
||||||
case ".js":
|
|
||||||
case ".css":
|
|
||||||
string entryPath = Utilities.PathCombine(entry.FullName.Replace("wwwroot", name).Split('/'));
|
|
||||||
filename = Path.Combine(sourceFolder, entryPath);
|
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(filename)))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.ExtractToFile(filename, true);
|
switch (foldername)
|
||||||
|
{
|
||||||
|
case "lib":
|
||||||
|
filename = Path.Combine(binFolder, filename);
|
||||||
|
ExtractFile(entry, filename);
|
||||||
|
break;
|
||||||
|
case "wwwroot":
|
||||||
|
filename = Path.Combine(sourceFolder, Utilities.PathCombine(entry.FullName.Replace("wwwroot", name).Split('/')));
|
||||||
|
ExtractFile(entry, filename);
|
||||||
|
break;
|
||||||
|
case "content":
|
||||||
|
if (Path.GetDirectoryName(entry.FullName) != "content") // assets must be in subfolders
|
||||||
|
{
|
||||||
|
filename = Path.Combine(webRootPath, Utilities.PathCombine(entry.FullName.Replace("content", "").Split('/')));
|
||||||
|
ExtractFile(entry, filename);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,6 +121,15 @@ namespace Oqtane.Infrastructure
|
|||||||
return install;
|
return install;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ExtractFile(ZipArchiveEntry entry, string filename)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Path.GetDirectoryName(filename)))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||||
|
}
|
||||||
|
entry.ExtractToFile(filename, true);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpgradeFramework()
|
public void UpgradeFramework()
|
||||||
{
|
{
|
||||||
string folder = Path.Combine(_environment.WebRootPath, "Framework");
|
string folder = Path.Combine(_environment.WebRootPath, "Framework");
|
||||||
|
17
Oqtane.Server/Infrastructure/Interfaces/IServerStartup.cs
Normal file
17
Oqtane.Server/Infrastructure/Interfaces/IServerStartup.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public interface IServerStartup
|
||||||
|
{
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||||
|
void ConfigureServices(IServiceCollection services);
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
void Configure(IApplicationBuilder app, IWebHostEnvironment env);
|
||||||
|
void ConfigureMvc(IMvcBuilder mvcBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,9 +55,9 @@ namespace Oqtane.SiteTemplates
|
|||||||
new Permission(PermissionNames.View, Constants.AdminRole, true),
|
new Permission(PermissionNames.View, Constants.AdminRole, true),
|
||||||
new Permission(PermissionNames.Edit, Constants.AdminRole, true)
|
new Permission(PermissionNames.Edit, Constants.AdminRole, true)
|
||||||
}.EncodePermissions(),
|
}.EncodePermissions(),
|
||||||
Content = "<p><a href=\"https://www.oqtane.org\" target=\"_new\">Oqtane</a> is an open source <b>modular application framework</b> built from the ground up using modern .NET Core technology. It leverages the revolutionary new Blazor component model to create a <b>fully dynamic</b> web development experience which can be executed on a client or server. Whether you are looking for a platform to <b>accelerate your web development</b> efforts, or simply interested in exploring the anatomy of a large-scale Blazor application, Oqtane provides a solid foundation based on proven enterprise architectural principles.</p>" +
|
Content = "<p><a href=\"https://www.oqtane.org\" target=\"_new\">Oqtane</a> is an open source <b>modular application framework</b> that provides advanced functionality for developing web and mobile applications on ASP.NET Core. It leverages the revolutionary new Blazor component model to compose a <b>fully dynamic</b> web development experience which can be hosted either client-side or server-side. Whether you are looking for a platform to <b>accelerate your web development</b> efforts, or simply interested in exploring the anatomy of a large-scale Blazor application, Oqtane provides a solid foundation based on proven enterprise architectural principles.</p>" +
|
||||||
"<p align=\"center\"><a href=\"https://www.oqtane.org\" target=\"_new\"><img class=\"img-fluid\" src=\"oqtane.png\"></a></p><p align=\"center\"><a class=\"btn btn-primary\" href=\"https://www.oqtane.org/Community\" target=\"_new\">Join Our Community</a> <a class=\"btn btn-primary\" href=\"https://github.com/oqtane/oqtane.framework\" target=\"_new\">Clone Our Repo</a></p>" +
|
"<p align=\"center\"><a href=\"https://www.oqtane.org\" target=\"_new\"><img class=\"img-fluid\" src=\"oqtane-white.png\"></a></p><p align=\"center\"><a class=\"btn btn-primary\" href=\"https://www.oqtane.org/Community\" target=\"_new\">Join Our Community</a> <a class=\"btn btn-primary\" href=\"https://github.com/oqtane/oqtane.framework\" target=\"_new\">Clone Our Repo</a></p>" +
|
||||||
"<p><a href=\"https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor\" target=\"_new\">Blazor</a> is a single-page app framework that lets you build interactive web applications using C# instead of JavaScript. Client-side Blazor relies on WebAssembly, an open web standard that does not require plugins or code transpilation in order to run natively in a web browser. Server-side Blazor uses SignalR to host your application on a web server and provide a responsive and robust debugging experience. Blazor applications works in all modern web browsers, including mobile browsers.</p>" +
|
"<p><a href=\"https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor\" target=\"_new\">Blazor</a> is an open source and cross-platform web UI framework for building single-page apps using .NET and C# instead of JavaScript. Blazor WebAssembly relies on Wasm, an open web standard that does not require plugins or code transpilation in order to run natively in a web browser. Blazor Server uses SignalR to host your application on a web server and provide a responsive and robust development experience. Blazor applications work in all modern web browsers, including mobile browsers.</p>" +
|
||||||
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">ASP.NET Core 3</a>, the popular cross platform web development framework from Microsoft that extends the <a href=\"https://dotnet.microsoft.com/learn/dotnet/what-is-dotnet\" target=\"_new\" >.NET developer platform</a> with tools and libraries for building web apps.</p>"
|
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">ASP.NET Core 3</a>, the popular cross platform web development framework from Microsoft that extends the <a href=\"https://dotnet.microsoft.com/learn/dotnet/what-is-dotnet\" target=\"_new\" >.NET developer platform</a> with tools and libraries for building web apps.</p>"
|
||||||
},
|
},
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "MIT License", Pane = "Content",
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "MIT License", Pane = "Content",
|
||||||
@ -132,16 +132,16 @@ namespace Oqtane.SiteTemplates
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (System.IO.File.Exists(Path.Combine(_environment.WebRootPath, "images", "logo.png")))
|
if (System.IO.File.Exists(Path.Combine(_environment.WebRootPath, "images", "logo-white.png")))
|
||||||
{
|
{
|
||||||
string folderpath = Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", site.TenantId.ToString(), "Sites", site.SiteId.ToString(),"\\");
|
string folderpath = Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", site.TenantId.ToString(), "Sites", site.SiteId.ToString(),"\\");
|
||||||
System.IO.Directory.CreateDirectory(folderpath);
|
System.IO.Directory.CreateDirectory(folderpath);
|
||||||
if (!System.IO.File.Exists(Path.Combine(folderpath, "logo.png")))
|
if (!System.IO.File.Exists(Path.Combine(folderpath, "logo-white.png")))
|
||||||
{
|
{
|
||||||
System.IO.File.Copy(Path.Combine(_environment.WebRootPath, "images", "logo.png"), Path.Combine(folderpath, "logo.png"));
|
System.IO.File.Copy(Path.Combine(_environment.WebRootPath, "images", "logo-white.png"), Path.Combine(folderpath, "logo-white.png"));
|
||||||
}
|
}
|
||||||
Folder folder = _folderRepository.GetFolder(site.SiteId, "");
|
Folder folder = _folderRepository.GetFolder(site.SiteId, "");
|
||||||
Oqtane.Models.File file = _fileRepository.AddFile(new Oqtane.Models.File { FolderId = folder.FolderId, Name = "logo.png", Extension = "png", Size = 8192, ImageHeight = 80, ImageWidth = 250 });
|
Oqtane.Models.File file = _fileRepository.AddFile(new Oqtane.Models.File { FolderId = folder.FolderId, Name = "logo-white.png", Extension = "png", Size = 8192, ImageHeight = 80, ImageWidth = 250 });
|
||||||
site.LogoFileId = file.FileId;
|
site.LogoFileId = file.FileId;
|
||||||
_siteRepository.UpdateSite(site);
|
_siteRepository.UpdateSite(site);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<LangVersion>7.3</LangVersion>
|
<LangVersion>7.3</LangVersion>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>0.9.1</Version>
|
<Version>1.0.0</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -16,33 +16,26 @@
|
|||||||
<PackageReleaseNotes>Not for production use.</PackageReleaseNotes>
|
<PackageReleaseNotes>Not for production use.</PackageReleaseNotes>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="Scripts\Tenant.0.9.1.sql" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Scripts\Master.0.9.0.sql" />
|
||||||
|
<EmbeddedResource Include="Scripts\Tenant.0.9.0.sql" />
|
||||||
|
<EmbeddedResource Include="Scripts\Tenant.0.9.1.sql" />
|
||||||
|
<EmbeddedResource Include="Scripts\Tenant.0.9.2.sql" />
|
||||||
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.1.0.0.sql" />
|
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.1.0.0.sql" />
|
||||||
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.Uninstall.sql" />
|
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.Uninstall.sql" />
|
||||||
<EmbeddedResource Include="Scripts\Master.0.9.0.sql" />
|
|
||||||
<EmbeddedResource Include="Scripts\Tenant.0.9.1.sql" />
|
|
||||||
<EmbeddedResource Include="Scripts\Tenant.0.9.0.sql" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="dbup" Version="4.3.0" />
|
<PackageReference Include="dbup" Version="4.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0-rc1.20223.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.4" />
|
||||||
<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.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.1.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
|
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
|
||||||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -14,8 +14,6 @@
|
|||||||
<link id="fav-icon" rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
<link id="fav-icon" rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
||||||
<!-- stub the PWA manifest but defer the assignment of href -->
|
<!-- stub the PWA manifest but defer the assignment of href -->
|
||||||
<link id="pwa-manifest" rel="manifest" />
|
<link id="pwa-manifest" rel="manifest" />
|
||||||
<link href="css/quill/quill1.3.6.bubble.css" rel="stylesheet" />
|
|
||||||
<link href="css/quill/quill1.3.6.snow.css" rel="stylesheet" />
|
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
<link href="css/app.css" rel="stylesheet" />
|
<link href="css/app.css" rel="stylesheet" />
|
||||||
</head>
|
</head>
|
||||||
@ -25,10 +23,7 @@
|
|||||||
<component type="typeof(Oqtane.App)" render-mode="Server" />
|
<component type="typeof(Oqtane.App)" render-mode="Server" />
|
||||||
</app>
|
</app>
|
||||||
|
|
||||||
<script src="js/site.js"></script>
|
|
||||||
<script src="js/interop.js"></script>
|
<script src="js/interop.js"></script>
|
||||||
<script src="js/quill1.3.6.min.js"></script>
|
|
||||||
<script src="js/quill-blot-formatter.min.js"></script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||||
|
@ -213,8 +213,8 @@ namespace Oqtane.Repository
|
|||||||
if (moduletype != null)
|
if (moduletype != null)
|
||||||
{
|
{
|
||||||
// get property values from IModule
|
// get property values from IModule
|
||||||
var moduleobject = Activator.CreateInstance(moduletype);
|
var moduleobject = Activator.CreateInstance(moduletype) as IModule;
|
||||||
moduledefinition = (ModuleDefinition) moduletype.GetProperty("ModuleDefinition").GetValue(moduleobject);
|
moduledefinition = moduleobject.ModuleDefinition;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -261,8 +261,8 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
moduledefinition = moduledefinitions[index];
|
moduledefinition = moduledefinitions[index];
|
||||||
// actions
|
// actions
|
||||||
var modulecontrolobject = Activator.CreateInstance(modulecontroltype);
|
var modulecontrolobject = Activator.CreateInstance(modulecontroltype) as IModuleControl;
|
||||||
string actions = (string) modulecontroltype.GetProperty("Actions")?.GetValue(modulecontrolobject);
|
string actions = modulecontrolobject.Actions;
|
||||||
if (!string.IsNullOrEmpty(actions))
|
if (!string.IsNullOrEmpty(actions))
|
||||||
{
|
{
|
||||||
foreach (string action in actions.Split(','))
|
foreach (string action in actions.Split(','))
|
||||||
|
@ -757,6 +757,7 @@ namespace Oqtane.Repository
|
|||||||
EditMode = pagetemplate.EditMode,
|
EditMode = pagetemplate.EditMode,
|
||||||
ThemeType = "",
|
ThemeType = "",
|
||||||
LayoutType = "",
|
LayoutType = "",
|
||||||
|
DefaultContainerType = "",
|
||||||
Icon = pagetemplate.Icon,
|
Icon = pagetemplate.Icon,
|
||||||
Permissions = pagetemplate.PagePermissions,
|
Permissions = pagetemplate.PagePermissions,
|
||||||
IsPersonalizable = pagetemplate.IsPersonalizable,
|
IsPersonalizable = pagetemplate.IsPersonalizable,
|
||||||
|
@ -66,8 +66,8 @@ namespace Oqtane.Repository
|
|||||||
.Where(item => item.GetInterfaces().Contains(typeof(ITheme))).FirstOrDefault();
|
.Where(item => item.GetInterfaces().Contains(typeof(ITheme))).FirstOrDefault();
|
||||||
if (themetype != null)
|
if (themetype != null)
|
||||||
{
|
{
|
||||||
var themeobject = Activator.CreateInstance(themetype);
|
var themeobject = Activator.CreateInstance(themetype) as ITheme;
|
||||||
theme = (Theme)themetype.GetProperty("Theme").GetValue(themeobject);
|
theme = themeobject.Theme;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
migration script
|
Version 0.9.1 migration script
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
18
Oqtane.Server/Scripts/Tenant.0.9.2.sql
Normal file
18
Oqtane.Server/Scripts/Tenant.0.9.2.sql
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Version 0.9.2 migration script
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[Role]
|
||||||
|
ALTER COLUMN [Description] VARCHAR (256) NOT NULL
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[Page] ADD
|
||||||
|
[DefaultContainerType] [nvarchar](200) NULL
|
||||||
|
GO
|
||||||
|
|
||||||
|
UPDATE [dbo].[Page]
|
||||||
|
SET [DefaultContainerType] = ''
|
||||||
|
GO
|
||||||
|
|
@ -14,11 +14,13 @@ using Microsoft.Extensions.Configuration;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Oqtane.Extensions;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using Oqtane.UI;
|
||||||
|
|
||||||
namespace Oqtane
|
namespace Oqtane
|
||||||
{
|
{
|
||||||
@ -26,6 +28,7 @@ namespace Oqtane
|
|||||||
{
|
{
|
||||||
public IConfigurationRoot Configuration { get; }
|
public IConfigurationRoot Configuration { get; }
|
||||||
private string _webRoot;
|
private string _webRoot;
|
||||||
|
private Runtime _runtime;
|
||||||
|
|
||||||
public Startup(IWebHostEnvironment env)
|
public Startup(IWebHostEnvironment env)
|
||||||
{
|
{
|
||||||
@ -33,6 +36,9 @@ namespace Oqtane
|
|||||||
.SetBasePath(env.ContentRootPath)
|
.SetBasePath(env.ContentRootPath)
|
||||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
|
||||||
Configuration = builder.Build();
|
Configuration = builder.Build();
|
||||||
|
|
||||||
|
_runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server;
|
||||||
|
|
||||||
_webRoot = env.WebRootPath;
|
_webRoot = env.WebRootPath;
|
||||||
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data"));
|
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data"));
|
||||||
}
|
}
|
||||||
@ -157,7 +163,7 @@ namespace Oqtane
|
|||||||
services.AddSingleton<IDatabaseManager, DatabaseManager>();
|
services.AddSingleton<IDatabaseManager, DatabaseManager>();
|
||||||
|
|
||||||
// install any modules or themes ( this needs to occur BEFORE the assemblies are loaded into the app domain )
|
// install any modules or themes ( this needs to occur BEFORE the assemblies are loaded into the app domain )
|
||||||
InstallationManager.UnpackPackages("Modules,Themes", _webRoot);
|
InstallationManager.InstallPackages("Modules,Themes", _webRoot);
|
||||||
|
|
||||||
// register transient scoped core services
|
// register transient scoped core services
|
||||||
services.AddTransient<IModuleDefinitionRepository, ModuleDefinitionRepository>();
|
services.AddTransient<IModuleDefinitionRepository, ModuleDefinitionRepository>();
|
||||||
@ -187,14 +193,13 @@ namespace Oqtane
|
|||||||
services.AddTransient<ISqlRepository, SqlRepository>();
|
services.AddTransient<ISqlRepository, SqlRepository>();
|
||||||
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
||||||
|
|
||||||
// load the external assemblies into the app domain
|
// load the external assemblies into the app domain, install services
|
||||||
services.AddOqtaneParts();
|
services.AddOqtaneParts(_runtime);
|
||||||
|
|
||||||
services.AddMvc()
|
services.AddMvc()
|
||||||
|
.AddNewtonsoftJson()
|
||||||
.AddOqtaneApplicationParts() // register any Controllers from custom modules
|
.AddOqtaneApplicationParts() // register any Controllers from custom modules
|
||||||
.AddNewtonsoftJson();
|
.ConfigureOqtaneMvc(); // any additional configuration from IStart classes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
services.AddSwaggerGen(c =>
|
services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
@ -217,14 +222,12 @@ namespace Oqtane
|
|||||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||||
app.UseHsts();
|
app.UseHsts();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseBlazorFrameworkFiles();
|
app.UseBlazorFrameworkFiles();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(c =>
|
app.UseSwaggerUI(c =>
|
||||||
{
|
{
|
||||||
@ -237,6 +240,7 @@ namespace Oqtane
|
|||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
endpoints.MapFallbackToPage("/_Host");
|
endpoints.MapFallbackToPage("/_Host");
|
||||||
});
|
});
|
||||||
|
app.ConfigureOqtaneAssemblies(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<br /><br /><h1 align="center">Please Wait... Upgrade In Progress....</h1>
|
<br /><br /><h1 align="center">Please Wait... Upgrade In Progress....</h1>
|
||||||
<img src="https://www.oqtane.org/Portals/0/oqtane.png" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);" />
|
<img src="https://www.oqtane.org/Portals/0/oqtane-black.png" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);" />
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
/* HtmlText Module Custom Styles */
|
@ -101,6 +101,12 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-logo {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.breadcrumbs {
|
.breadcrumbs {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 275px;
|
left: 275px;
|
||||||
@ -164,6 +170,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
|
.app-logo {
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.breadcrumbs {
|
.breadcrumbs {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 150px;
|
top: 150px;
|
||||||
|
File diff suppressed because it is too large
Load Diff
BIN
Oqtane.Server/wwwroot/images/error.png
Normal file
BIN
Oqtane.Server/wwwroot/images/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user