@if (ReadOnly)
{
-
+
}
else
{
-
+
}
@@ -83,110 +83,121 @@
@code {
- private ElementReference _editorElement;
- private ElementReference _toolBar;
- private bool _filemanagervisible = false;
- private FileManager _fileManager;
- private string _content = string.Empty;
- private string _original = string.Empty;
- private string _message = string.Empty;
+ private ElementReference _editorElement;
+ private ElementReference _toolBar;
+ private bool _filemanagervisible = false;
+ private FileManager _fileManager;
+ private string _richhtml = string.Empty;
+ private string _originalrichhtml = string.Empty;
+ private string _rawhtml = string.Empty;
+ private string _originalrawhtml = string.Empty;
+ private string _message = string.Empty;
- [Parameter]
- public string Content { get; set; }
+ [Parameter]
+ public string Content { get; set; }
- [Parameter]
- public bool ReadOnly { get; set; } = false;
+ [Parameter]
+ public bool ReadOnly { get; set; } = false;
- [Parameter]
- public string Placeholder { get; set; } = "Enter Your Content...";
+ [Parameter]
+ public string Placeholder { get; set; } = "Enter Your Content...";
- // parameters only applicable to rich text editor
- [Parameter]
- public RenderFragment ToolbarContent { get; set; }
+ // parameters only applicable to rich text editor
+ [Parameter]
+ public RenderFragment ToolbarContent { get; set; }
- [Parameter]
- public string Theme { get; set; } = "snow";
+ [Parameter]
+ public string Theme { get; set; } = "snow";
- [Parameter]
- public string DebugLevel { get; set; } = "info";
+ [Parameter]
+ public string DebugLevel { get; set; } = "info";
- [Parameter]
- public bool AllowFileManagement { get; set; } = true;
+ [Parameter]
+ public bool AllowFileManagement { get; set; } = true;
- public override List Resources => new List()
+ public override List Resources => new List()
{
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.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 async Task OnParametersSetAsync()
- {
- _content = Content; // raw HTML
- await RefreshRichText();
- }
+ protected override void OnParametersSet()
+ {
+ _richhtml = Content;
+ _rawhtml = Content;
+ _originalrawhtml = _rawhtml; // preserve for comparison later
+ }
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (firstRender)
- {
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ await base.OnAfterRenderAsync(firstRender);
+
+ var interop = new RichTextEditorInterop(JSRuntime);
+
+ if (firstRender)
+ {
+ await interop.CreateEditor(
+ _editorElement,
+ _toolBar,
+ ReadOnly,
+ Placeholder,
+ Theme,
+ DebugLevel);
+
+ await interop.LoadEditorContent(_editorElement, _richhtml);
+
+ // preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
+ _originalrichhtml = await interop.GetHtml(_editorElement);
+ }
+ else
+ {
+ await interop.LoadEditorContent(_editorElement, _richhtml);
+ }
+ }
+
+ public void CloseFileManager()
+ {
+ _filemanagervisible = false;
+ _message = string.Empty;
+ StateHasChanged();
+ }
+
+ public void RefreshRichText()
+ {
+ _richhtml = _rawhtml;
+ StateHasChanged();
+ }
+
+ public async Task RefreshRawHtml()
+ {
+ var interop = new RichTextEditorInterop(JSRuntime);
+ _rawhtml = await interop.GetHtml(_editorElement);
+ StateHasChanged();
+ }
+
+ public async Task GetHtml()
+ {
+ // evaluate raw html content as first priority
+ if (_rawhtml != _originalrawhtml)
+ {
+ return _rawhtml;
+ }
+ else
+ {
+ // return rich text content if it has changed
var interop = new RichTextEditorInterop(JSRuntime);
-
- await base.OnAfterRenderAsync(firstRender);
-
- await interop.CreateEditor(
- _editorElement,
- _toolBar,
- ReadOnly,
- Placeholder,
- Theme,
- DebugLevel);
-
- await interop.LoadEditorContent(_editorElement, Content);
-
- _content = Content; // raw HTML
-
- // preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
- _original = await interop.GetHtml(_editorElement);
- }
- }
-
- public void CloseFileManager()
- {
- _filemanagervisible = false;
- _message = string.Empty;
- StateHasChanged();
- }
-
- public async Task RefreshRichText()
- {
- var interop = new RichTextEditorInterop(JSRuntime);
- await interop.LoadEditorContent(_editorElement, _content);
- }
-
- public async Task RefreshRawHtml()
- {
- var interop = new RichTextEditorInterop(JSRuntime);
- _content = await interop.GetHtml(_editorElement);
- StateHasChanged();
- }
-
- public async Task GetHtml()
- {
- // get rich text content
- var interop = new RichTextEditorInterop(JSRuntime);
- string content = await interop.GetHtml(_editorElement);
-
- if (_original != content)
- {
- // rich text content has changed - return it
- return content;
- }
- else
- {
- // return raw html content
- return _content;
- }
+ var richhtml = await interop.GetHtml(_editorElement);
+ if (richhtml != _originalrichhtml)
+ {
+ return richhtml;
+ }
+ else
+ {
+ // return original raw html content
+ return _originalrawhtml;
+ }
+ }
}
public async Task InsertImage()
@@ -212,23 +223,4 @@
}
StateHasChanged();
}
-
- // other rich text editor methods which can be used by developers
- public async Task GetText()
- {
- var interop = new RichTextEditorInterop(JSRuntime);
- return await interop.GetText(_editorElement);
- }
-
- public async Task GetContent()
- {
- var interop = new RichTextEditorInterop(JSRuntime);
- return await interop.GetContent(_editorElement);
- }
-
- public async Task EnableEditor(bool mode)
- {
- var interop = new RichTextEditorInterop(JSRuntime);
- await interop.EnableEditor(_editorElement, mode);
- }
}
diff --git a/Oqtane.Client/Modules/HtmlText/Edit.razor b/Oqtane.Client/Modules/HtmlText/Edit.razor
index 528cafef..ca86ea95 100644
--- a/Oqtane.Client/Modules/HtmlText/Edit.razor
+++ b/Oqtane.Client/Modules/HtmlText/Edit.razor
@@ -9,95 +9,186 @@
@inject IStringLocalizer Localizer
@inject IStringLocalizer SharedLocalizer
-@if (_content != null)
-{
-
-
- @SharedLocalizer["Cancel"]
- @if (!string.IsNullOrEmpty(_content))
- {
-
-
-
- }
-}
+
+
+ @if (_content != null)
+ {
+
+
+
+ @SharedLocalizer["Cancel"]
+ @if (!string.IsNullOrEmpty(_content))
+ {
+
+
+
+ }
+ }
+
+
+
+
+
+
+
+
@SharedLocalizer["CreatedOn"]
+
@SharedLocalizer["CreatedBy"]
+
+
+
+
+
+
@context.CreatedOn
+
@context.CreatedBy
+
+
+ @((MarkupString)_view)
+
+
@code {
- public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
+ public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
- public override string Title => "Edit Html/Text";
+ public override string Title => "Edit Html/Text";
- public override List Resources => new List()
-{
+ public override List Resources => new List()
+ {
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
};
- private RichTextEditor RichTextEditorHtml;
- private bool _allowfilemanagement;
- private string _content = null;
- private string _createdby;
- private DateTime _createdon;
- private string _modifiedby;
- private DateTime _modifiedon;
+ private RichTextEditor RichTextEditorHtml;
+ private bool _allowfilemanagement;
+ private string _content = null;
+ private string _createdby;
+ private DateTime _createdon;
+ private string _modifiedby;
+ private DateTime _modifiedon;
+ private List _htmltexts;
+ private string _view = "";
- protected override async Task OnInitializedAsync()
- {
- try
- {
- _allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
+ protected override async Task OnInitializedAsync()
+ {
+ try
+ {
+ _allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
+ await LoadContent();
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
+ }
+ }
- var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
- if (htmltext != null)
- {
- _content = htmltext.Content;
- _content = Utilities.FormatContent(_content, PageState.Alias, "render");
- _createdby = htmltext.CreatedBy;
- _createdon = htmltext.CreatedOn;
- _modifiedby = htmltext.ModifiedBy;
- _modifiedon = htmltext.ModifiedOn;
- }
- else
- {
- _content = string.Empty;
- }
- }
- catch (Exception ex)
- {
- await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
- AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
- }
- }
+ private async Task LoadContent()
+ {
+ var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
+ if (htmltext != null)
+ {
+ _content = htmltext.Content;
+ _content = Utilities.FormatContent(_content, PageState.Alias, "render");
+ _createdby = htmltext.CreatedBy;
+ _createdon = htmltext.CreatedOn;
+ _modifiedby = htmltext.ModifiedBy;
+ _modifiedon = htmltext.ModifiedOn;
+ }
+ else
+ {
+ _content = string.Empty;
+ }
- private async Task SaveContent()
- {
- string content = await RichTextEditorHtml.GetHtml();
- content = Utilities.FormatContent(content, PageState.Alias, "save");
+ _htmltexts = await HtmlTextService.GetHtmlTextsAsync(ModuleState.ModuleId);
+ _htmltexts = _htmltexts.OrderByDescending(item => item.CreatedOn).ToList();
- try
- {
- var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
- if (htmltext != null)
- {
- htmltext.Content = content;
- await HtmlTextService.UpdateHtmlTextAsync(htmltext);
- }
- else
- {
- htmltext = new HtmlText();
- htmltext.ModuleId = ModuleState.ModuleId;
- htmltext.Content = content;
- await HtmlTextService.AddHtmlTextAsync(htmltext);
- }
+ _view = "";
+ }
- await logger.LogInformation("Content Saved {HtmlText}", htmltext);
- NavigationManager.NavigateTo(NavigateUrl());
- }
- catch (Exception ex)
- {
- await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
- AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
- }
- }
+ private async Task SaveContent()
+ {
+ string content = await RichTextEditorHtml.GetHtml();
+ content = Utilities.FormatContent(content, PageState.Alias, "save");
+
+ try
+ {
+ var htmltext = new HtmlText();
+ htmltext.ModuleId = ModuleState.ModuleId;
+ htmltext.Content = content;
+ await HtmlTextService.AddHtmlTextAsync(htmltext);
+
+ await logger.LogInformation("Content Saved {HtmlText}", htmltext);
+ NavigationManager.NavigateTo(NavigateUrl());
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
+ }
+ }
+
+ private async Task View(Models.HtmlText htmltext)
+ {
+ try
+ {
+ htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
+ if (htmltext != null)
+ {
+ _view = htmltext.Content;
+ _view = Utilities.FormatContent(_view, PageState.Alias, "render");
+ StateHasChanged();
+ }
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.Content.View"], MessageType.Error);
+ }
+ }
+
+ private async Task Restore(Models.HtmlText htmltext)
+ {
+ try
+ {
+ htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
+ if (htmltext != null)
+ {
+ var content = htmltext.Content;
+ htmltext = new HtmlText();
+ htmltext.ModuleId = ModuleState.ModuleId;
+ htmltext.Content = content;
+ await HtmlTextService.AddHtmlTextAsync(htmltext);
+ await logger.LogInformation("Content Restored {HtmlText}", htmltext);
+ AddModuleMessage(Localizer["Message.Content.Restored"], MessageType.Success);
+ await LoadContent();
+ StateHasChanged();
+ }
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.Content.Restore"], MessageType.Error);
+ }
+ }
+
+ private async Task Delete(Models.HtmlText htmltext)
+ {
+ try
+ {
+ htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
+ if (htmltext != null)
+ {
+ await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
+ await logger.LogInformation("Content Deleted {HtmlText}", htmltext);
+ AddModuleMessage(Localizer["Message.Content.Deleted"], MessageType.Success);
+ await LoadContent();
+ StateHasChanged();
+ }
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.Content.Delete"], MessageType.Error);
+ }
+ }
}
diff --git a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs
index 85583f7e..e4dd0174 100644
--- a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs
+++ b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Oqtane.Documentation;
@@ -13,24 +15,29 @@ namespace Oqtane.Modules.HtmlText.Services
private string ApiUrl => CreateApiUrl("HtmlText");
+ public async Task> GetHtmlTextsAsync(int moduleId)
+ {
+ return await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{ApiUrl}?moduleid={moduleId}", EntityNames.Module, moduleId));
+ }
+
public async Task GetHtmlTextAsync(int moduleId)
{
return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
}
+ public async Task GetHtmlTextAsync(int htmlTextId, int moduleId)
+ {
+ return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
+ }
+
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
{
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
}
- public async Task UpdateHtmlTextAsync(Models.HtmlText htmlText)
+ public async Task DeleteHtmlTextAsync(int htmlTextId, int moduleId)
{
- await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", EntityNames.Module, htmlText.ModuleId), htmlText);
- }
-
- public async Task DeleteHtmlTextAsync(int moduleId)
- {
- await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
+ await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
}
}
}
diff --git a/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs
index 80d725a9..7ca069c6 100644
--- a/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs
+++ b/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs
@@ -1,19 +1,20 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Oqtane.Documentation;
-using Oqtane.Modules.HtmlText.Models;
namespace Oqtane.Modules.HtmlText.Services
{
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
public interface IHtmlTextService
{
- Task GetHtmlTextAsync(int ModuleId);
+ Task> GetHtmlTextsAsync(int moduleId);
+
+ Task GetHtmlTextAsync(int moduleId);
+
+ Task GetHtmlTextAsync(int htmlTextId, int moduleId);
Task AddHtmlTextAsync(Models.HtmlText htmltext);
- Task UpdateHtmlTextAsync(Models.HtmlText htmltext);
-
- Task DeleteHtmlTextAsync(int ModuleId);
+ Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
}
}
diff --git a/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx
index b29a4f1e..71c3f04f 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx
@@ -231,4 +231,10 @@
A page with path {0} already exists for the selected parent page in the Recycle Bin. Either recover the page or remove from the Recycle Bin and create it again.
+
+ Optionally enter meta tags (in exactly the form you want them to be included in the page output).
+
+
+ Meta:
+
\ No newline at end of file
diff --git a/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx
index ad6dfd25..5dc82a55 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx
@@ -264,4 +264,10 @@
Clickable?
+
+ Optionally enter meta tags (in exactly the form you want them to be included in the page output).
+
+
+ Meta:
+
\ No newline at end of file
diff --git a/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx b/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx
index e2eed7a2..5e1d2160 100644
--- a/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx
+++ b/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx
@@ -117,10 +117,52 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Are You Sure You Wish To Delete The {0} Version?
+
+
+ Are You Sure You Wish To Restore The {0} Version?
+
+
+ Created By
+
+
+ Created On
+
+
+ Delete Version
+
+
+ Delete
+
+
+ Error Deleting Version
+
An Error Occurred Loading Content
+
+ Error Restoring Version
+
An Error Occurred Saving Content
+
+ Error Viewing Version
+
+
+ Version Deleted
+
+
+ Version Restored
+
+
+ Restore Version
+
+
+ Restore
+
+
+ View
+
\ No newline at end of file
diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
index cd5bb63a..d8693bd2 100644
--- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
+++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
@@ -17,18 +17,17 @@ using Oqtane.Infrastructure;
using Oqtane.Modules;
using Oqtane.Repository;
using Oqtane.Security;
-using Oqtane.Services;
using Oqtane.Shared;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OqtaneServiceCollectionExtensions
{
- public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime, string[] supportedCultures)
+ public static IServiceCollection AddOqtane(this IServiceCollection services, string[] supportedCultures)
{
LoadAssemblies();
LoadSatelliteAssemblies(supportedCultures);
- services.AddOqtaneServices(runtime);
+ services.AddOqtaneServices();
return services;
}
@@ -190,7 +189,7 @@ namespace Microsoft.Extensions.DependencyInjection
return services;
}
- private static IServiceCollection AddOqtaneServices(this IServiceCollection services, Runtime runtime)
+ private static IServiceCollection AddOqtaneServices(this IServiceCollection services)
{
if (services is null)
{
@@ -229,14 +228,6 @@ namespace Microsoft.Extensions.DependencyInjection
{
startup.ConfigureServices(services);
}
-
- if (runtime == Runtime.Server)
- {
- // register client startup services if running on server
- assembly.GetInstances()
- .ToList()
- .ForEach(x => x.ConfigureServices(services));
- }
}
return services;
}
diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs
index cad82ac9..df58e73a 100644
--- a/Oqtane.Server/Infrastructure/DatabaseManager.cs
+++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs
@@ -28,14 +28,14 @@ namespace Oqtane.Infrastructure
{
public class DatabaseManager : IDatabaseManager
{
- private readonly IConfigurationRoot _config;
+ private readonly IConfigManager _config;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IWebHostEnvironment _environment;
private readonly IMemoryCache _cache;
private readonly IConfigManager _configManager;
private readonly ILogger _filelogger;
- public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger filelogger)
+ public DatabaseManager(IConfigManager config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger filelogger)
{
_config = config;
_serviceScopeFactory = serviceScopeFactory;
diff --git a/Oqtane.Server/Infrastructure/InstallationManager.cs b/Oqtane.Server/Infrastructure/InstallationManager.cs
index 22a8176d..41860c5e 100644
--- a/Oqtane.Server/Infrastructure/InstallationManager.cs
+++ b/Oqtane.Server/Infrastructure/InstallationManager.cs
@@ -125,6 +125,9 @@ namespace Oqtane.Infrastructure
case "ref": // ref/net*/...
filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2);
break;
+ case "refs": // refs/net*/...
+ filename = ExtractFile(entry, Path.Combine(binPath, "refs"), 2);
+ break;
}
if (filename != "")
diff --git a/Oqtane.Server/Infrastructure/LogManager.cs b/Oqtane.Server/Infrastructure/LogManager.cs
index afbb1de8..e8f58854 100644
--- a/Oqtane.Server/Infrastructure/LogManager.cs
+++ b/Oqtane.Server/Infrastructure/LogManager.cs
@@ -14,18 +14,18 @@ namespace Oqtane.Infrastructure
public class LogManager : ILogManager
{
private readonly ILogRepository _logs;
- private readonly IConfigurationRoot _config;
+ private readonly ITenantManager _tenantManager;
+ private readonly IConfigManager _config;
private readonly IUserPermissions _userPermissions;
private readonly IHttpContextAccessor _accessor;
- private readonly Alias _alias;
- public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor)
+ public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigManager config, IUserPermissions userPermissions, IHttpContextAccessor accessor)
{
_logs = logs;
+ _tenantManager = tenantManager;
_config = config;
_userPermissions = userPermissions;
_accessor = accessor;
- _alias = tenantManager.GetAlias();
}
public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args)
@@ -48,9 +48,13 @@ namespace Oqtane.Infrastructure
Log log = new Log();
log.SiteId = siteId;
- if (log.SiteId == -1 && _alias != null)
+ if (log.SiteId == -1)
{
- log.SiteId = _alias.SiteId;
+ var alias = _tenantManager.GetAlias();
+ if (alias != null)
+ {
+ log.SiteId = alias.SiteId;
+ }
}
if (log.SiteId == -1) return; // logs must be site specific
diff --git a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs
index 189a44c9..9a748d96 100644
--- a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs
+++ b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs
@@ -1,6 +1,5 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Configuration;
namespace Oqtane.Infrastructure
{
@@ -16,8 +15,8 @@ namespace Oqtane.Infrastructure
public async Task Invoke(HttpContext context)
{
// check if framework is installed
- var config = context.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
- if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection")))
+ var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager;
+ if (config.IsInstalled())
{
// get alias
var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager;
diff --git a/Oqtane.Server/Migrations/Tenant/03000104_AddVisitorReferrer.cs b/Oqtane.Server/Migrations/Tenant/03000105_AddVisitorReferrer.cs
similarity index 100%
rename from Oqtane.Server/Migrations/Tenant/03000104_AddVisitorReferrer.cs
rename to Oqtane.Server/Migrations/Tenant/03000105_AddVisitorReferrer.cs
diff --git a/Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs b/Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs
new file mode 100644
index 00000000..9dea0d49
--- /dev/null
+++ b/Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs
@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Oqtane.Databases.Interfaces;
+using Oqtane.Migrations.EntityBuilders;
+using Oqtane.Repository;
+
+namespace Oqtane.Migrations.Tenant
+{
+ [DbContext(typeof(TenantDBContext))]
+ [Migration("Tenant.03.00.03.01")]
+ public class AddPageMeta : MultiDatabaseMigration
+ {
+ public AddPageMeta(IDatabase database) : base(database)
+ {
+ }
+
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
+ pageEntityBuilder.AddStringColumn("Meta", 2000, true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
+ pageEntityBuilder.DropColumn("Meta");
+ }
+ }
+}
diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs
index 020d6e48..f269650b 100644
--- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs
+++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs
@@ -8,6 +8,8 @@ using Oqtane.Infrastructure;
using Oqtane.Controllers;
using System.Net;
using Oqtane.Documentation;
+using System.Collections.Generic;
+using System.Linq;
namespace Oqtane.Modules.HtmlText.Controllers
{
@@ -22,18 +24,60 @@ namespace Oqtane.Modules.HtmlText.Controllers
_htmlText = htmlText;
}
- // GET api//5
- [HttpGet("{id}")]
- [Authorize(Policy = PolicyNames.ViewModule)]
- public Models.HtmlText Get(int id)
+ // GET: api/?moduleid=x
+ [HttpGet]
+ [Authorize(Roles = RoleNames.Registered)]
+ public IEnumerable Get(string moduleId)
{
- if (AuthEntityId(EntityNames.Module) == id)
+ if (int.TryParse(moduleId, out int ModuleId) && AuthEntityId(EntityNames.Module) == ModuleId)
+ {
+ return _htmlText.GetHtmlTexts(ModuleId);
+ }
+ else
+ {
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {ModuleId}", moduleId);
+ HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
+ return null;
+ }
+ }
+
+ // GET api//5
+ [HttpGet("{moduleid}")]
+ [Authorize(Policy = PolicyNames.ViewModule)]
+ public Models.HtmlText Get(int moduleId)
+ {
+ if (AuthEntityId(EntityNames.Module) == moduleId)
+ {
+ var htmltexts = _htmlText.GetHtmlTexts(moduleId);
+ if (htmltexts != null && htmltexts.Any())
+ {
+ return htmltexts.OrderByDescending(item => item.CreatedOn).First();
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {ModuleId}", moduleId);
+ HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
+ return null;
+ }
+ }
+
+ // GET api//5/6
+ [HttpGet("{id}/{moduleid}")]
+ [Authorize(Policy = PolicyNames.ViewModule)]
+ public Models.HtmlText Get(int id, int moduleId)
+ {
+ if (AuthEntityId(EntityNames.Module) == moduleId)
{
return _htmlText.GetHtmlText(id);
}
else
{
- _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Get Attempt {ModuleId}", id);
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {HtmlTextId}", id);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return null;
}
@@ -53,27 +97,7 @@ namespace Oqtane.Modules.HtmlText.Controllers
}
else
{
- _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Post Attempt {HtmlText}", htmlText);
- HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
- return null;
- }
- }
-
- // PUT api//5
- [ValidateAntiForgeryToken]
- [HttpPut("{id}")]
- [Authorize(Policy = PolicyNames.EditModule)]
- public Models.HtmlText Put(int id, [FromBody] Models.HtmlText htmlText)
- {
- if (ModelState.IsValid && AuthEntityId(EntityNames.Module) == htmlText.ModuleId)
- {
- htmlText = _htmlText.UpdateHtmlText(htmlText);
- _logger.Log(LogLevel.Information, this, LogFunction.Update, "Html/Text Updated {HtmlText}", htmlText);
- return htmlText;
- }
- else
- {
- _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Put Attempt {HtmlText}", htmlText);
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Post Attempt {HtmlText}", htmlText);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return null;
}
@@ -81,18 +105,18 @@ namespace Oqtane.Modules.HtmlText.Controllers
// DELETE api//5
[ValidateAntiForgeryToken]
- [HttpDelete("{id}")]
+ [HttpDelete("{id}/{moduleid}")]
[Authorize(Policy = PolicyNames.EditModule)]
- public void Delete(int id)
+ public void Delete(int id, int moduleId)
{
- if (AuthEntityId(EntityNames.Module) == id)
+ if (AuthEntityId(EntityNames.Module) == moduleId)
{
_htmlText.DeleteHtmlText(id);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Html/Text Deleted {HtmlTextId}", id);
}
else
{
- _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Delete Attempt {ModuleId}", id);
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Delete Attempt {HtmlTextId}", id);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
}
}
diff --git a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs
index f9a862e8..6179c40c 100644
--- a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs
+++ b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs
@@ -43,19 +43,10 @@ namespace Oqtane.Modules.HtmlText.Manager
public void ImportModule(Module module, string content, string version)
{
content = WebUtility.HtmlDecode(content);
- var htmlText = _htmlText.GetHtmlText(module.ModuleId);
- if (htmlText != null)
- {
- htmlText.Content = content;
- _htmlText.UpdateHtmlText(htmlText);
- }
- else
- {
- htmlText = new Models.HtmlText();
- htmlText.ModuleId = module.ModuleId;
- htmlText.Content = content;
- _htmlText.AddHtmlText(htmlText);
- }
+ var htmlText = new Models.HtmlText();
+ htmlText.ModuleId = module.ModuleId;
+ htmlText.Content = content;
+ _htmlText.AddHtmlText(htmlText);
}
public bool Install(Tenant tenant, string version)
diff --git a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs
index a2229f0e..6f6d8e6d 100644
--- a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs
+++ b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs
@@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore;
using System.Linq;
using Oqtane.Modules.HtmlText.Models;
using Oqtane.Documentation;
+using System.Collections.Generic;
namespace Oqtane.Modules.HtmlText.Repository
{
@@ -15,11 +16,15 @@ namespace Oqtane.Modules.HtmlText.Repository
_db = context;
}
- public Models.HtmlText GetHtmlText(int moduleId)
+ public IEnumerable GetHtmlTexts(int moduleId)
{
- return _db.HtmlText.FirstOrDefault(item => item.ModuleId == moduleId);
+ return _db.HtmlText.Where(item => item.ModuleId == moduleId);
}
+ public Models.HtmlText GetHtmlText(int htmlTextId)
+ {
+ return _db.HtmlText.Find(htmlTextId);
+ }
public Models.HtmlText AddHtmlText(Models.HtmlText htmlText)
{
@@ -28,16 +33,9 @@ namespace Oqtane.Modules.HtmlText.Repository
return htmlText;
}
- public Models.HtmlText UpdateHtmlText(Models.HtmlText htmlText)
+ public void DeleteHtmlText(int htmlTextId)
{
- _db.Entry(htmlText).State = EntityState.Modified;
- _db.SaveChanges();
- return htmlText;
- }
-
- public void DeleteHtmlText(int moduleId)
- {
- Models.HtmlText htmlText = _db.HtmlText.FirstOrDefault(item => item.ModuleId == moduleId);
+ Models.HtmlText htmlText = _db.HtmlText.FirstOrDefault(item => item.HtmlTextId == htmlTextId);
if (htmlText != null) _db.HtmlText.Remove(htmlText);
_db.SaveChanges();
}
diff --git a/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs b/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs
index 014c5adc..44be5973 100644
--- a/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs
+++ b/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using Oqtane.Documentation;
using Oqtane.Modules.HtmlText.Models;
@@ -6,9 +7,9 @@ namespace Oqtane.Modules.HtmlText.Repository
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
public interface IHtmlTextRepository
{
- Models.HtmlText GetHtmlText(int moduleId);
+ IEnumerable GetHtmlTexts(int moduleId);
+ Models.HtmlText GetHtmlText(int htmlTextId);
Models.HtmlText AddHtmlText(Models.HtmlText htmlText);
- Models.HtmlText UpdateHtmlText(Models.HtmlText htmlText);
- void DeleteHtmlText(int moduleId);
+ void DeleteHtmlText(int htmlTextId);
}
}
diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml
index 86827eba..4b56af10 100644
--- a/Oqtane.Server/Pages/_Host.cshtml
+++ b/Oqtane.Server/Pages/_Host.cshtml
@@ -8,6 +8,7 @@
@Model.Title
+ @Html.Raw(@Model.Meta)
@if (!string.IsNullOrEmpty(Model.PWAScript))
@@ -20,34 +21,42 @@
@Html.Raw(Model.HeadResources)
- @(Html.AntiForgeryToken())
-
-
-
-
- An error has occurred. This application may no longer respond until reloaded.
-
-
- An unhandled exception has occurred. See browser dev tools for details.
-
- Reload
- 🗙
-
+
+ An error has occurred. This application may no longer respond until reloaded.
+
+
+ An unhandled exception has occurred. See browser dev tools for details.
+
+ Reload
+ 🗙
+