@ -1,7 +1,6 @@
|
||||
@namespace Oqtane.Modules.Admin.Login
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject IUserService UserService
|
||||
@inject IServiceProvider ServiceProvider
|
||||
|
||||
@ -96,7 +95,7 @@
|
||||
{
|
||||
await logger.LogInformation("Login Successful For Username {Username}", _username);
|
||||
// complete the login on the server so that the cookies are set correctly on SignalR
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
|
||||
var fields = new { __RequestVerificationToken = antiforgerytoken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
||||
await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/login/", fields);
|
||||
|
@ -4,7 +4,6 @@
|
||||
@inject IFileService FileService
|
||||
@inject IModuleDefinitionService ModuleDefinitionService
|
||||
@inject IPackageService PackageService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@if (_packages != null)
|
||||
{
|
||||
@ -79,7 +78,7 @@
|
||||
try
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IModuleDefinitionService ModuleDefinitionService
|
||||
@inject IPackageService PackageService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@if (_moduleDefinitions == null)
|
||||
{
|
||||
@ -86,7 +85,7 @@ else
|
||||
await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules");
|
||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", moduledefinitionname, version);
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
||||
}
|
||||
@ -102,7 +101,7 @@ else
|
||||
try
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
@inject IFileService FileService
|
||||
@inject IThemeService ThemeService
|
||||
@inject IPackageService PackageService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@if (_packages != null)
|
||||
{
|
||||
@ -79,7 +78,7 @@
|
||||
try
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await ThemeService.InstallThemesAsync();
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IThemeService ThemeService
|
||||
@inject IPackageService PackageService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@if (_themes == null)
|
||||
{
|
||||
@ -86,7 +85,7 @@ else
|
||||
await PackageService.DownloadPackageAsync(themename, version, "Themes");
|
||||
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", themename, version);
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await ThemeService.InstallThemesAsync();
|
||||
}
|
||||
@ -102,7 +101,7 @@ else
|
||||
try
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await ThemeService.DeleteThemeAsync(Theme.ThemeName);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
@inject IFileService FileService
|
||||
@inject IPackageService PackageService
|
||||
@inject IInstallationService InstallationService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@if (_package != null)
|
||||
{
|
||||
@ -71,7 +70,7 @@
|
||||
try
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await InstallationService.Upgrade();
|
||||
}
|
||||
@ -88,7 +87,7 @@
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packageid, version, "Framework");
|
||||
ShowProgressIndicator();
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.RedirectBrowser(NavigateUrl(), 3);
|
||||
await InstallationService.Upgrade();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ else
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Profile">
|
||||
@if (profiles != null)
|
||||
@if (profiles != null && settings != null)
|
||||
{
|
||||
<table class="table table-borderless">
|
||||
@foreach (Profile profile in profiles)
|
||||
@ -126,7 +126,16 @@ else
|
||||
</Row>
|
||||
<Detail>
|
||||
<td colspan="2"></td>
|
||||
<td colspan="3">@(context.Body.Length > 100 ? context.Body.Substring(0, 100) : context.Body)</td>
|
||||
<td colspan="3">
|
||||
@{
|
||||
string input = "___";
|
||||
if (context.Body.Contains(input)){
|
||||
context.Body = context.Body.Split(input)[0];
|
||||
context.Body = context.Body.Replace("\n", "");
|
||||
context.Body = context.Body.Replace("\r", "");
|
||||
} }
|
||||
@(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
|
||||
</td>
|
||||
</Detail>
|
||||
</Pager>
|
||||
}
|
||||
@ -149,7 +158,16 @@ else
|
||||
</Row>
|
||||
<Detail>
|
||||
<td colspan="2"></td>
|
||||
<td colspan="3">@(context.Body.Length > 100 ? context.Body.Substring(0, 100) : context.Body)</td>
|
||||
<td colspan="3">
|
||||
@{
|
||||
string input = "___";
|
||||
if (context.Body.Contains(input)){
|
||||
context.Body = context.Body.Split(input)[0];
|
||||
context.Body = context.Body.Replace("\n", "");
|
||||
context.Body = context.Body.Replace("\r", "");
|
||||
} }
|
||||
@(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
|
||||
</td>
|
||||
</Detail>
|
||||
</Pager>
|
||||
}
|
||||
|
@ -9,56 +9,94 @@
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td>
|
||||
<label class="control-label">@title: </label>
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control" @bind="@username" />
|
||||
<label class="control-label">@title: </label>
|
||||
</td>
|
||||
@if (title == "From")
|
||||
{
|
||||
<td>
|
||||
<input class="form-control" @bind="@username" readonly />
|
||||
</td>
|
||||
}
|
||||
@if (title == "To")
|
||||
{
|
||||
<td>
|
||||
<input class="form-control" @bind="@username" />
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label class="control-label">Subject: </label>
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control" @bind="@subject" />
|
||||
<label class="control-label">Subject: </label>
|
||||
</td>
|
||||
@if (title == "From")
|
||||
{
|
||||
<td>
|
||||
<input class="form-control" @bind="@subject" readonly />
|
||||
</td>
|
||||
}
|
||||
@if (title == "To")
|
||||
{
|
||||
<td>
|
||||
<input class="form-control" @bind="@subject" />
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
@if (title == "From")
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<label class="control-label">Date: </label>
|
||||
<label class="control-label">Date: </label>
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control" @bind="@createdon" />
|
||||
<input class="form-control" @bind="@createdon" readonly />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<td>
|
||||
<label class="control-label">Message: </label>
|
||||
</td>
|
||||
<td>
|
||||
<textarea class="form-control" @bind="@body" rows="5" />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (title == "From")
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<label class="control-label">Message: </label>
|
||||
</td>
|
||||
<td>
|
||||
<textarea class="form-control" @bind="@body" rows="5" readonly />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (title == "To")
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<label class="control-label">Message: </label>
|
||||
</td>
|
||||
<td>
|
||||
<textarea class="form-control" @bind="@body" rows="5" />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
|
||||
|
||||
@if (reply != string.Empty)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick="Send">Send</button>
|
||||
}
|
||||
<button type="button" class="btn btn-primary" @onclick="Send">Send</button> }
|
||||
else
|
||||
{
|
||||
if (title == "From")
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick="Reply">Reply</button>
|
||||
}
|
||||
<button type="button" class="btn btn-primary" @onclick="Reply">Reply</button>}
|
||||
}
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
|
||||
<br />
|
||||
<br />
|
||||
<p>@reply</p>
|
||||
}
|
||||
@if (title == "To")
|
||||
{
|
||||
<div class="control-group">
|
||||
<label class="control-label">Original Message </label>
|
||||
<textarea class="form-control" @bind="@reply" rows="5" readonly />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
private int notificationid;
|
||||
@ -124,8 +162,12 @@
|
||||
private void Reply()
|
||||
{
|
||||
title = "To";
|
||||
subject = "RE: " + subject;
|
||||
if (!subject.Contains("RE:"))
|
||||
{
|
||||
subject = "RE: " + subject;
|
||||
}
|
||||
reply = body;
|
||||
body = "\n\n____________________________________________\nSent: " + createdon + "\nSubject: " + subject + "\n\n" + body;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@ -165,5 +207,5 @@
|
||||
AddModuleMessage("Error Adding Notification", MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,8 @@
|
||||
|
||||
if (!string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
_iconSpan = $"<span class=\"oi oi-{IconName}\"></span> ";
|
||||
_iconSpan = $"<span class=\"oi oi-{IconName}\"></span>{(IconOnly?"":" ")}";
|
||||
|
||||
}
|
||||
|
||||
_url = EditUrl(Action, _parameters);
|
||||
|
@ -4,7 +4,6 @@
|
||||
@attribute [OqtaneIgnore]
|
||||
@inject IFolderService FolderService
|
||||
@inject IFileService FileService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@if (_folders != null)
|
||||
{
|
||||
@ -258,7 +257,7 @@
|
||||
|
||||
private async Task UploadFile()
|
||||
{
|
||||
var interop = new Interop(JsRuntime);
|
||||
var interop = new Interop(JSRuntime);
|
||||
var upload = await interop.GetFiles(_fileinputid);
|
||||
if (upload.Length > 0)
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@inherits ModuleBase
|
||||
@attribute [OqtaneIgnore]
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
<div class="row" style="margin-bottom: 50px;">
|
||||
<div class="col">
|
||||
@ -108,6 +107,13 @@
|
||||
[Parameter]
|
||||
public string DebugLevel { get; set; } = "info";
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_content = Content; // raw HTML
|
||||
@ -117,7 +123,9 @@
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
await interop.CreateEditor(
|
||||
_editorElement,
|
||||
@ -143,13 +151,13 @@
|
||||
|
||||
public async Task RefreshRichText()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.LoadEditorContent(_editorElement, _content);
|
||||
}
|
||||
|
||||
public async Task RefreshRawHtml()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
_content = await interop.GetHtml(_editorElement);
|
||||
StateHasChanged();
|
||||
}
|
||||
@ -157,7 +165,7 @@
|
||||
public async Task<string> GetHtml()
|
||||
{
|
||||
// get rich text content
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
string content = await interop.GetHtml(_editorElement);
|
||||
|
||||
if (_original != content)
|
||||
@ -179,7 +187,7 @@
|
||||
var fileid = _fileManager.GetFileId();
|
||||
if (fileid != -1)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.InsertImage(_editorElement, ContentUrl(fileid));
|
||||
_filemanagervisible = false;
|
||||
_message = string.Empty;
|
||||
@ -200,19 +208,19 @@
|
||||
// other rich text editor methods which can be used by developers
|
||||
public async Task<string> GetText()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
return await interop.GetText(_editorElement);
|
||||
}
|
||||
|
||||
public async Task<string> GetContent()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
return await interop.GetContent(_editorElement);
|
||||
}
|
||||
|
||||
public async Task EnableEditor(bool mode)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JsRuntime);
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.EnableEditor(_editorElement, mode);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace Oqtane.Modules.Controls
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public Task CreateEditor(
|
||||
public async Task CreateEditor(
|
||||
ElementReference quillElement,
|
||||
ElementReference toolbar,
|
||||
bool readOnly,
|
||||
@ -23,15 +23,14 @@ namespace Oqtane.Modules.Controls
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
await _jsRuntime.InvokeAsync<object>(
|
||||
"Oqtane.RichTextEditor.createQuill",
|
||||
quillElement, toolbar, readOnly,
|
||||
placeholder, theme, debugLevel);
|
||||
return Task.CompletedTask;
|
||||
quillElement, toolbar, readOnly, placeholder, theme, debugLevel);
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
// handle exception
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<a data-toggle="collapse" class="app-link-unstyled" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name">
|
||||
<a data-toggle="collapse" class="app-link-unstyled" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
|
||||
<h5>@_heading</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div class="ml-auto">
|
||||
<a data-toggle="collapse" class="app-link-unstyled float-right" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name">
|
||||
<a data-toggle="collapse" class="app-link-unstyled float-right" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
|
||||
<i class="oi oi-chevron-bottom"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -11,13 +11,13 @@
|
||||
<li class="nav-item">
|
||||
@if (tabPanel.Name == ActiveTab)
|
||||
{
|
||||
<a class="nav-link active" data-toggle="tab" href="#@tabPanel.Name" role="tab">
|
||||
<a class="nav-link active" data-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
|
||||
@DisplayHeading(tabPanel.Name, tabPanel.Heading)
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a class="nav-link" data-toggle="tab" href="#@tabPanel.Name" role="tab">
|
||||
<a class="nav-link" data-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
|
||||
@DisplayHeading(tabPanel.Name, tabPanel.Heading)
|
||||
</a>
|
||||
}
|
||||
|
@ -27,12 +27,8 @@
|
||||
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" }
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.snow.css" }
|
||||
};
|
||||
|
||||
private RichTextEditor RichTextEditorHtml;
|
||||
|
@ -7,6 +7,8 @@ using System;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.UI;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Linq;
|
||||
|
||||
namespace Oqtane.Modules
|
||||
{
|
||||
@ -19,6 +21,9 @@ namespace Oqtane.Modules
|
||||
[Inject]
|
||||
protected ILogService LoggingService { get; set; }
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
|
||||
@ -28,7 +33,6 @@ namespace Oqtane.Modules
|
||||
[CascadingParameter]
|
||||
protected ModuleInstance ModuleInstance { get; set; }
|
||||
|
||||
|
||||
// optional interface properties
|
||||
public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security
|
||||
|
||||
@ -40,7 +44,25 @@ namespace Oqtane.Modules
|
||||
|
||||
public virtual List<Resource> Resources { get; set; }
|
||||
|
||||
// base lifecycle method for handling JSInterop script registration
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||
{
|
||||
var scripts = new List<object>();
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||
{
|
||||
scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" });
|
||||
}
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeScripts(scripts.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// path method
|
||||
|
||||
public string ModulePath()
|
||||
|
@ -153,7 +153,7 @@ namespace Oqtane.Services
|
||||
public string GetSetting(Dictionary<string, string> settings, string settingName, string defaultValue)
|
||||
{
|
||||
string value = defaultValue;
|
||||
if (settings.ContainsKey(settingName))
|
||||
if (settings != null && settings.ContainsKey(settingName))
|
||||
{
|
||||
value = settings[settingName];
|
||||
}
|
||||
@ -162,6 +162,10 @@ namespace Oqtane.Services
|
||||
|
||||
public Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue)
|
||||
{
|
||||
if (settings == null)
|
||||
{
|
||||
settings = new Dictionary<string, string>();
|
||||
}
|
||||
if (settings.ContainsKey(settingName))
|
||||
{
|
||||
settings[settingName] = settingValue;
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Themes.BlazorTheme
|
||||
@inherits ThemeBase
|
||||
@implements IThemeControl
|
||||
|
||||
<div class="breadcrumbs">
|
||||
<Breadcrumbs />
|
||||
@ -30,6 +31,11 @@
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css", Integrity = "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.3.1.slim.min.js", Integrity = "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js", Integrity = "sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", Integrity = "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM", CrossOrigin = "anonymous" }
|
||||
};
|
||||
|
||||
}
|
@ -1,64 +1,11 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Themes
|
||||
{
|
||||
public abstract class ContainerBase : ComponentBase, IContainerControl
|
||||
public abstract class ContainerBase : ThemeBase, IContainerControl
|
||||
{
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
protected Module ModuleState { get; set; }
|
||||
|
||||
public virtual string Name { get; set; }
|
||||
public virtual string Thumbnail { get; set; }
|
||||
|
||||
public string ThemePath()
|
||||
{
|
||||
return "Themes/" + GetType().Namespace + "/";
|
||||
}
|
||||
|
||||
public string NavigateUrl()
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path);
|
||||
}
|
||||
|
||||
public string NavigateUrl(string path)
|
||||
{
|
||||
return NavigateUrl(path, "");
|
||||
}
|
||||
|
||||
public string NavigateUrl(string path, string parameters)
|
||||
{
|
||||
return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters);
|
||||
}
|
||||
|
||||
public string EditUrl(string action, string parameters)
|
||||
{
|
||||
return EditUrl(ModuleState.ModuleId, action, parameters);
|
||||
}
|
||||
|
||||
public string EditUrl(int moduleid, string action)
|
||||
{
|
||||
return EditUrl(moduleid, action, "");
|
||||
}
|
||||
|
||||
public string EditUrl(int moduleid, string action, string parameters)
|
||||
{
|
||||
return EditUrl(PageState.Page.Path, moduleid, action, parameters);
|
||||
}
|
||||
|
||||
public string EditUrl(string path, int moduleid, string action, string parameters)
|
||||
{
|
||||
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Themes
|
||||
namespace Oqtane.Themes
|
||||
{
|
||||
public abstract class LayoutBase : ComponentBase, ILayoutControl
|
||||
public abstract class LayoutBase : ThemeBase, ILayoutControl
|
||||
{
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
public virtual string Name { get; set; }
|
||||
public virtual string Thumbnail { get; set; }
|
||||
public virtual string Panes { get; set; }
|
||||
|
||||
public string LayoutPath()
|
||||
{
|
||||
return "Themes/" + GetType().Namespace + "/";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Themes.OqtaneTheme
|
||||
@inherits ThemeBase
|
||||
@implements IThemeControl
|
||||
|
||||
<main role="main">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-primary fixed-top">
|
||||
@ -23,10 +24,10 @@
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "BootswatchCyborg.css" },
|
||||
// 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
|
||||
//new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css", Integrity = "sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css", Integrity = "sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.3.1.slim.min.js", Integrity = "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js", Integrity = "sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", Integrity = "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM", CrossOrigin = "anonymous" }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Themes
|
||||
{
|
||||
public abstract class ThemeBase : ComponentBase, IThemeControl
|
||||
public abstract class ThemeBase : ComponentBase
|
||||
{
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; }
|
||||
@ -22,6 +23,25 @@ namespace Oqtane.Themes
|
||||
public virtual string Panes { get; set; }
|
||||
public virtual List<Resource> Resources { get; set; }
|
||||
|
||||
// base lifecycle method for handling JSInterop script registration
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||
{
|
||||
var scripts = new List<object>();
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||
{
|
||||
scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" });
|
||||
}
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeScripts(scripts.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// path method
|
||||
|
||||
public string ThemePath()
|
||||
@ -60,5 +80,10 @@ namespace Oqtane.Themes
|
||||
{
|
||||
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters);
|
||||
}
|
||||
|
||||
public string ContentUrl(int fileid)
|
||||
{
|
||||
return Utilities.ContentUrl(PageState.Alias, fileid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Themes
|
||||
namespace Oqtane.Themes
|
||||
{
|
||||
public abstract class ThemeControlBase : ComponentBase
|
||||
public abstract class ThemeControlBase : ThemeBase
|
||||
{
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
|
||||
public string NavigateUrl()
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path);
|
||||
}
|
||||
|
||||
public string NavigateUrl(string path)
|
||||
{
|
||||
return NavigateUrl(path, "");
|
||||
}
|
||||
|
||||
public string NavigateUrl(string path, string parameters)
|
||||
{
|
||||
return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters);
|
||||
}
|
||||
|
||||
public string EditUrl(int moduleid, string action)
|
||||
{
|
||||
return EditUrl(moduleid, action, "");
|
||||
}
|
||||
|
||||
public string EditUrl(int moduleid, string action, string parameters)
|
||||
{
|
||||
return EditUrl(PageState.Page.Path, moduleid, action, parameters);
|
||||
}
|
||||
|
||||
public string EditUrl(string path, int moduleid, string action, string parameters)
|
||||
{
|
||||
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters);
|
||||
}
|
||||
|
||||
public string ContentUrl(int fileid)
|
||||
{
|
||||
return Utilities.ContentUrl(PageState.Alias, fileid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
@inject IInstallationService InstallationService
|
||||
@inject ISiteService SiteService
|
||||
@inject IUserService UserService
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
@ -138,6 +139,15 @@
|
||||
private string _integratedSecurityDisplay = "display: none;";
|
||||
private string _loadingDisplay = "display: none;";
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("app-stylesheet", "stylesheet", "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css", "text/css", "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T", "anonymous", "");
|
||||
}
|
||||
}
|
||||
|
||||
private void SetIntegratedSecurity(ChangeEventArgs e)
|
||||
{
|
||||
_integratedSecurityDisplay = Convert.ToBoolean((string)e.Value)
|
||||
|
@ -17,9 +17,9 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
"Oqtane.Interop.setCookie",
|
||||
name, value, days);
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.setCookie",
|
||||
name, value, days);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
@ -46,7 +46,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.updateTitle",
|
||||
title);
|
||||
return Task.CompletedTask;
|
||||
@ -61,7 +61,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeMeta",
|
||||
id, attribute, name, content, key);
|
||||
return Task.CompletedTask;
|
||||
@ -76,7 +76,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeLink",
|
||||
id, rel, href, type, integrity, crossorigin, key);
|
||||
return Task.CompletedTask;
|
||||
@ -91,7 +91,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeLinks",
|
||||
(object) links);
|
||||
return Task.CompletedTask;
|
||||
@ -106,7 +106,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeScript",
|
||||
id, src, integrity, crossorigin, content, location, key);
|
||||
return Task.CompletedTask;
|
||||
@ -117,18 +117,17 @@ namespace Oqtane.UI
|
||||
}
|
||||
}
|
||||
|
||||
public Task IncludeScripts(object[] scripts)
|
||||
public async Task IncludeScripts(object[] scripts)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
await _jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeScripts",
|
||||
(object)scripts);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
// ignore exception
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +135,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.removeElementsById",
|
||||
prefix, first, last);
|
||||
return Task.CompletedTask;
|
||||
@ -165,9 +164,9 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
"Oqtane.Interop.submitForm",
|
||||
path, fields);
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.submitForm",
|
||||
path, fields);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
@ -194,9 +193,9 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
"Oqtane.Interop.uploadFiles",
|
||||
posturl, folder, id);
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.uploadFiles",
|
||||
posturl, folder, id);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
@ -209,7 +208,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.refreshBrowser",
|
||||
force, wait);
|
||||
return Task.CompletedTask;
|
||||
@ -224,7 +223,7 @@ namespace Oqtane.UI
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.redirectBrowser",
|
||||
url, wait);
|
||||
return Task.CompletedTask;
|
||||
@ -234,5 +233,6 @@ namespace Oqtane.UI
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,6 @@
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
await LogService.Log(null, null, null, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", path);
|
||||
// redirect to login page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(alias.Path, "login", "returnurl=" + path));
|
||||
}
|
||||
@ -361,20 +360,26 @@
|
||||
|
||||
string panes = "";
|
||||
Type themetype = Type.GetType(page.ThemeType);
|
||||
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||
if (themeobject != null)
|
||||
if (themetype != null)
|
||||
{
|
||||
panes = themeobject.Panes;
|
||||
page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
|
||||
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))
|
||||
{
|
||||
Type layouttype = Type.GetType(page.LayoutType);
|
||||
var layoutobject = Activator.CreateInstance(layouttype) as ILayoutControl;
|
||||
if (layoutobject != null)
|
||||
if (layouttype != null)
|
||||
{
|
||||
panes = layoutobject.Panes;
|
||||
var layoutobject = Activator.CreateInstance(layouttype) as ILayoutControl;
|
||||
if (layoutobject != null)
|
||||
{
|
||||
panes = layoutobject.Panes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,27 +30,15 @@
|
||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||
}
|
||||
|
||||
// include page resources
|
||||
// manage stylesheets for this page
|
||||
string batch = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
var scripts = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources)
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
||||
{
|
||||
switch (resource.ResourceType)
|
||||
{
|
||||
case ResourceType.Stylesheet:
|
||||
links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" });
|
||||
break;
|
||||
case ResourceType.Script:
|
||||
scripts.Add(new { id = "app-script-" + batch + "-" + (scripts.Count + 1).ToString("00"), src = resource.Url, integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", content = "", location = "body", key = "" });
|
||||
break;
|
||||
}
|
||||
links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" });
|
||||
}
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
await interop.IncludeScripts(scripts.ToArray());
|
||||
// remove any page resource references which are no longer required for this page
|
||||
await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00");
|
||||
await interop.RemoveElementsById("app-script", "", "app-script-" + batch + "-00");
|
||||
|
||||
// add favicon
|
||||
if (PageState.Site.FaviconFileId != null)
|
||||
|
@ -75,7 +75,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
private User Filter(User user)
|
||||
{
|
||||
if (user != null && !User.IsInRole(Constants.AdminRole) && User.Identity.Name != user.Username)
|
||||
if (user != null && !User.IsInRole(Constants.AdminRole) && User.Identity.Name?.ToLower() != user.Username.ToLower())
|
||||
{
|
||||
user.DisplayName = "";
|
||||
user.Email = "";
|
||||
|
@ -194,10 +194,12 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
if (install.TenantName == Constants.MasterTenant)
|
||||
{
|
||||
MigrateScriptNamingConvention("Master", install.ConnectionString);
|
||||
|
||||
var upgradeConfig = DeployChanges
|
||||
.To
|
||||
.SqlDatabase(NormalizeConnectionString(install.ConnectionString))
|
||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains("Master.") && s.EndsWith(".sql",StringComparison.OrdinalIgnoreCase));
|
||||
.To
|
||||
.SqlDatabase(NormalizeConnectionString(install.ConnectionString))
|
||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains("Master.") && s.EndsWith(".sql",StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var upgrade = upgradeConfig.Build();
|
||||
if (upgrade.IsUpgradeRequired())
|
||||
@ -285,6 +287,8 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
foreach (var tenant in db.Tenant.ToList())
|
||||
{
|
||||
MigrateScriptNamingConvention("Tenant", tenant.DBConnectionString);
|
||||
|
||||
var upgradeConfig = DeployChanges.To.SqlDatabase(NormalizeConnectionString(tenant.DBConnectionString))
|
||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains("Tenant.") && s.EndsWith(".sql", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@ -568,6 +572,18 @@ namespace Oqtane.Infrastructure
|
||||
if (string.IsNullOrEmpty(value)) value = defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private void MigrateScriptNamingConvention(string scriptType, string connectionString)
|
||||
{
|
||||
// migrate to new naming convention for scripts
|
||||
var migrateConfig = DeployChanges.To.SqlDatabase(NormalizeConnectionString(connectionString))
|
||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s == scriptType + ".00.00.00.00.sql");
|
||||
var migrate = migrateConfig.Build();
|
||||
if (migrate.IsUpgradeRequired())
|
||||
{
|
||||
migrate.PerformUpgrade();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,16 +23,14 @@
|
||||
<EmbeddedResource Remove="wwwroot\Modules\Templates\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Scripts\Master.1.0.1.sql" />
|
||||
<None Remove="Scripts\Tenant.1.0.1.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Scripts\Master.1.0.1.sql" />
|
||||
<EmbeddedResource Include="Scripts\Master.0.9.0.sql" />
|
||||
<EmbeddedResource Include="Scripts\Tenant.1.0.1.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="Scripts\Master.00.00.00.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Master.00.09.00.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Master.01.00.01.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Tenant.00.00.00.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Tenant.00.09.00.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Tenant.00.09.01.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Tenant.00.09.02.00.sql" />
|
||||
<EmbeddedResource Include="Scripts\Tenant.01.00.01.00.sql" />
|
||||
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.1.0.0.sql" />
|
||||
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.Uninstall.sql" />
|
||||
</ItemGroup>
|
||||
|
@ -14,8 +14,8 @@
|
||||
<link id="app-favicon" rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
||||
<!-- stub the PWA manifest but defer the assignment of href -->
|
||||
<link id="app-manifest" rel="manifest" />
|
||||
<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="css/app.css" />
|
||||
<script src="js/loadjs.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@(Html.AntiForgeryToken())
|
||||
@ -23,10 +23,18 @@
|
||||
<component type="typeof(Oqtane.App)" render-mode="Server" />
|
||||
</app>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
<environment include="Staging,Production">
|
||||
An error has occurred. This application may no longer respond until reloaded.
|
||||
</environment>
|
||||
<environment include="Development">
|
||||
An unhandled exception has occurred. See browser dev tools for details.
|
||||
</environment>
|
||||
<a href="~/" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
|
||||
<script src="js/interop.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://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>
|
||||
|
||||
@if (Configuration.GetSection("Runtime").Value == "WebAssembly")
|
||||
{
|
||||
|
@ -24,9 +24,9 @@ namespace Oqtane.Repository
|
||||
return _db.Role.Where(item => item.SiteId == siteId || item.SiteId == null);
|
||||
}
|
||||
|
||||
|
||||
public Role AddRole(Role role)
|
||||
{
|
||||
role.Description = role.Description.Substring(0, (role.Description.Length > 256) ? 256 : role.Description.Length);
|
||||
_db.Role.Add(role);
|
||||
_db.SaveChanges();
|
||||
return role;
|
||||
@ -34,6 +34,7 @@ namespace Oqtane.Repository
|
||||
|
||||
public Role UpdateRole(Role role)
|
||||
{
|
||||
role.Description = role.Description.Substring(0, (role.Description.Length > 256) ? 256 : role.Description.Length);
|
||||
_db.Entry(role).State = EntityState.Modified;
|
||||
_db.SaveChanges();
|
||||
return role;
|
||||
|
10
Oqtane.Server/Scripts/Master.00.00.00.00.sql
Normal file
10
Oqtane.Server/Scripts/Master.00.00.00.00.sql
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
|
||||
migrate to new naming convention for scripts
|
||||
|
||||
*/
|
||||
|
||||
UPDATE [dbo].[SchemaVersions] SET ScriptName = 'Oqtane.Scripts.Master.00.09.00.00.sql' WHERE ScriptName = 'Oqtane.Scripts.Master.0.9.0.sql'
|
||||
GO
|
||||
UPDATE [dbo].[SchemaVersions] SET ScriptName = 'Oqtane.Scripts.Master.01.00.01.00.sql' WHERE ScriptName = 'Oqtane.Scripts.Master.1.0.1.sql'
|
||||
GO
|
14
Oqtane.Server/Scripts/Tenant.00.00.00.00.sql
Normal file
14
Oqtane.Server/Scripts/Tenant.00.00.00.00.sql
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
|
||||
migrate to new naming convention for scripts
|
||||
|
||||
*/
|
||||
|
||||
UPDATE [dbo].[SchemaVersions] SET ScriptName = 'Oqtane.Scripts.Tenant.00.09.00.00.sql' WHERE ScriptName = 'Oqtane.Scripts.Tenant.0.9.0.sql'
|
||||
GO
|
||||
UPDATE [dbo].[SchemaVersions] SET ScriptName = 'Oqtane.Scripts.Tenant.00.09.01.00.sql' WHERE ScriptName = 'Oqtane.Scripts.Tenant.0.9.1.sql'
|
||||
GO
|
||||
UPDATE [dbo].[SchemaVersions] SET ScriptName = 'Oqtane.Scripts.Tenant.00.09.02.00.sql' WHERE ScriptName = 'Oqtane.Scripts.Tenant.0.9.2.sql'
|
||||
GO
|
||||
UPDATE [dbo].[SchemaVersions] SET ScriptName = 'Oqtane.Scripts.Tenant.01.00.01.00.sql' WHERE ScriptName = 'Oqtane.Scripts.Tenant.1.0.1.sql'
|
||||
GO
|
@ -29,7 +29,8 @@ namespace Oqtane
|
||||
public IConfigurationRoot Configuration { get; }
|
||||
private string _webRoot;
|
||||
private Runtime _runtime;
|
||||
|
||||
private bool _useSwagger;
|
||||
|
||||
public Startup(IWebHostEnvironment env)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
@ -37,9 +38,12 @@ namespace Oqtane
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
|
||||
Configuration = builder.Build();
|
||||
|
||||
_runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server;
|
||||
_runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server;
|
||||
|
||||
//add possibility to switch off swagger on production.
|
||||
_useSwagger = Configuration.GetSection("UseSwagger").Value != "false";
|
||||
|
||||
_webRoot = env.WebRootPath;
|
||||
_webRoot = env.WebRootPath;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data"));
|
||||
}
|
||||
|
||||
@ -47,7 +51,6 @@ namespace Oqtane
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
services.AddServerSideBlazor();
|
||||
|
||||
// setup HttpClient for server side in a client side compatible fashion ( with auth cookie )
|
||||
@ -59,7 +62,7 @@ namespace Oqtane
|
||||
var navigationManager = s.GetRequiredService<NavigationManager>();
|
||||
var httpContextAccessor = s.GetRequiredService<IHttpContextAccessor>();
|
||||
var authToken = httpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Identity.Application"];
|
||||
var client = new HttpClient(new HttpClientHandler { UseCookies = false });
|
||||
var client = new HttpClient(new HttpClientHandler {UseCookies = false});
|
||||
if (authToken != null)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Identity.Application=" + authToken);
|
||||
@ -121,7 +124,7 @@ namespace Oqtane
|
||||
.AddEntityFrameworkStores<TenantDBContext>()
|
||||
.AddSignInManager()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
|
||||
services.Configure<IdentityOptions>(options =>
|
||||
{
|
||||
// Password settings
|
||||
@ -199,14 +202,12 @@ namespace Oqtane
|
||||
services.AddMvc()
|
||||
.AddNewtonsoftJson()
|
||||
.AddOqtaneApplicationParts() // register any Controllers from custom modules
|
||||
.ConfigureOqtaneMvc(); // any additional configuration from IStart classes.
|
||||
.ConfigureOqtaneMvc(); // any additional configuration from IStart classes.
|
||||
|
||||
services.AddSwaggerGen(c =>
|
||||
if (_useSwagger)
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Oqtane", Version = "v1" });
|
||||
});
|
||||
|
||||
|
||||
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo {Title = "Oqtane", Version = "v1"}); });
|
||||
}
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
@ -230,11 +231,11 @@ namespace Oqtane
|
||||
app.UseRouting();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
if (_useSwagger)
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Oqtane V1");
|
||||
});
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Oqtane V1"); });
|
||||
}
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
@ -242,7 +243,6 @@ namespace Oqtane
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapFallbackToPage("/_Host");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,4 +163,23 @@ app {
|
||||
margin-left: -5em;
|
||||
width: 10em;
|
||||
}
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
@ -145,7 +145,7 @@ Oqtane.Interop = {
|
||||
script.innerHTML = content;
|
||||
}
|
||||
script.async = false;
|
||||
this.loadScript(script, location)
|
||||
this.addScript(script, location)
|
||||
.then(() => {
|
||||
console.log(src + ' loaded');
|
||||
})
|
||||
@ -185,7 +185,7 @@ Oqtane.Interop = {
|
||||
}
|
||||
}
|
||||
},
|
||||
loadScript: function (script, location) {
|
||||
addScript: function (script, location) {
|
||||
if (location === 'head') {
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
@ -198,9 +198,48 @@ Oqtane.Interop = {
|
||||
script.onerror = rej();
|
||||
});
|
||||
},
|
||||
includeScripts: function (scripts) {
|
||||
for (let i = 0; i < scripts.length; i++) {
|
||||
this.includeScript(scripts[i].id, scripts[i].src, scripts[i].integrity, scripts[i].crossorigin, scripts[i].content, scripts[i].location, scripts[i].key);
|
||||
includeScripts: async function (scripts) {
|
||||
const bundles = [];
|
||||
for (let s = 0; s < scripts.length; s++) {
|
||||
if (scripts[s].bundle === '') {
|
||||
scripts[s].bundle = scripts[s].href;
|
||||
}
|
||||
if (!bundles.includes(scripts[s].bundle)) {
|
||||
bundles.push(scripts[s].bundle);
|
||||
}
|
||||
}
|
||||
const urls = [];
|
||||
for (let b = 0; b < bundles.length; b++) {
|
||||
for (let s = 0; s < scripts.length; s++) {
|
||||
if (scripts[s].bundle === bundles[b]) {
|
||||
urls.push(scripts[s].href);
|
||||
}
|
||||
}
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
if (loadjs.isDefined(bundles[b])) {
|
||||
resolve(true);
|
||||
}
|
||||
else {
|
||||
loadjs(urls, bundles[b], {
|
||||
async: true,
|
||||
returnPromise: true,
|
||||
before: function (path, element) {
|
||||
for (let s = 0; s < scripts.length; s++) {
|
||||
if (path === scripts[s].href && scripts[s].integrity !== '') {
|
||||
element.integrity = scripts[s].integrity;
|
||||
}
|
||||
if (path === scripts[s].href && scripts[s].crossorigin !== '') {
|
||||
element.crossOrigin = scripts[s].crossorigin;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(function () { resolve(true) })
|
||||
.catch(function (pathsNotFound) { reject(false) });
|
||||
}
|
||||
});
|
||||
await promise;
|
||||
urls = [];
|
||||
}
|
||||
},
|
||||
getAbsoluteUrl: function (url) {
|
||||
|
1
Oqtane.Server/wwwroot/js/loadjs.min.js
vendored
Normal file
1
Oqtane.Server/wwwroot/js/loadjs.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
loadjs=function(){var h=function(){},c={},u={},f={};function o(e,n){if(e){var r=f[e];if(u[e]=n,r)for(;r.length;)r[0](e,n),r.splice(0,1)}}function l(e,n){e.call&&(e={success:e}),n.length?(e.error||h)(n):(e.success||h)(e)}function d(r,t,s,i){var c,o,e=document,n=s.async,u=(s.numRetries||0)+1,f=s.before||h,l=r.replace(/[\?|#].*$/,""),a=r.replace(/^(css|img)!/,"");i=i||0,/(^css!|\.css$)/.test(l)?((o=e.createElement("link")).rel="stylesheet",o.href=a,(c="hideFocus"in o)&&o.relList&&(c=0,o.rel="preload",o.as="style")):/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(l)?(o=e.createElement("img")).src=a:((o=e.createElement("script")).src=r,o.async=void 0===n||n),!(o.onload=o.onerror=o.onbeforeload=function(e){var n=e.type[0];if(c)try{o.sheet.cssText.length||(n="e")}catch(e){18!=e.code&&(n="e")}if("e"==n){if((i+=1)<u)return d(r,t,s,i)}else if("preload"==o.rel&&"style"==o.as)return o.rel="stylesheet";t(r,n,e.defaultPrevented)})!==f(r,o)&&e.head.appendChild(o)}function r(e,n,r){var t,s;if(n&&n.trim&&(t=n),s=(t?r:n)||{},t){if(t in c)throw"LoadJS";c[t]=!0}function i(n,r){!function(e,t,n){var r,s,i=(e=e.push?e:[e]).length,c=i,o=[];for(r=function(e,n,r){if("e"==n&&o.push(e),"b"==n){if(!r)return;o.push(e)}--i||t(o)},s=0;s<c;s++)d(e[s],r,n)}(e,function(e){l(s,e),n&&l({success:n,error:r},e),o(t,e)},s)}if(s.returnPromise)return new Promise(i);i()}return r.ready=function(e,n){return function(e,r){e=e.push?e:[e];var n,t,s,i=[],c=e.length,o=c;for(n=function(e,n){n.length&&i.push(e),--o||r(i)};c--;)t=e[c],(s=u[t])?n(t,s):(f[t]=f[t]||[]).push(n)}(e,function(e){l(n,e)}),r},r.done=function(e){o(e,[])},r.reset=function(){c={},u={},f={}},r.isDefined=function(e){return e in c},r}();
|
@ -1,7 +1,7 @@
|
||||
var Oqtane = Oqtane || {};
|
||||
|
||||
Oqtane.RichTextEditor = {
|
||||
createQuill: function (
|
||||
createQuill: async function (
|
||||
quillElement, toolBar, readOnly,
|
||||
placeholder, theme, debugLevel) {
|
||||
|
||||
|
@ -8,5 +8,6 @@ namespace Oqtane.Models
|
||||
public string Url { get; set; }
|
||||
public string Integrity { get; set; }
|
||||
public string CrossOrigin { get; set; }
|
||||
public string Bundle { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ Please note that this project is owned by the .NET Foundation and is governed by
|
||||
|
||||
**To get started with Oqtane:**
|
||||
|
||||
1. Install **[.NET Core 3.2 SDK (v3.1.300)](https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.300-windows-x64-installer)**.
|
||||
1. Install **[.NET Core 3.1 SDK (v3.1.300)](https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.300-windows-x64-installer)**.
|
||||
|
||||
2. Install the Preview edition of [Visual Studio 2019](https://visualstudio.microsoft.com/vs/preview/) (version 16.6 or higher) with the **ASP.NET and web development** workload enabled. Oqtane works with all editions of Visual Studio from Community to Enterprise. If you do not have a SQL Server installation available already and you wish to use LocalDB for development, you must also install the **.NET desktop development workload**.
|
||||
|
||||
|
Reference in New Issue
Block a user