commit
a637b6d4d0
@ -1,6 +1,8 @@
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@inject IInstallationService InstallationService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject SiteState SiteState
|
||||
@inject IServiceProvider ServiceProvider
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
@ -30,35 +32,47 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string AntiForgeryToken { get; set; }
|
||||
[Parameter]
|
||||
public string AntiForgeryToken { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RemoteIPAddress { get; set; }
|
||||
[Parameter]
|
||||
public string RemoteIPAddress { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string AuthorizationToken { get; set; }
|
||||
[Parameter]
|
||||
public string AuthorizationToken { get; set; }
|
||||
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
|
||||
private PageState PageState { get; set; }
|
||||
private PageState PageState { get; set; }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.RemoteIPAddress = RemoteIPAddress;
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
SiteState.AuthorizationToken = AuthorizationToken;
|
||||
private IHttpContextAccessor accessor;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.RemoteIPAddress = RemoteIPAddress;
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
SiteState.AuthorizationToken = AuthorizationToken;
|
||||
|
||||
accessor = (IHttpContextAccessor)ServiceProvider.GetService(typeof(IHttpContextAccessor));
|
||||
if (accessor != null)
|
||||
{
|
||||
SiteState.IsPrerendering = !accessor.HttpContext.Response.HasStarted;
|
||||
}
|
||||
else
|
||||
{
|
||||
SiteState.IsPrerendering = true;
|
||||
}
|
||||
|
||||
_installation = await InstallationService.IsInstalled();
|
||||
if (_installation.Alias != null)
|
||||
@ -72,6 +86,7 @@
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// prevents flash on initial page load
|
||||
_display = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
64
Oqtane.Client/Head.razor
Normal file
64
Oqtane.Client/Head.razor
Normal file
@ -0,0 +1,64 @@
|
||||
@using System.ComponentModel
|
||||
@using Oqtane.Shared
|
||||
@inject SiteState SiteState
|
||||
|
||||
@if (!string.IsNullOrEmpty(_title))
|
||||
{
|
||||
@((MarkupString)_title)
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(_content))
|
||||
{
|
||||
@((MarkupString)_content)
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _title = "";
|
||||
private string _content = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
((INotifyPropertyChanged)SiteState.Properties).PropertyChanged += PropertyChanged;
|
||||
}
|
||||
|
||||
private void PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case "PageTitle":
|
||||
var title = "\n<title>" + SiteState.Properties.PageTitle + "</title>";
|
||||
if (title != _title)
|
||||
{
|
||||
_title = title;
|
||||
StateHasChanged();
|
||||
}
|
||||
break;
|
||||
case "HeadContent":
|
||||
var content = RemoveScripts(SiteState.Properties.HeadContent) + "\n";
|
||||
if (content != _content)
|
||||
{
|
||||
_content = content;
|
||||
StateHasChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private string RemoveScripts(string headcontent)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(headcontent))
|
||||
{
|
||||
var index = headcontent.IndexOf("<script");
|
||||
while (index >= 0)
|
||||
{
|
||||
headcontent = headcontent.Remove(index, headcontent.IndexOf("</script>") + 9 - index);
|
||||
index = headcontent.IndexOf("<script");
|
||||
}
|
||||
}
|
||||
return headcontent;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
((INotifyPropertyChanged)SiteState.Properties).PropertyChanged -= PropertyChanged;
|
||||
}
|
||||
}
|
@ -5,15 +5,17 @@
|
||||
@inject ISiteService SiteService
|
||||
@inject IUserService UserService
|
||||
@inject IDatabaseService DatabaseService
|
||||
@inject ISiteTemplateService SiteTemplateService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject IStringLocalizer<Installer> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@inject SiteState SiteState
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="mx-auto text-center">
|
||||
<img src="oqtane-black.png" />
|
||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version</div>
|
||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 7)</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="app-rule" />
|
||||
@ -61,7 +63,7 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<h2>@Localizer["ApplicationAdmin"]</h2><br />
|
||||
@ -96,6 +98,20 @@
|
||||
<input type="text" class="form-control" @bind="@_hostEmail" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="Select a site template" ResourceKey="Template">Template:</Label>
|
||||
<div class="col-sm-9">
|
||||
@if (_templates != null)
|
||||
{
|
||||
<select id="template" class="form-select" @bind="@_template" required>
|
||||
@foreach (var template in _templates)
|
||||
{
|
||||
<option value="@template.TypeName">@template.Name</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -103,7 +119,13 @@
|
||||
<div class="row">
|
||||
<div class="mx-auto text-center">
|
||||
<button type="button" class="btn btn-success" @onclick="Install">@Localizer["InstallNow"]</button><br /><br />
|
||||
<ModuleMessage Message="@_message" Type="MessageType.Error"></ModuleMessage>
|
||||
@if (!string.IsNullOrEmpty(_message))
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible fade show mb-3" role="alert">
|
||||
@((MarkupString)_message)
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="DismissModal"></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="app-progress-indicator" style="@_loadingDisplay"></div>
|
||||
</div>
|
||||
@ -115,29 +137,35 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private List<Database> _databases;
|
||||
private string _databaseName;
|
||||
private Type _databaseConfigType;
|
||||
private object _databaseConfig;
|
||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||
private bool _showConnectionString = false;
|
||||
private string _connectionString = string.Empty;
|
||||
private List<Database> _databases;
|
||||
private string _databaseName;
|
||||
private Type _databaseConfigType;
|
||||
private object _databaseConfig;
|
||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||
private bool _showConnectionString = false;
|
||||
private string _connectionString = string.Empty;
|
||||
|
||||
private string _hostUsername = string.Empty;
|
||||
private string _hostPassword = string.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _confirmPasswordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
private string _toggleConfirmPassword = string.Empty;
|
||||
private string _confirmPassword = string.Empty;
|
||||
private string _hostEmail = string.Empty;
|
||||
private bool _register = true;
|
||||
private string _hostUsername = string.Empty;
|
||||
private string _hostPassword = string.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _confirmPasswordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
private string _toggleConfirmPassword = string.Empty;
|
||||
private string _confirmPassword = string.Empty;
|
||||
private string _hostEmail = string.Empty;
|
||||
private List<SiteTemplate> _templates;
|
||||
private string _template = Constants.DefaultSiteTemplate;
|
||||
private bool _register = true;
|
||||
private string _message = string.Empty;
|
||||
private string _loadingDisplay = "display: none;";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
// include CSS
|
||||
var content = "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css\" integrity=\"sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==\" crossorigin=\"anonymous\" type=\"text/css\"/>";
|
||||
SiteState.AppendHeadContent(content);
|
||||
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
_databases = await DatabaseService.GetDatabasesAsync();
|
||||
@ -150,7 +178,9 @@
|
||||
_databaseName = "LocalDB";
|
||||
}
|
||||
LoadDatabaseConfigComponent();
|
||||
}
|
||||
|
||||
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
|
||||
}
|
||||
|
||||
private void DatabaseChanged(ChangeEventArgs eventArgs)
|
||||
{
|
||||
@ -185,9 +215,9 @@
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// include JavaScript
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/css/bootstrap.min.css", "text/css", "sha512-XWTTruHZEYJsxV3W/lSXG1n3Q39YIWOstqvmFsdNEEQfHoZ6vm6E9GK2OrF6DSJSpIbRbi+Nn0WDPID9O7xB2Q==", "anonymous", "");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/js/bootstrap.bundle.min.js", "sha512-9GacT4119eY3AcosfWtHMsT5JyZudrexyEVzTBWV3viP/YfB9e2pEy3N7WXL3SV6ASXpTU0vzzSxsbfsuUH4sQ==", "anonymous", "", "head");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", "anonymous", "", "head");
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +259,8 @@
|
||||
TenantName = TenantNames.Master,
|
||||
IsNewTenant = true,
|
||||
SiteName = Constants.DefaultSite,
|
||||
Register = _register
|
||||
Register = _register,
|
||||
SiteTemplate = _template
|
||||
};
|
||||
|
||||
var installation = await InstallationService.Install(config);
|
||||
@ -291,4 +322,9 @@
|
||||
_showConnectionString = !_showConnectionString;
|
||||
}
|
||||
|
||||
private void DismissModal()
|
||||
{
|
||||
_message = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ else
|
||||
if (_owner != "" && _module != "" && _template != "-")
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_location = template.Location + _owner + "." + _module;
|
||||
_location = template.Location + _owner + ".Module." + _module;
|
||||
|
||||
}
|
||||
StateHasChanged();
|
||||
|
@ -33,7 +33,16 @@
|
||||
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isenabled" HelpText="Is module enabled for this site?" ResourceKey="IsEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isenabled" class="form-select" @bind="@_isenabled" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<Section Name="Information" ResourceKey="Information">
|
||||
<div class="container">
|
||||
@ -199,6 +208,7 @@
|
||||
private string _name;
|
||||
private string _description = "";
|
||||
private string _categories;
|
||||
private string _isenabled;
|
||||
private string _moduledefinitionname = "";
|
||||
private string _version;
|
||||
private string _packagename = "";
|
||||
@ -234,6 +244,7 @@
|
||||
_name = moduleDefinition.Name;
|
||||
_description = moduleDefinition.Description;
|
||||
_categories = moduleDefinition.Categories;
|
||||
_isenabled = moduleDefinition.IsEnabled.ToString();
|
||||
_moduledefinitionname = moduleDefinition.ModuleDefinitionName;
|
||||
_version = moduleDefinition.Version;
|
||||
_packagename = moduleDefinition.PackageName;
|
||||
@ -297,6 +308,7 @@
|
||||
{
|
||||
moduledefinition.Categories = _categories;
|
||||
}
|
||||
moduledefinition.IsEnabled = (_isenabled == null ? true : bool.Parse(_isenabled));
|
||||
moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
|
||||
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
|
||||
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
|
||||
|
@ -43,6 +43,7 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Version"]</th>
|
||||
<th>@Localizer["Enabled"]</th>
|
||||
<th>@Localizer["InUse"]</th>
|
||||
<th>@SharedLocalizer["Expires"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
@ -57,6 +58,16 @@ else
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if (context.IsEnabled)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
||||
{
|
||||
|
@ -44,12 +44,20 @@
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that the module is located on" ResourceKey="Page">Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="page" class="form-select" @bind="@_pageId" required>
|
||||
@foreach (Page p in PageState.Pages)
|
||||
@if (PageState.Page.UserId != null)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
<option value="@PageState.Page.PageId">@(PageState.Page.Name)</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages)
|
||||
{
|
||||
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
|
||||
{
|
||||
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
@ -90,37 +98,35 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override string Title => "Module Settings";
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override string Title => "Module Settings";
|
||||
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<Theme> _themes;
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _title;
|
||||
private string _containerType;
|
||||
private string _allPages = "false";
|
||||
private string _permissionNames = "";
|
||||
private List<Permission> _permissions = null;
|
||||
private string _pageId;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _moduleSettingsType;
|
||||
private object _moduleSettings;
|
||||
private string _moduleSettingsTitle = "Module Settings";
|
||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||
private Type _containerSettingsType;
|
||||
private object _containerSettings;
|
||||
private RenderFragment ContainerSettingsComponent { get; set; }
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _title;
|
||||
private string _containerType;
|
||||
private string _allPages = "false";
|
||||
private string _permissionNames = "";
|
||||
private List<Permission> _permissions = null;
|
||||
private string _pageId;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _moduleSettingsType;
|
||||
private object _moduleSettings;
|
||||
private string _moduleSettingsTitle = "Module Settings";
|
||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||
private Type _containerSettingsType;
|
||||
private object _containerSettings;
|
||||
private RenderFragment ContainerSettingsComponent { get; set; }
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_title = ModuleState.Title;
|
||||
_themes = await ThemeService.GetThemesAsync();
|
||||
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_title = ModuleState.Title;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||
_containerType = ModuleState.ContainerType;
|
||||
_allPages = ModuleState.AllPages.ToString();
|
||||
_permissions = ModuleState.PermissionList;
|
||||
@ -165,7 +171,7 @@
|
||||
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
||||
}
|
||||
|
||||
var theme = _themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
||||
{
|
||||
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
||||
|
@ -6,12 +6,11 @@
|
||||
@inject IStringLocalizer<Add> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<TabStrip Refresh="@_refresh">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
||||
@if (_themeList != null)
|
||||
{
|
||||
@if (_initialized)
|
||||
{
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<TabStrip Refresh="@_refresh">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
||||
@ -19,42 +18,67 @@
|
||||
<input id="name" class="form-control" @bind="@_name" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="parent" class="form-select" @onchange="(e => ParentChanged(e))" required>
|
||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||
@foreach (Page page in PageState.Pages)
|
||||
{
|
||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||
<option value="<<">@Localizer["AtBeginning"]</option>
|
||||
@if (_children != null && _children.Count > 0)
|
||||
{
|
||||
<option value="<">@Localizer["Before"]</option>
|
||||
<option value=">">@Localizer["After"]</option>
|
||||
}
|
||||
<option value=">>">@Localizer["AtEnd"]</option>
|
||||
</select>
|
||||
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
|
||||
{
|
||||
<select class="form-select" @bind="@_childid">
|
||||
<option value="-1"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page page in _children)
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||
@foreach (Page page in PageState.Pages)
|
||||
{
|
||||
<option value="@(page.PageId)">@(page.Name)</option>
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||
<option value="<<">@Localizer["AtBeginning"]</option>
|
||||
@if (_children != null && _children.Count > 0)
|
||||
{
|
||||
<option value="<">@Localizer["Before"]</option>
|
||||
<option value=">">@Localizer["After"]</option>
|
||||
}
|
||||
<option value=">>">@Localizer["AtEnd"]</option>
|
||||
</select>
|
||||
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
|
||||
{
|
||||
<select class="form-select" @bind="@_childid">
|
||||
<option value="-1"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page page in _children)
|
||||
{
|
||||
<option value="@(page.PageId)">@(page.Name)</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="parent" class="form-select" @onchange="(e => ParentChanged(e))" required>
|
||||
<option value="@(_parent.PageId)">@(new string('-', _parent.Level * 2))@(_parent.Name)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||
<option value=">>">@Localizer["AtEnd"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="navigation" HelpText="Select whether the page is part of the site navigation or hidden" ResourceKey="Navigation">Navigation? </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -85,9 +109,24 @@
|
||||
<input id="url" class="form-control" @bind="@_url" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="icon" HelpText="Optionally provide an icon class name for this page which will be displayed in the site navigation" ResourceKey="Icon">Icon: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="icon" class="form-control" @bind="@_icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="personalizable" class="form-select" @bind="@_ispersonalizable" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Section Name="Appearance" ResourceKey="Appearance">
|
||||
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
||||
@ -95,16 +134,10 @@
|
||||
<input id="title" class="form-control" @bind="@_title" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="meta" HelpText="Optionally enter meta tags (in exactly the form you want them to be included in the page output)." ResourceKey="Meta">Meta: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="meta" class="form-control" @bind="@_meta" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="theme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
<select id="theme" class="form-select" @bind="@_themetype" required>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
@ -116,7 +149,6 @@
|
||||
<Label Class="col-sm-3" For="container" HelpText="Select the default container for the page" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="container" class="form-select" @bind="@_containertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
@ -124,90 +156,113 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="icon" HelpText="Optionally provide an icon class name for this page which will be displayed in the site navigation" ResourceKey="Icon">Icon: </Label>
|
||||
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="icon" class="form-control" @bind="@_icon" />
|
||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </Label>
|
||||
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="personalizable" class="form-select" @bind="@_ispersonalizable" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
{
|
||||
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
||||
@ThemeSettingsComponent
|
||||
</TabPanel>
|
||||
}
|
||||
</TabStrip>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
</form>
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
{
|
||||
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
||||
@ThemeSettingsComponent
|
||||
</TabPanel>
|
||||
}
|
||||
</TabStrip>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
</form>
|
||||
}
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _meta;
|
||||
private string _path = string.Empty;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation = "True";
|
||||
private string _isclickable = "True";
|
||||
private string _url;
|
||||
private string _ispersonalizable = "False";
|
||||
private string _themetype = string.Empty;
|
||||
private string _containertype = string.Empty;
|
||||
private string _icon = string.Empty;
|
||||
private string _permissions = null;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private int _pageId;
|
||||
private string _name;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation = "True";
|
||||
private string _isclickable = "True";
|
||||
private string _path = string.Empty;
|
||||
private string _url;
|
||||
private string _ispersonalizable = "False";
|
||||
private string _title;
|
||||
private string _icon = string.Empty;
|
||||
private string _themetype = string.Empty;
|
||||
private string _containertype = string.Empty;
|
||||
private string _headcontent;
|
||||
private string _bodycontent;
|
||||
private string _permissions = null;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
protected Page _parent = null;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
ThemeSettings();
|
||||
}
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||
_parent = await PageService.GetPageAsync(_pageId);
|
||||
if (_parent != null)
|
||||
{
|
||||
_parentid = _parent.PageId.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// if admin or user has edit access to parent page
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) || (_parent != null && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, _parent.PermissionList)))
|
||||
{
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
_themes = ThemeService.GetThemeControls(PageState.Site.Themes, _themetype);
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
ThemeSettings();
|
||||
_initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogWarning("Error Loading Page {ParentId}", _parentid);
|
||||
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error);
|
||||
await logger.LogError(ex, "Error Loading Page {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,27 +301,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = "-";
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
||||
{
|
||||
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
||||
@ -292,12 +330,11 @@
|
||||
Page page = null;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||
if (!string.IsNullOrEmpty(_themetype) && !string.IsNullOrEmpty(_containertype))
|
||||
{
|
||||
page = new Page();
|
||||
page.SiteId = PageState.Page.SiteId;
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
@ -365,34 +402,42 @@
|
||||
|
||||
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
|
||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||
page.Url = _url;
|
||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||
page.Url = _url;
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
|
||||
// appearance
|
||||
page.Title = _title;
|
||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||
page.ThemeType = _themetype;
|
||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||
{
|
||||
page.ThemeType = string.Empty;
|
||||
}
|
||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||
page.DefaultContainerType = _containertype;
|
||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
page.DefaultContainerType = string.Empty;
|
||||
}
|
||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||
|
||||
// page content
|
||||
page.HeadContent = _headcontent;
|
||||
page.BodyContent = _bodycontent;
|
||||
|
||||
// permissions
|
||||
page.PermissionList = _permissionGrid.GetPermissionList();
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.Meta = _meta;
|
||||
|
||||
page = await PageService.AddPageAsync(page);
|
||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||
|
||||
await logger.LogInformation("Page Added {Page}", page);
|
||||
if (PageState.QueryString.ContainsKey("cp"))
|
||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Pages.First(item => item.PageId == int.Parse(PageState.QueryString["cp"])).Path));
|
||||
NavigationManager.NavigateTo(page.Path); // redirect to new page
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(page.Path));
|
||||
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -415,9 +460,9 @@
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("cp"))
|
||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Pages.First(item => item.PageId == int.Parse(PageState.QueryString["cp"])).Path));
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (PageState.Pages != null)
|
||||
@if (PageState.Pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
|
||||
|
||||
|
@ -64,6 +64,12 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="validation" HelpText="Optionally provide a regular expression (RegExp) for validating the value entered" ResourceKey="Validation">Validation: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="validation" class="form-control" @bind="@_validation" maxlength="200" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="private" HelpText="Should this profile item be visible to all users?" ResourceKey="Private">Private? </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -97,6 +103,7 @@
|
||||
private string _maxlength = "0";
|
||||
private string _defaultvalue = string.Empty;
|
||||
private string _options = string.Empty;
|
||||
private string _validation = string.Empty;
|
||||
private string _isrequired = "False";
|
||||
private string _isprivate = "False";
|
||||
private string createdby;
|
||||
@ -126,6 +133,7 @@
|
||||
_maxlength = profile.MaxLength.ToString();
|
||||
_defaultvalue = profile.DefaultValue;
|
||||
_options = profile.Options;
|
||||
_validation = profile.Validation;
|
||||
_isrequired = profile.IsRequired.ToString();
|
||||
_isprivate = profile.IsPrivate.ToString();
|
||||
createdby = profile.CreatedBy;
|
||||
@ -169,6 +177,7 @@
|
||||
profile.MaxLength = int.Parse(_maxlength);
|
||||
profile.DefaultValue = _defaultvalue;
|
||||
profile.Options = _options;
|
||||
profile.Validation = _validation;
|
||||
profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired));
|
||||
profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate));
|
||||
if (_profileid != -1)
|
||||
|
@ -76,8 +76,8 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Page> _pages;
|
||||
private List<Module> _modules;
|
||||
private List<Page> _pages;
|
||||
private List<Module> _modules;
|
||||
private int _pagePage = 1;
|
||||
private int _pageModule = 1;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
@ -184,13 +184,6 @@ else
|
||||
try
|
||||
{
|
||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||
|
||||
// check if there are any remaining module instances in the site
|
||||
if (!_modules.Exists (item => item.ModuleId == module.ModuleId && item.PageModuleId != module.PageModuleId))
|
||||
{
|
||||
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
||||
}
|
||||
|
||||
await logger.LogInformation("Module Permanently Deleted {Module}", module);
|
||||
await Load();
|
||||
StateHasChanged();
|
||||
@ -210,16 +203,7 @@ else
|
||||
foreach (Module module in _modules.Where(item => item.IsDeleted).ToList())
|
||||
{
|
||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||
|
||||
// DeletePageModuleAsync does not update _modules so remove it.
|
||||
_modules.Remove(module);
|
||||
// check if there are any remaining module instances in the site
|
||||
if (!_modules.Exists(item => item.ModuleId == module.ModuleId && item.PageModuleId != module.PageModuleId))
|
||||
{
|
||||
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
||||
}
|
||||
}
|
||||
|
||||
await logger.LogInformation("Modules Permanently Deleted");
|
||||
await Load();
|
||||
ModuleInstance.HideProgressIndicator();
|
||||
|
@ -22,55 +22,6 @@
|
||||
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
<option value="-"><@Localizer["Theme.Select"]></option>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
<option value="@Constants.DefaultAdminContainer"><@Localizer["DefaultAdminContainer"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="homepage" HelpText="Select the home page for the site (to be used if there is no page with a path of '/')" ResourceKey="HomePage">Home Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -101,7 +52,80 @@
|
||||
<input id="sitemap" class="form-control" @bind="@_sitemap" required disabled />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="version" HelpText="The site version (for site content migrations)" ResourceKey="Version">Version: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="version" class="form-control" @bind="@_version" required disabled />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<Section Name="Appearance" ResourceKey="Appearance">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager FileId="@_faviconfileid" Filter="ico,png,gif" @ref="_faviconfilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
|
||||
<option value="@Constants.DefaultAdminContainer"><@Localizer["DefaultAdminContainer"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -124,9 +148,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="enabledSSl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="UseSsl">SSL Enabled: </Label>
|
||||
<Label Class="col-sm-3" For="smtpssl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="UseSsl">SSL Enabled: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="enabledSSl" class="form-select" @bind="@_smtpssl" >
|
||||
<select id="smtpssl" class="form-select" @bind="@_smtpssl" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
@ -162,7 +186,16 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpenabled" class="form-select" @bind="@_smtpenabled">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
@ -306,222 +339,234 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private List<Alias> _aliases;
|
||||
private int _aliasid = -1;
|
||||
private string _aliasname;
|
||||
private string _defaultalias;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
private FileManager _faviconfilemanager;
|
||||
private string _themetype = "-";
|
||||
private string _containertype = "-";
|
||||
private string _admincontainertype = "-";
|
||||
private string _homepageid = "-";
|
||||
private string _sitemap = "";
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtppasswordtype = "password";
|
||||
private string _togglesmtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _smtprelay = "False";
|
||||
private string _retention = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
private int _pwasplashiconfileid = -1;
|
||||
private FileManager _pwasplashiconfilemanager;
|
||||
private string _tenant = string.Empty;
|
||||
private string _database = string.Empty;
|
||||
private string _connectionstring = string.Empty;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
private string _isdeleted;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private string _homepageid = "-";
|
||||
private string _isdeleted;
|
||||
private string _sitemap = "";
|
||||
private string _version = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
private FileManager _faviconfilemanager;
|
||||
private string _themetype = "";
|
||||
private string _containertype = "";
|
||||
private string _admincontainertype = "";
|
||||
private string _headcontent = string.Empty;
|
||||
private string _bodycontent = string.Empty;
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtppasswordtype = "password";
|
||||
private string _togglesmtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _smtprelay = "False";
|
||||
private string _smtpenabled = "True";
|
||||
private string _retention = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
private int _pwasplashiconfileid = -1;
|
||||
private FileManager _pwasplashiconfilemanager;
|
||||
private List<Alias> _aliases;
|
||||
private int _aliasid = -1;
|
||||
private string _aliasname;
|
||||
private string _defaultalias;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private string _tenant = string.Empty;
|
||||
private string _database = string.Empty;
|
||||
private string _connectionstring = string.Empty;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
if (site.HomePageId != null)
|
||||
{
|
||||
_homepageid = site.HomePageId.Value.ToString();
|
||||
}
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
||||
_version = site.Version;
|
||||
|
||||
await GetAliases();
|
||||
// appearance
|
||||
if (site.LogoFileId != null)
|
||||
{
|
||||
_logofileid = site.LogoFileId.Value;
|
||||
}
|
||||
|
||||
if (site.LogoFileId != null)
|
||||
{
|
||||
_logofileid = site.LogoFileId.Value;
|
||||
}
|
||||
if (site.FaviconFileId != null)
|
||||
{
|
||||
_faviconfileid = site.FaviconFileId.Value;
|
||||
}
|
||||
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
|
||||
if (site.FaviconFileId != null)
|
||||
{
|
||||
_faviconfileid = site.FaviconFileId.Value;
|
||||
}
|
||||
// page content
|
||||
_headcontent = site.HeadContent;
|
||||
_bodycontent = site.BodyContent;
|
||||
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
// PWA
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
|
||||
if (site.HomePageId != null)
|
||||
{
|
||||
_homepageid = site.HomePageId.Value.ToString();
|
||||
}
|
||||
// SMTP
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True");
|
||||
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
// aliases
|
||||
await GetAliases();
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
||||
// hosting model
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var tenants = await TenantService.GetTenantsAsync();
|
||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
||||
var tenant = tenants.Find(item => item.TenantId == site.TenantId);
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
// database
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var tenants = await TenantService.GetTenantsAsync();
|
||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
||||
var tenant = tenants.Find(item => item.TenantId == site.TenantId);
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
|
||||
_createdby = site.CreatedBy;
|
||||
_createdon = site.CreatedOn;
|
||||
_modifiedby = site.ModifiedBy;
|
||||
_modifiedon = site.ModifiedOn;
|
||||
_deletedby = site.DeletedBy;
|
||||
_deletedon = site.DeletedOn;
|
||||
// audit
|
||||
_createdby = site.CreatedBy;
|
||||
_createdon = site.CreatedOn;
|
||||
_modifiedby = site.ModifiedBy;
|
||||
_modifiedon = site.ModifiedOn;
|
||||
_deletedby = site.DeletedBy;
|
||||
_deletedon = site.DeletedOn;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
if (_themetype != "-")
|
||||
{
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
}
|
||||
else
|
||||
{
|
||||
_containers = new List<ThemeControl>();
|
||||
}
|
||||
_containertype = "-";
|
||||
_admincontainertype = Constants.DefaultAdminContainer;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = _containers.First().TypeName;
|
||||
_admincontainertype = Constants.DefaultAdminContainer;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool refresh = false;
|
||||
bool reload = false;
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool refresh = false;
|
||||
bool reload = false;
|
||||
|
||||
site.Name = _name;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
site.Name = _name;
|
||||
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
|
||||
site.LogoFileId = null;
|
||||
var logofileid = _logofilemanager.GetFileId();
|
||||
if (logofileid != -1)
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId == -1) faviconFieldId = null;
|
||||
if (site.FaviconFileId != faviconFieldId)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
if (site.DefaultThemeType != _themetype)
|
||||
{
|
||||
site.DefaultThemeType = _themetype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
if (site.DefaultContainerType != _containertype)
|
||||
{
|
||||
site.DefaultContainerType = _containertype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
||||
// appearance
|
||||
site.LogoFileId = null;
|
||||
var logofileid = _logofilemanager.GetFileId();
|
||||
if (logofileid != -1)
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId == -1) faviconFieldId = null;
|
||||
if (site.FaviconFileId != faviconFieldId)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
if (site.DefaultThemeType != _themetype)
|
||||
{
|
||||
site.DefaultThemeType = _themetype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
if (site.DefaultContainerType != _containertype)
|
||||
{
|
||||
site.DefaultContainerType = _containertype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
|
||||
// page content
|
||||
if (site.HeadContent != _headcontent)
|
||||
{
|
||||
site.HeadContent = _headcontent;
|
||||
reload = true;
|
||||
}
|
||||
if (site.BodyContent != _bodycontent)
|
||||
{
|
||||
site.BodyContent = _bodycontent;
|
||||
reload = true;
|
||||
}
|
||||
|
||||
// PWA
|
||||
if (site.PwaIsEnabled.ToString() != _pwaisenabled)
|
||||
{
|
||||
site.PwaIsEnabled = Boolean.Parse(_pwaisenabled);
|
||||
@ -542,8 +587,20 @@
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
|
||||
// hosting model
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
|
||||
site = await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
// SMTP
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
@ -552,7 +609,8 @@
|
||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
|
||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||
@ -564,8 +622,8 @@
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
await ScrollToPageTop();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -633,9 +691,8 @@
|
||||
|
||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
await ScrollToPageTop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
||||
|
@ -142,7 +142,7 @@
|
||||
if (_owner != "" && _theme != "" && _template != "-")
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_location = template.Location + _owner + "." + _theme;
|
||||
_location = template.Location + _owner + ".Theme." + _theme;
|
||||
|
||||
}
|
||||
StateHasChanged();
|
||||
|
162
Oqtane.Client/Modules/Admin/Themes/Edit.razor
Normal file
162
Oqtane.Client/Modules/Admin/Themes/Edit.razor
Normal file
@ -0,0 +1,162 @@
|
||||
@namespace Oqtane.Modules.Admin.Themes
|
||||
@using System.Net
|
||||
@inherits ModuleBase
|
||||
@inject IThemeService ThemeService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="name" class="form-control" @bind="@_name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isenabled" HelpText="Is theme enabled for this site?" ResourceKey="IsEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isenabled" class="form-select" @bind="@_isenabled" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<Section Name="Information" ResourceKey="Information">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="themename" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="themename" class="form-control" @bind="@_themeName" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="version" HelpText="The version of the theme" ResourceKey="Version">Version: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the theme" ResourceKey="Owner">Owner: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="owner" class="form-control" @bind="@_owner" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The reference url of the theme" ResourceKey="ReferenceUrl">Reference Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="contact" HelpText="The contact for the theme" ResourceKey="Contact">Contact: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="contact" class="form-control" @bind="@_contact" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="license" HelpText="The license of the theme" ResourceKey="License">License: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveTheme">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
<br />
|
||||
<br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private int _themeId;
|
||||
private string _themeName = "";
|
||||
private string _isenabled;
|
||||
private string _name;
|
||||
private string _version;
|
||||
private string _packagename;
|
||||
private string _owner = "";
|
||||
private string _url = "";
|
||||
private string _contact = "";
|
||||
private string _license = "";
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var theme = await ThemeService.GetThemeAsync(_themeId, ModuleState.SiteId);
|
||||
if (theme != null)
|
||||
{
|
||||
_name = theme.Name;
|
||||
_isenabled =theme.IsEnabled.ToString();
|
||||
_version = theme.Version;
|
||||
_packagename = theme.PackageName;
|
||||
_owner = theme.Owner;
|
||||
_url = theme.Url;
|
||||
_contact = theme.Contact;
|
||||
_license = theme.License;
|
||||
_createdby = theme.CreatedBy;
|
||||
_createdon = theme.CreatedOn;
|
||||
_modifiedby = theme.ModifiedBy;
|
||||
_modifiedon = theme.ModifiedOn;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Theme {ThemeName} {Error}", _themeName, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.Loading"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveTheme()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
var theme = await ThemeService.GetThemeAsync(_themeId, ModuleState.SiteId);
|
||||
theme.Name = _name;
|
||||
theme.IsEnabled = (_isenabled == null ? true : bool.Parse(_isenabled));
|
||||
await ThemeService.UpdateThemeAsync(theme);
|
||||
await logger.LogInformation("Theme Saved {Theme}", theme);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Theme {ThemeId} {Error}", _themeId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,11 +23,12 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Version"]</th>
|
||||
<th>@Localizer["Enabled"]</th>
|
||||
<th>@SharedLocalizer["Expires"]</th>
|
||||
<th> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="View" Parameters="@($"name=" + WebUtility.UrlEncode(context.ThemeName))" ResourceKey="ViewTheme" /></td>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditModule" /></td>
|
||||
<td>
|
||||
@if (context.AssemblyName != Constants.ClientId)
|
||||
{
|
||||
@ -36,6 +37,16 @@ else
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if (context.IsEnabled)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)PurchaseLink(context.PackageName))
|
||||
</td>
|
||||
|
@ -1,97 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.Themes
|
||||
@using System.Net
|
||||
@inherits ModuleBase
|
||||
@inject IThemeService ThemeService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<View> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="The name of the theme" ResourceKey="Name">Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="name" class="form-control" @bind="@_name" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="themename" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="themename" class="form-control" @bind="@_themeName" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="version" HelpText="The version of the theme" ResourceKey="Version">Version: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the theme" ResourceKey="Owner">Owner: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="owner" class="form-control" @bind="@_owner" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The reference url of the theme" ResourceKey="ReferenceUrl">Reference Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="contact" HelpText="The contact for the theme" ResourceKey="Contact">Contact: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="contact" class="form-control" @bind="@_contact" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="license" HelpText="The license of the theme" ResourceKey="License">License: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private string _themeName = "";
|
||||
private string _name;
|
||||
private string _version;
|
||||
private string _packagename;
|
||||
private string _owner = "";
|
||||
private string _url = "";
|
||||
private string _contact = "";
|
||||
private string _license = "";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeName = WebUtility.UrlDecode(PageState.QueryString["name"]);
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
var theme = themes.FirstOrDefault(item => item.ThemeName == _themeName);
|
||||
if (theme != null)
|
||||
{
|
||||
_name = theme.Name;
|
||||
_version = theme.Version;
|
||||
_packagename = theme.PackageName;
|
||||
_owner = theme.Owner;
|
||||
_url = theme.Url;
|
||||
_contact = theme.Contact;
|
||||
_license = theme.License;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Theme {ThemeName} {Error}", _themeName, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.Loading"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
@namespace Oqtane.Modules.Admin.UserProfile
|
||||
@using System.Text.RegularExpressions;
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@ -227,140 +228,140 @@ else
|
||||
<br /><br />
|
||||
|
||||
@code {
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private bool allowtwofactor = false;
|
||||
private string twofactor = "False";
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int folderid = -1;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
private string filter = "to";
|
||||
private List<Notification> notifications;
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private bool allowtwofactor = false;
|
||||
private string twofactor = "False";
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int folderid = -1;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
private string filter = "to";
|
||||
private List<Notification> notifications;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
||||
{
|
||||
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
||||
}
|
||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
||||
{
|
||||
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
||||
}
|
||||
|
||||
if (PageState.User != null)
|
||||
{
|
||||
username = PageState.User.Username;
|
||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||
email = PageState.User.Email;
|
||||
displayname = PageState.User.DisplayName;
|
||||
if (PageState.User != null)
|
||||
{
|
||||
username = PageState.User.Username;
|
||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||
email = PageState.User.Email;
|
||||
displayname = PageState.User.DisplayName;
|
||||
|
||||
// get user folder
|
||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||
if (folder != null)
|
||||
{
|
||||
folderid = folder.FolderId;
|
||||
}
|
||||
// get user folder
|
||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||
if (folder != null)
|
||||
{
|
||||
folderid = folder.FolderId;
|
||||
}
|
||||
|
||||
if (PageState.User.PhotoFileId != null)
|
||||
{
|
||||
photofileid = PageState.User.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
if (PageState.User.PhotoFileId != null)
|
||||
{
|
||||
photofileid = PageState.User.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
|
||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
|
||||
await LoadNotificationsAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
await LoadNotificationsAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadNotificationsAsync()
|
||||
{
|
||||
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
||||
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
||||
}
|
||||
private async Task LoadNotificationsAsync()
|
||||
{
|
||||
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
||||
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
||||
}
|
||||
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = PageState.User;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||
user.Email = email;
|
||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
private async Task Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = PageState.User;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||
user.Email = email;
|
||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
await logger.LogInformation("User Profile Saved");
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
await logger.LogInformation("User Profile Saved");
|
||||
|
||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
|
||||
@ -370,6 +371,8 @@ else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
|
||||
}
|
||||
|
||||
await ScrollToPageTop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -389,10 +392,15 @@ else
|
||||
}
|
||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
|
||||
{
|
||||
Regex regex = new Regex(profile.Validation);
|
||||
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
|
@ -1,4 +1,5 @@
|
||||
@namespace Oqtane.Modules.Admin.Users
|
||||
@using System.Text.RegularExpressions;
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@ -95,8 +96,8 @@
|
||||
@code {
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
@ -121,15 +122,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private async Task SaveUser()
|
||||
{
|
||||
@ -195,9 +196,17 @@
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
||||
}
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
valid = false;
|
||||
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
|
||||
{
|
||||
Regex regex = new Regex(profile.Validation);
|
||||
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
|
@ -1,4 +1,5 @@
|
||||
@namespace Oqtane.Modules.Admin.Users
|
||||
@using System.Text.RegularExpressions;
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@ -148,124 +149,124 @@ else
|
||||
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
|
||||
|
||||
@code {
|
||||
private int userid;
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private string isdeleted;
|
||||
private string lastlogin;
|
||||
private string lastipaddress;
|
||||
private int userid;
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private string isdeleted;
|
||||
private string lastlogin;
|
||||
private string lastipaddress;
|
||||
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private string deletedby;
|
||||
private DateTime? deletedon;
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private string deletedby;
|
||||
private DateTime? deletedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||
userid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
username = user.Username;
|
||||
email = user.Email;
|
||||
displayname = user.DisplayName;
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
isdeleted = user.IsDeleted.ToString();
|
||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
||||
lastipaddress = user.LastIPAddress;
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||
userid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
username = user.Username;
|
||||
email = user.Email;
|
||||
displayname = user.DisplayName;
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
isdeleted = user.IsDeleted.ToString();
|
||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
||||
lastipaddress = user.LastIPAddress;
|
||||
|
||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||
createdby = user.CreatedBy;
|
||||
createdon = user.CreatedOn;
|
||||
modifiedby = user.ModifiedBy;
|
||||
modifiedon = user.ModifiedOn;
|
||||
deletedby = user.DeletedBy;
|
||||
deletedon = user.DeletedOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||
createdby = user.CreatedBy;
|
||||
createdon = user.CreatedOn;
|
||||
modifiedby = user.ModifiedBy;
|
||||
modifiedon = user.ModifiedOn;
|
||||
deletedby = user.DeletedBy;
|
||||
deletedon = user.DeletedOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private async Task SaveUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
private async Task SaveUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
|
||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||
await logger.LogInformation("User Saved {User}", user);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||
await logger.LogInformation("User Saved {User}", user);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -293,9 +294,17 @@ else
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
||||
}
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
valid = false;
|
||||
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
|
||||
{
|
||||
Regex regex = new Regex(profile.Validation);
|
||||
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
|
@ -53,7 +53,6 @@
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
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" }
|
||||
};
|
||||
|
@ -15,11 +15,6 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||
};
|
||||
|
||||
private string content = "";
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText
|
||||
{
|
||||
@ -13,7 +15,11 @@ namespace Oqtane.Modules.HtmlText
|
||||
Version = "1.0.1",
|
||||
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
||||
ReleaseVersions = "1.0.0,1.0.1",
|
||||
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"
|
||||
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client",
|
||||
Resources = new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using Oqtane.UI;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Linq;
|
||||
using Oqtane.Themes;
|
||||
|
||||
namespace Oqtane.Modules
|
||||
{
|
||||
@ -70,17 +71,33 @@ namespace Oqtane.Modules
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||
List<Resource> resources = null;
|
||||
var type = GetType();
|
||||
if (type.BaseType == typeof(ModuleBase))
|
||||
{
|
||||
if (PageState.Page.Resources != null)
|
||||
{
|
||||
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level != ResourceLevel.Site && item.Namespace == type.Namespace).ToList();
|
||||
}
|
||||
}
|
||||
else // modulecontrolbase
|
||||
{
|
||||
if (Resources != null)
|
||||
{
|
||||
resources = Resources.Where(item => item.ResourceType == ResourceType.Script).ToList();
|
||||
}
|
||||
}
|
||||
if (resources != null &&resources.Any())
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
var scripts = new List<object>();
|
||||
var inline = 0;
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||
foreach (Resource resource in resources)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(resource.Url))
|
||||
{
|
||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module, location = resource.Location.ToString().ToLower() });
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -104,6 +121,7 @@ namespace Oqtane.Modules
|
||||
}
|
||||
|
||||
// url methods
|
||||
|
||||
public string NavigateUrl()
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path);
|
||||
@ -273,6 +291,33 @@ namespace Oqtane.Modules
|
||||
SiteState.Properties.ModuleVisibility = obj;
|
||||
}
|
||||
|
||||
public void SetPageTitle(string title)
|
||||
{
|
||||
SiteState.Properties.PageTitle = title;
|
||||
}
|
||||
|
||||
// note - only supports links and meta tags - not scripts
|
||||
public void AddHeadContent(string content)
|
||||
{
|
||||
SiteState.AppendHeadContent(content);
|
||||
}
|
||||
|
||||
public void AddScript(Resource resource)
|
||||
{
|
||||
resource.ResourceType = ResourceType.Script;
|
||||
if (Resources == null) Resources = new List<Resource>();
|
||||
if (!Resources.Any(item => (!string.IsNullOrEmpty(resource.Url) && item.Url == resource.Url) || (!string.IsNullOrEmpty(resource.Content) && item.Content == resource.Content)))
|
||||
{
|
||||
Resources.Add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ScrollToPageTop()
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
|
||||
// logging methods
|
||||
public async Task Log(Alias alias, LogLevel level, string function, Exception exception, string message, params object[] args)
|
||||
{
|
||||
|
@ -1,19 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.4.3</Version>
|
||||
<Version>4.0.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>Modular Application Framework for Blazor and MAUI</Description>
|
||||
<Description>CMS and Application Framework for Blazor and .NET MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -22,13 +22,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.3" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -16,7 +16,6 @@ using Microsoft.JSInterop;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Client
|
||||
|
@ -124,7 +124,7 @@
|
||||
<value>Database:</value>
|
||||
</data>
|
||||
<data name="ApplicationAdmin" xml:space="preserve">
|
||||
<value>Application Administrator</value>
|
||||
<value>Application Administration</value>
|
||||
</data>
|
||||
<data name="InstallNow" xml:space="preserve">
|
||||
<value>Install Now</value>
|
||||
@ -180,4 +180,7 @@
|
||||
<data name="EnterConnectionString" xml:space="preserve">
|
||||
<value>Enter Connection String</value>
|
||||
</data>
|
||||
<data name="Template" xml:space="preserve">
|
||||
<value>Select a site template</value>
|
||||
</data>
|
||||
</root>
|
@ -219,4 +219,10 @@
|
||||
<data name="Message.DuplicateName" xml:space="preserve">
|
||||
<value>A Module With The Name Specified Already Exists</value>
|
||||
</data>
|
||||
<data name="IsEnabled.HelpText" xml:space="preserve">
|
||||
<value>Is module enabled for this site?</value>
|
||||
</data>
|
||||
<data name="IsEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
</root>
|
@ -145,7 +145,7 @@
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="InUse" xml:space="preserve">
|
||||
<value>In Use</value>
|
||||
<value>In Use?</value>
|
||||
</data>
|
||||
<data name="EditModule.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
@ -153,4 +153,7 @@
|
||||
<data name="Modules" xml:space="preserve">
|
||||
<value>Modules</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
</root>
|
@ -150,8 +150,8 @@
|
||||
<data name="Container.Select" xml:space="preserve">
|
||||
<value>Select Container</value>
|
||||
</data>
|
||||
<data name="Error.Page.Initialize" xml:space="preserve">
|
||||
<value>Error Initializing Page</value>
|
||||
<data name="Error.Page.Load" xml:space="preserve">
|
||||
<value>Error Loading Page</value>
|
||||
</data>
|
||||
<data name="Error.ChildPage.Load" xml:space="preserve">
|
||||
<value>Error Loading Child Pages For Parent</value>
|
||||
@ -228,13 +228,22 @@
|
||||
<data name="Appearance.Name" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
<data name="HeadContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page head (ie. meta, link, or script tags)</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
<data name="HeadContent.Text" xml:space="preserve">
|
||||
<value>Head Content:</value>
|
||||
</data>
|
||||
<data name="Message.Page.Reserved" xml:space="preserve">
|
||||
<value>The page name {0} is reserved. Please enter a different name for your page.</value>
|
||||
</data>
|
||||
<data name="BodyContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page body (ie. script tags)</value>
|
||||
</data>
|
||||
<data name="BodyContent.Text" xml:space="preserve">
|
||||
<value>Body Content:</value>
|
||||
</data>
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
</root>
|
@ -264,13 +264,22 @@
|
||||
<data name="Clickable.Text" xml:space="preserve">
|
||||
<value>Clickable?</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
<data name="HeadContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page head (ie. meta, link, or script tags)</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
<data name="HeadContent.Text" xml:space="preserve">
|
||||
<value>Head Content:</value>
|
||||
</data>
|
||||
<data name="Message.Page.Reserved" xml:space="preserve">
|
||||
<value>The page name {0} is reserved. Please enter a different name for your page.</value>
|
||||
</data>
|
||||
<data name="BodyContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page body (ie. script tags)</value>
|
||||
</data>
|
||||
<data name="BodyContent.Text" xml:space="preserve">
|
||||
<value>Body Content:</value>
|
||||
</data>
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
</root>
|
@ -183,4 +183,10 @@
|
||||
<data name="Private.Text" xml:space="preserve">
|
||||
<value>Private? </value>
|
||||
</data>
|
||||
<data name="Validation.HelpText" xml:space="preserve">
|
||||
<value>Optionally provide a regular expression (RegExp) for validating the value entered</value>
|
||||
</data>
|
||||
<data name="Validation.Text" xml:space="preserve">
|
||||
<value>Validation:</value>
|
||||
</data>
|
||||
</root>
|
@ -175,7 +175,7 @@
|
||||
<value>Specify a logo for the site</value>
|
||||
</data>
|
||||
<data name="FavoriteIcon.HelpText" xml:space="preserve">
|
||||
<value>Specify a Favicon</value>
|
||||
<value>Specify a Favicon. The format for the image must be 16×16, 32×32, 48×48, or 64×64 pixels in size, and 8-bit, 24-bit, or 32-bit in color depth. The format of the image must be ICO, PNG, or GIF.</value>
|
||||
</data>
|
||||
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
||||
<value>Select the sites default theme</value>
|
||||
@ -351,4 +351,34 @@
|
||||
<data name="SiteMap.Text" xml:space="preserve">
|
||||
<value>Site Map:</value>
|
||||
</data>
|
||||
<data name="Appearance.Heading" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="HeadContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page head (ie. meta, link, or script tags)</value>
|
||||
</data>
|
||||
<data name="HeadContent.Text" xml:space="preserve">
|
||||
<value>Head Content:</value>
|
||||
</data>
|
||||
<data name="BodyContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page body (ie. script tags)</value>
|
||||
</data>
|
||||
<data name="BodyContent.Text" xml:space="preserve">
|
||||
<value>Body Content:</value>
|
||||
</data>
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
<data name="SMTPEnabled.HelpText" xml:space="preserve">
|
||||
<value>Specify if SMTP is enabled for this site</value>
|
||||
</data>
|
||||
<data name="SMTPEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
<data name="Version.HelpText" xml:space="preserve">
|
||||
<value>The site version (for site content migrations)</value>
|
||||
</data>
|
||||
<data name="Version.Text" xml:space="preserve">
|
||||
<value>Version:</value>
|
||||
</data>
|
||||
</root>
|
@ -168,4 +168,13 @@
|
||||
<data name="PackageName.Text" xml:space="preserve">
|
||||
<value>Package Name:</value>
|
||||
</data>
|
||||
<data name="Information.Heading" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="IsEnabled.HelpText" xml:space="preserve">
|
||||
<value>Is theme enabled for this site?</value>
|
||||
</data>
|
||||
<data name="IsEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
</root>
|
@ -144,4 +144,7 @@
|
||||
<data name="ViewTheme.Text" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
</root>
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@ -29,9 +30,9 @@ namespace Oqtane.Services
|
||||
|
||||
public async Task<List<File>> GetFilesAsync(int siteId, string folderPath)
|
||||
{
|
||||
if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
|
||||
if (!(string.IsNullOrEmpty(folderPath) || folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
|
||||
{
|
||||
folderPath = Utilities.PathCombine(folderPath, System.IO.Path.DirectorySeparatorChar.ToString());
|
||||
folderPath = Utilities.UrlCombine(folderPath) + "/";
|
||||
}
|
||||
|
||||
var path = WebUtility.UrlEncode(folderPath);
|
||||
|
@ -23,14 +23,6 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
Task<Page> GetPageAsync(int pageId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a specific page personalized for the given user
|
||||
/// </summary>
|
||||
/// <param name="pageId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Page> GetPageAsync(int pageId, int userId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a specific page by its defined path
|
||||
/// </summary>
|
||||
|
@ -16,6 +16,22 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
Task<List<Theme>> GetThemesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a specific thenme
|
||||
/// </summary>
|
||||
/// <param name="themeId"></param>
|
||||
/// <param name="siteId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Theme> GetThemeAsync(int themeId, int siteId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a theme <see cref="ThemeControl"/>s containing a specific theme control type
|
||||
/// </summary>
|
||||
/// <param name="themes"></param>
|
||||
/// <param name="themeControlType"></param>
|
||||
/// <returns></returns>
|
||||
Theme GetTheme(List<Theme> themes, string themeControlType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="ThemeControl"/>s from the given themes
|
||||
/// </summary>
|
||||
@ -24,20 +40,27 @@ namespace Oqtane.Services
|
||||
List<ThemeControl> GetThemeControls(List<Theme> themes);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of layouts (<see cref="ThemeControl"/>) from the given themes with a matching theme name
|
||||
/// Returns a list of <see cref="ThemeControl"/>s for a theme containing a specific theme control type
|
||||
/// </summary>
|
||||
/// <param name="themes"></param>
|
||||
/// <param name="themeName"></param>
|
||||
/// <param name="themeControlType"></param>
|
||||
/// <returns></returns>
|
||||
List<ThemeControl> GetLayoutControls(List<Theme> themes, string themeName);
|
||||
List<ThemeControl> GetThemeControls(List<Theme> themes, string themeControlType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of containers (<see cref="ThemeControl"/>) from the given themes with a matching theme name
|
||||
/// Returns a list of containers (<see cref="ThemeControl"/>) for a theme containing a specific theme control type
|
||||
/// </summary>
|
||||
/// <param name="themes"></param>
|
||||
/// <param name="themeName"></param>
|
||||
/// <param name="themeControlType"></param>
|
||||
/// <returns></returns>
|
||||
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
||||
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeControlType);
|
||||
|
||||
/// <summary>
|
||||
/// Updates a existing theem
|
||||
/// </summary>
|
||||
/// <param name="theme"></param>
|
||||
/// <returns></returns>
|
||||
Task UpdateThemeAsync(Theme theme);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a theme
|
||||
@ -58,5 +81,14 @@ namespace Oqtane.Services
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<Template>> GetThemeTemplatesAsync();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of layouts (<see cref="ThemeControl"/>) from the given themes with a matching theme name
|
||||
/// </summary>
|
||||
/// <param name="themes"></param>
|
||||
/// <param name="themeName"></param>
|
||||
/// <returns></returns>
|
||||
List<ThemeControl> GetLayoutControls(List<Theme> themes, string themeName);
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,6 @@ namespace Oqtane.Services
|
||||
return await GetJsonAsync<Page>($"{Apiurl}/{pageId}");
|
||||
}
|
||||
|
||||
public async Task<Page> GetPageAsync(int pageId, int userId)
|
||||
{
|
||||
return await GetJsonAsync<Page>($"{Apiurl}/{pageId}?userid={userId}");
|
||||
}
|
||||
|
||||
public async Task<Page> GetPageAsync(string path, int siteId)
|
||||
{
|
||||
try
|
||||
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
@ -20,22 +21,35 @@ namespace Oqtane.Services
|
||||
List<Theme> themes = await GetJsonAsync<List<Theme>>(ApiUrl);
|
||||
return themes.OrderBy(item => item.Name).ToList();
|
||||
}
|
||||
public async Task<Theme> GetThemeAsync(int themeId, int siteId)
|
||||
{
|
||||
return await GetJsonAsync<Theme>($"{ApiUrl}/{themeId}?siteid={siteId}");
|
||||
}
|
||||
|
||||
public Theme GetTheme(List<Theme> themes, string themeControlType)
|
||||
{
|
||||
return themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeControlType));
|
||||
}
|
||||
|
||||
public List<ThemeControl> GetThemeControls(List<Theme> themes)
|
||||
{
|
||||
return themes.SelectMany(item => item.Themes).ToList();
|
||||
return themes.SelectMany(item => item.Themes).OrderBy(item => item.Name).ToList();
|
||||
}
|
||||
|
||||
//[Obsolete("This method is deprecated.", false)]
|
||||
public List<ThemeControl> GetLayoutControls(List<Theme> themes, string themeName)
|
||||
public List<ThemeControl> GetThemeControls(List<Theme> themes, string themeControlType)
|
||||
{
|
||||
return null;
|
||||
return GetTheme(themes, themeControlType)?.Themes.OrderBy(item => item.Name).ToList();
|
||||
}
|
||||
|
||||
public List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName)
|
||||
|
||||
public List<ThemeControl> GetContainerControls(List<Theme> themes, string themeControlType)
|
||||
{
|
||||
return themes.Where(item => Utilities.GetTypeName(themeName).StartsWith(Utilities.GetTypeName(item.ThemeName)))
|
||||
.SelectMany(item => item.Containers).ToList();
|
||||
return GetTheme(themes, themeControlType)?.Containers.OrderBy(item => item.Name).ToList();
|
||||
}
|
||||
|
||||
public async Task UpdateThemeAsync(Theme theme)
|
||||
{
|
||||
await PutJsonAsync($"{ApiUrl}/{theme.ThemeId}", theme);
|
||||
}
|
||||
|
||||
public async Task DeleteThemeAsync(string themeName)
|
||||
@ -53,5 +67,11 @@ namespace Oqtane.Services
|
||||
List<Template> templates = await GetJsonAsync<List<Template>>($"{ApiUrl}/templates");
|
||||
return templates;
|
||||
}
|
||||
|
||||
//[Obsolete("This method is deprecated.", false)]
|
||||
public List<ThemeControl> GetLayoutControls(List<Theme> themes, string themeName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,9 +31,9 @@
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
// obtained from https://cdnjs.com/libraries
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/css/bootstrap.min.css", Integrity = "sha512-XWTTruHZEYJsxV3W/lSXG1n3Q39YIWOstqvmFsdNEEQfHoZ6vm6E9GK2OrF6DSJSpIbRbi+Nn0WDPID9O7xB2Q==", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css", Integrity = "sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/js/bootstrap.bundle.min.js", Integrity = "sha512-9GacT4119eY3AcosfWtHMsT5JyZudrexyEVzTBWV3viP/YfB9e2pEy3N7WXL3SV6ASXpTU0vzzSxsbfsuUH4sQ==", CrossOrigin = "anonymous" }
|
||||
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", Integrity = "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", CrossOrigin = "anonymous" }
|
||||
};
|
||||
|
||||
}
|
@ -2,12 +2,9 @@
|
||||
@namespace Oqtane.Themes.Controls
|
||||
@inherits ContainerBase
|
||||
@attribute [OqtaneIgnore]
|
||||
@inject SiteState SiteState
|
||||
|
||||
<span class="app-moduletitle">
|
||||
<a id="@ModuleState.PageModuleId.ToString()">
|
||||
@((MarkupString)title)
|
||||
</a>
|
||||
@((MarkupString)title)
|
||||
</span>
|
||||
|
||||
@code {
|
||||
|
@ -1,3 +1,4 @@
|
||||
@using System.Net
|
||||
@namespace Oqtane.Themes.Controls
|
||||
@inherits ThemeControlBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@ -55,7 +56,7 @@
|
||||
</div>
|
||||
<hr class="app-rule" />
|
||||
}
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
@ -64,7 +65,10 @@
|
||||
</div>
|
||||
<div class="row d-flex mb-2">
|
||||
<div class="col d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary col me-1" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Add"))>@SharedLocalizer["Add"]</button>
|
||||
@if (PageState.Page.UserId == null)
|
||||
{
|
||||
<button type="button" class="btn btn-secondary col me-1" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Add"))>@SharedLocalizer["Add"]</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary col" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Edit"))>@SharedLocalizer["Edit"]</button>
|
||||
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||
</div>
|
||||
@ -144,7 +148,7 @@
|
||||
}
|
||||
@foreach (var moduledefinition in _moduleDefinitions)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.PermissionList))
|
||||
if (moduledefinition.IsEnabled && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.PermissionList))
|
||||
{
|
||||
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
||||
{
|
||||
@ -223,270 +227,274 @@
|
||||
}
|
||||
|
||||
@code{
|
||||
private bool _canViewAdminDashboard = false;
|
||||
private bool _showEditMode = false;
|
||||
private bool _deleteConfirmation = false;
|
||||
private List<string> _categories = new List<string>();
|
||||
private List<ModuleDefinition> _allModuleDefinitions;
|
||||
private List<ModuleDefinition> _moduleDefinitions;
|
||||
private List<Page> _pages = new List<Page>();
|
||||
private List<Module> _modules = new List<Module>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _category = "Common";
|
||||
private bool _canViewAdminDashboard = false;
|
||||
private bool _showEditMode = false;
|
||||
private bool _deleteConfirmation = false;
|
||||
private List<string> _categories = new List<string>();
|
||||
private List<ModuleDefinition> _allModuleDefinitions;
|
||||
private List<ModuleDefinition> _moduleDefinitions;
|
||||
private List<Page> _pages = new List<Page>();
|
||||
private List<Module> _modules = new List<Module>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _category = "Common";
|
||||
|
||||
protected string PageId { get; private set; } = "-";
|
||||
protected string ModuleId { get; private set; } = "-";
|
||||
protected string ModuleType { get; private set; } = "new";
|
||||
protected string ModuleDefinitionName { get; private set; } = "-";
|
||||
protected string PageId { get; private set; } = "-";
|
||||
protected string ModuleId { get; private set; } = "-";
|
||||
protected string ModuleType { get; private set; } = "new";
|
||||
protected string ModuleDefinitionName { get; private set; } = "-";
|
||||
|
||||
protected string Category
|
||||
{
|
||||
get => _category;
|
||||
private set
|
||||
{
|
||||
if (_category != value)
|
||||
{
|
||||
_category = value;
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||
ModuleDefinitionName = "-";
|
||||
Message = "";
|
||||
StateHasChanged();
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected string Category
|
||||
{
|
||||
get => _category;
|
||||
private set
|
||||
{
|
||||
if (_category != value)
|
||||
{
|
||||
_category = value;
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||
ModuleDefinitionName = "-";
|
||||
Message = "";
|
||||
StateHasChanged();
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string Pane
|
||||
{
|
||||
get => _pane;
|
||||
private set
|
||||
{
|
||||
if (_pane != value)
|
||||
{
|
||||
_pane = value;
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected string Pane
|
||||
{
|
||||
get => _pane;
|
||||
private set
|
||||
{
|
||||
if (_pane != value)
|
||||
{
|
||||
_pane = value;
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string Title { get; private set; } = "";
|
||||
protected string ContainerType { get; private set; } = "";
|
||||
protected string Visibility { get; private set; } = "view";
|
||||
protected string Message { get; private set; } = "";
|
||||
protected string Title { get; private set; } = "";
|
||||
protected string ContainerType { get; private set; } = "";
|
||||
protected string Visibility { get; private set; } = "view";
|
||||
protected string Message { get; private set; } = "";
|
||||
|
||||
[Parameter]
|
||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||
[Parameter]
|
||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||
|
||||
[Parameter]
|
||||
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
||||
[Parameter]
|
||||
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
||||
|
||||
[Parameter]
|
||||
public string HeaderClass { get; set; } = "offcanvas-header";
|
||||
[Parameter]
|
||||
public string HeaderClass { get; set; } = "offcanvas-header";
|
||||
|
||||
[Parameter]
|
||||
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
||||
[Parameter]
|
||||
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
||||
|
||||
[Parameter]
|
||||
public bool ShowLanguageSwitcher { get; set; } = true;
|
||||
[Parameter]
|
||||
public bool ShowLanguageSwitcher { get; set; } = true;
|
||||
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_canViewAdminDashboard = CanViewAdminDashboard();
|
||||
_showEditMode = false;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||
{
|
||||
_showEditMode = true;
|
||||
_pages?.Clear();
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_canViewAdminDashboard = CanViewAdminDashboard();
|
||||
_showEditMode = false;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||
{
|
||||
_showEditMode = true;
|
||||
_pages?.Clear();
|
||||
|
||||
foreach (Page p in PageState.Pages)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
_pages.Add(p);
|
||||
}
|
||||
}
|
||||
await LoadSettingsAsync();
|
||||
foreach (Page p in PageState.Pages)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
_pages.Add(p);
|
||||
}
|
||||
}
|
||||
await LoadSettingsAsync();
|
||||
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
||||
ContainerType = PageState.Site.DefaultContainerType;
|
||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.PermissionList))
|
||||
{
|
||||
_showEditMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
||||
ContainerType = PageState.Site.DefaultContainerType;
|
||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.PermissionList))
|
||||
{
|
||||
_showEditMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanViewAdminDashboard()
|
||||
{
|
||||
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
||||
if (admin != null)
|
||||
{
|
||||
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private bool CanViewAdminDashboard()
|
||||
{
|
||||
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
||||
if (admin != null)
|
||||
{
|
||||
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CategoryChanged(ChangeEventArgs e)
|
||||
{
|
||||
Category = (string)e.Value;
|
||||
}
|
||||
private void CategoryChanged(ChangeEventArgs e)
|
||||
{
|
||||
Category = (string)e.Value;
|
||||
}
|
||||
|
||||
private void ModuleChanged(ChangeEventArgs e)
|
||||
{
|
||||
ModuleDefinitionName = (string)e.Value;
|
||||
if (ModuleDefinitionName != "-")
|
||||
{
|
||||
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
|
||||
Message = "<div class=\"alert alert-info mt-2 text-center\" role=\"alert\">" + moduleDefinition.Description + "</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = "";
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
private void ModuleChanged(ChangeEventArgs e)
|
||||
{
|
||||
ModuleDefinitionName = (string)e.Value;
|
||||
if (ModuleDefinitionName != "-")
|
||||
{
|
||||
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
|
||||
Message = "<div class=\"alert alert-info mt-2 text-center\" role=\"alert\">" + moduleDefinition.Description + "</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = "";
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void PageChanged(ChangeEventArgs e)
|
||||
{
|
||||
PageId = (string)e.Value;
|
||||
if (PageId != "-")
|
||||
{
|
||||
_modules = PageState.Modules
|
||||
.Where(module => module.PageId == int.Parse(PageId) &&
|
||||
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||
.ToList();
|
||||
}
|
||||
ModuleId = "-";
|
||||
StateHasChanged();
|
||||
}
|
||||
private void PageChanged(ChangeEventArgs e)
|
||||
{
|
||||
PageId = (string)e.Value;
|
||||
if (PageId != "-")
|
||||
{
|
||||
_modules = PageState.Modules
|
||||
.Where(module => module.PageId == int.Parse(PageId) &&
|
||||
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||
.ToList();
|
||||
}
|
||||
ModuleId = "-";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task AddModule()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||
{
|
||||
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
Module module = new Module();
|
||||
module.SiteId = PageState.Site.SiteId;
|
||||
module.PageId = PageState.Page.PageId;
|
||||
module.ModuleDefinitionName = ModuleDefinitionName;
|
||||
module.AllPages = false;
|
||||
private async Task AddModule()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||
{
|
||||
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
Module module = new Module();
|
||||
module.SiteId = PageState.Site.SiteId;
|
||||
module.PageId = PageState.Page.PageId;
|
||||
module.ModuleDefinitionName = ModuleDefinitionName;
|
||||
module.AllPages = false;
|
||||
|
||||
var permissions = new List<Permission>();
|
||||
if (Visibility == "view")
|
||||
{
|
||||
// set module view permissions to page view permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set module view permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit);
|
||||
}
|
||||
// set module edit permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit);
|
||||
module.PermissionList = permissions;
|
||||
var permissions = new List<Permission>();
|
||||
if (Visibility == "view")
|
||||
{
|
||||
// set module view permissions to page view permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set module view permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit);
|
||||
}
|
||||
// set module edit permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit);
|
||||
module.PermissionList = permissions;
|
||||
|
||||
module = await ModuleService.AddModuleAsync(module);
|
||||
ModuleId = module.ModuleId.ToString();
|
||||
}
|
||||
module = await ModuleService.AddModuleAsync(module);
|
||||
ModuleId = module.ModuleId.ToString();
|
||||
}
|
||||
|
||||
var pageModule = new PageModule
|
||||
var pageModule = new PageModule
|
||||
{
|
||||
PageId = PageState.Page.PageId,
|
||||
ModuleId = int.Parse(ModuleId),
|
||||
Title = Title
|
||||
};
|
||||
if (pageModule.Title == "")
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
|
||||
}
|
||||
}
|
||||
if (pageModule.Title == "")
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
|
||||
}
|
||||
}
|
||||
|
||||
pageModule.Pane = Pane;
|
||||
pageModule.Order = int.MaxValue;
|
||||
pageModule.ContainerType = ContainerType;
|
||||
pageModule.Pane = Pane;
|
||||
pageModule.Order = int.MaxValue;
|
||||
pageModule.ContainerType = ContainerType;
|
||||
|
||||
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
pageModule.ContainerType = "";
|
||||
}
|
||||
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
pageModule.ContainerType = "";
|
||||
}
|
||||
|
||||
await PageModuleService.AddPageModuleAsync(pageModule);
|
||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||
await PageModuleService.AddPageModuleAsync(pageModule);
|
||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||
|
||||
Message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||
Title = "";
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = $"<div class=\"alert alert-warning mt-2 text-center\" role=\"alert\">{Localizer["Message.Require.ModuleSelect"]}</div>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = $"<div class=\"alert alert-error mt-2 text-center\" role=\"alert\">{Localizer["Error.Authorize.No"]}</div>";
|
||||
}
|
||||
}
|
||||
Message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||
Title = "";
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = $"<div class=\"alert alert-warning mt-2 text-center\" role=\"alert\">{Localizer["Message.Require.ModuleSelect"]}</div>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = $"<div class=\"alert alert-error mt-2 text-center\" role=\"alert\">{Localizer["Error.Authorize.No"]}</div>";
|
||||
}
|
||||
}
|
||||
|
||||
private List<Permission> SetPermissions(List<Permission> permissions, int siteId, string modulePermission, string pagePermission)
|
||||
{
|
||||
foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission))
|
||||
{
|
||||
permissions.Add(new Permission { SiteId = siteId, EntityName = EntityNames.Module, PermissionName = modulePermission, RoleId = permission.RoleId, UserId = permission.UserId, IsAuthorized = permission.IsAuthorized });
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
private List<Permission> SetPermissions(List<Permission> permissions, int siteId, string modulePermission, string pagePermission)
|
||||
{
|
||||
foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission))
|
||||
{
|
||||
permissions.Add(new Permission { SiteId = siteId, EntityName = EntityNames.Module, PermissionName = modulePermission, RoleId = permission.RoleId, UserId = permission.UserId, IsAuthorized = permission.IsAuthorized });
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
private async Task ToggleEditMode(bool EditMode)
|
||||
{
|
||||
if (_showEditMode)
|
||||
{
|
||||
if (EditMode)
|
||||
{
|
||||
PageState.EditMode = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PageState.EditMode = true;
|
||||
}
|
||||
private async Task ToggleEditMode(bool EditMode)
|
||||
{
|
||||
if (_showEditMode)
|
||||
{
|
||||
if (EditMode)
|
||||
{
|
||||
PageState.EditMode = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PageState.EditMode = true;
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false")));
|
||||
// preserve other querystring parameters
|
||||
if (PageState.QueryString.ContainsKey("edit")) PageState.QueryString.Remove("edit");
|
||||
PageState.QueryString.Add("edit", PageState.EditMode.ToString().ToLower());
|
||||
var url = PageState.Route.AbsolutePath + Utilities.CreateQueryString(PageState.QueryString);
|
||||
NavigationManager.NavigateTo(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageState.Page.IsPersonalizable && PageState.User != null)
|
||||
{
|
||||
await PageService.AddPageAsync(PageState.Page.PageId, PageState.User.UserId);
|
||||
var page = await PageService.AddPageAsync(PageState.Page.PageId, PageState.User.UserId);
|
||||
PageState.EditMode = true;
|
||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false")));
|
||||
NavigationManager.NavigateTo(NavigateUrl(page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false")));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -501,7 +509,7 @@
|
||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
||||
if (module != null)
|
||||
{
|
||||
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, module.ModuleId, "Index", ""));
|
||||
NavigationManager.NavigateTo(EditUrl("admin", module.ModuleId, "Index", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery)));
|
||||
}
|
||||
break;
|
||||
case "Add":
|
||||
@ -515,10 +523,10 @@
|
||||
switch (location)
|
||||
{
|
||||
case "Add":
|
||||
url = EditUrl(PageState.Page.Path, module.ModuleId, location, "cp=" + PageState.Page.PageId);
|
||||
break;
|
||||
url = EditUrl("admin/pages", module.ModuleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}");
|
||||
break;
|
||||
case "Edit":
|
||||
url = EditUrl(PageState.Page.Path, module.ModuleId, location, "id=" + PageState.Page.PageId.ToString() + "&cp=" + PageState.Page.PageId);
|
||||
url = EditUrl("admin/pages", module.ModuleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ namespace Oqtane.Themes.Controls
|
||||
[Inject] public IUserService UserService { get; set; }
|
||||
[Inject] public IJSRuntime jsRuntime { get; set; }
|
||||
[Inject] public IServiceProvider ServiceProvider { get; set; }
|
||||
[Inject] public SiteState SiteState { get; set; }
|
||||
[Inject] public ILogService LoggingService { get; set; }
|
||||
|
||||
protected void LoginUser()
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Themes.OqtaneTheme
|
||||
{
|
||||
@ -11,7 +13,13 @@ namespace Oqtane.Themes.OqtaneTheme
|
||||
Name = "Oqtane Theme",
|
||||
Version = "1.0.0",
|
||||
ThemeSettingsType = "Oqtane.Themes.OqtaneTheme.ThemeSettings, Oqtane.Client",
|
||||
ContainerSettingsType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client"
|
||||
ContainerSettingsType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client",
|
||||
Resources = new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.0/cyborg/bootstrap.min.css", Integrity = "sha512-jwIqEv8o/kTBMJVtbNCBrDqhBojl0YSUam+EFpLjVOC86Ci6t4ZciTnIkelFNOik+dEQVymKGcQLiaJZNAfWRg==", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", Integrity = "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", CrossOrigin = "anonymous" }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -110,14 +110,6 @@
|
||||
|
||||
public override string Panes => PaneNames.Default + ",Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width,Footer";
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
// obtained from https://cdnjs.com/libraries
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.2.0/cyborg/bootstrap.min.css", Integrity = "sha512-d6pZJl/sNcj0GFkp4kTjXtPE14deuUsOqFQtxkj0KyBJQl+4e0qsEyuIDcNqrYuGoauAW3sWyDCQp49mhF4Syw==", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/js/bootstrap.bundle.min.js", Integrity = "sha512-9GacT4119eY3AcosfWtHMsT5JyZudrexyEVzTBWV3viP/YfB9e2pEy3N7WXL3SV6ASXpTU0vzzSxsbfsuUH4sQ==", CrossOrigin = "anonymous" }
|
||||
};
|
||||
|
||||
private bool _login = true;
|
||||
private bool _register = true;
|
||||
private bool _footer = false;
|
||||
|
@ -52,17 +52,23 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string resourceType = "Oqtane.Themes.OqtaneTheme.ThemeSettings, Oqtane.Client"; // for localization
|
||||
private string _scope = "page";
|
||||
private string _login = "-";
|
||||
private string _register = "-";
|
||||
private string _footer = "-";
|
||||
private int pageId = -1;
|
||||
private string resourceType = "Oqtane.Themes.OqtaneTheme.ThemeSettings, Oqtane.Client"; // for localization
|
||||
private string _scope = "page";
|
||||
private string _login = "-";
|
||||
private string _register = "-";
|
||||
private string _footer = "-";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadSettings();
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
pageId = int.Parse(PageState.QueryString["id"]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await LoadSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -82,10 +88,11 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
var settings = SettingService.MergeSettings(PageState.Site.Settings, PageState.Page.Settings);
|
||||
var settings = await SettingService.GetPageSettingsAsync(pageId);
|
||||
settings = SettingService.MergeSettings(PageState.Site.Settings, settings);
|
||||
_login = SettingService.GetSetting(settings, GetType().Namespace + ":Login", "-");
|
||||
_register = SettingService.GetSetting(settings, GetType().Namespace + ":Register", "-");
|
||||
_footer = SettingService.GetSetting(settings, GetType().Namespace + ":Footer", "-");
|
||||
_footer = SettingService.GetSetting(settings, GetType().Namespace + ":Footer", "-");
|
||||
}
|
||||
await Task.Yield();
|
||||
}
|
||||
@ -128,7 +135,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
var settings = await SettingService.GetPageSettingsAsync(PageState.Page.PageId);
|
||||
var settings = await SettingService.GetPageSettingsAsync(pageId);
|
||||
if (_login != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
|
||||
@ -141,7 +148,7 @@
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Footer", _footer);
|
||||
}
|
||||
await SettingService.UpdatePageSettingsAsync(settings, PageState.Page.PageId);
|
||||
await SettingService.UpdatePageSettingsAsync(settings, pageId);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -6,6 +6,7 @@ using Oqtane.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Themes
|
||||
@ -15,10 +16,13 @@ namespace Oqtane.Themes
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; }
|
||||
|
||||
// optional interface properties
|
||||
[Inject]
|
||||
protected SiteState SiteState { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
|
||||
// optional interface properties
|
||||
public virtual string Name { get; set; }
|
||||
public virtual string Thumbnail { get; set; }
|
||||
public virtual string Panes { get; set; }
|
||||
@ -30,17 +34,33 @@ namespace Oqtane.Themes
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||
List<Resource> resources = null;
|
||||
var type = GetType();
|
||||
if (type.BaseType == typeof(ThemeBase))
|
||||
{
|
||||
if (PageState.Page.Resources != null)
|
||||
{
|
||||
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level != ResourceLevel.Site && item.Namespace == type.Namespace).ToList();
|
||||
}
|
||||
}
|
||||
else // themecontrolbase, containerbase
|
||||
{
|
||||
if (Resources != null)
|
||||
{
|
||||
resources = Resources.Where(item => item.ResourceType == ResourceType.Script).ToList();
|
||||
}
|
||||
}
|
||||
if (resources != null && resources.Any())
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
var scripts = new List<object>();
|
||||
var inline = 0;
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||
foreach (Resource resource in resources)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(resource.Url))
|
||||
{
|
||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module, location = resource.Location.ToString().ToLower() });
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -139,6 +159,33 @@ namespace Oqtane.Themes
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, position, background, rotate, recreate);
|
||||
}
|
||||
|
||||
public void SetPageTitle(string title)
|
||||
{
|
||||
SiteState.Properties.PageTitle = title;
|
||||
}
|
||||
|
||||
// note - only supports links and meta tags - not scripts
|
||||
public void AddHeadContent(string content)
|
||||
{
|
||||
SiteState.AppendHeadContent(content);
|
||||
}
|
||||
|
||||
public void AddScript(Resource resource)
|
||||
{
|
||||
resource.ResourceType = ResourceType.Script;
|
||||
if (Resources == null) Resources = new List<Resource>();
|
||||
if (!Resources.Any(item => (!string.IsNullOrEmpty(resource.Url) && item.Url == resource.Url) || (!string.IsNullOrEmpty(resource.Content) && item.Content == resource.Content)))
|
||||
{
|
||||
Resources.Add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ScrollToPageTop()
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
|
||||
[Obsolete("ContentUrl(int fileId) is deprecated. Use FileUrl(int fileId) instead.", false)]
|
||||
public string ContentUrl(int fileid)
|
||||
{
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
@if (_visible)
|
||||
{
|
||||
<CascadingValue Value="@ModuleState">
|
||||
<a id="@ModuleState.PageModuleId.ToString()"></a>
|
||||
<CascadingValue Value="@ModuleState">
|
||||
@if (_useadminborder)
|
||||
{
|
||||
<div class="app-pane-admin-border">
|
||||
@ -16,6 +17,7 @@
|
||||
@DynamicComponent
|
||||
}
|
||||
</CascadingValue>
|
||||
|
||||
}
|
||||
|
||||
@code {
|
||||
@ -38,7 +40,7 @@
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
string container = ModuleState.ContainerType;
|
||||
if (PageState.ModuleId != -1 && ModuleState.UseAdminContainer)
|
||||
if (PageState.ModuleId != -1 && PageState.Route.Action != "" && ModuleState.UseAdminContainer)
|
||||
{
|
||||
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
}
|
||||
|
@ -95,8 +95,8 @@ namespace Oqtane.UI
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeLinks",
|
||||
(object) links);
|
||||
"Oqtane.Interop.includeLinks",
|
||||
(object)links);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
@ -107,12 +107,17 @@ namespace Oqtane.UI
|
||||
|
||||
// external scripts need to specify src, inline scripts need to specify id and content
|
||||
public Task IncludeScript(string id, string src, string integrity, string crossorigin, string content, string location)
|
||||
{
|
||||
return IncludeScript(id, src, integrity, crossorigin, "", content, location);
|
||||
}
|
||||
|
||||
public Task IncludeScript(string id, string src, string integrity, string crossorigin, string type, string content, string location)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.includeScript",
|
||||
id, src, integrity, crossorigin, content, location);
|
||||
id, src, integrity, crossorigin, type, content, location);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
|
@ -13,6 +13,7 @@ namespace Oqtane.UI
|
||||
public Page Page { get; set; }
|
||||
public User User { get; set; }
|
||||
public Uri Uri { get; set; }
|
||||
public Route Route { get; set; }
|
||||
public Dictionary<string, string> QueryString { get; set; }
|
||||
public string UrlParameters { get; set; }
|
||||
public int ModuleId { get; set; }
|
||||
@ -23,6 +24,7 @@ namespace Oqtane.UI
|
||||
public int VisitorId { get; set; }
|
||||
public string RemoteIPAddress { get; set; }
|
||||
public string ReturnUrl { get; set; }
|
||||
public bool IsInternalNavigation { get; set; }
|
||||
|
||||
public List<Page> Pages
|
||||
{
|
||||
|
@ -17,61 +17,59 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _useadminborder = false;
|
||||
private string _panetitle = "";
|
||||
private bool _useadminborder = false;
|
||||
private string _panetitle = "";
|
||||
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Name { get; set; }
|
||||
[Parameter]
|
||||
public string Name { get; set; }
|
||||
|
||||
RenderFragment DynamicComponent { get; set; }
|
||||
RenderFragment DynamicComponent { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction)
|
||||
{
|
||||
_useadminborder = true;
|
||||
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
_useadminborder = false;
|
||||
_panetitle = "";
|
||||
}
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction)
|
||||
{
|
||||
_useadminborder = true;
|
||||
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
_useadminborder = false;
|
||||
_panetitle = "";
|
||||
}
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
if (PageState.ModuleId != -1 && PageState.Action != Constants.DefaultAction)
|
||||
{
|
||||
// action route needs to inject module control into specific pane
|
||||
string pane = "";
|
||||
if (PageState.Page.Panes.FindIndex(item => item.Equals(PaneNames.Default, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
pane = PaneNames.Default;
|
||||
}
|
||||
else
|
||||
{
|
||||
pane = PaneNames.Admin;
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
||||
{
|
||||
var pane = module.Pane;
|
||||
if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction)
|
||||
{
|
||||
if (PageState.Page.Panes.FindIndex(item => item.Equals(PaneNames.Default, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
pane = PaneNames.Default;
|
||||
}
|
||||
else
|
||||
{
|
||||
pane = PaneNames.Admin;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (Name.ToLower() == pane.ToLower())
|
||||
{
|
||||
Module module = PageState.Modules.FirstOrDefault(item => item.PageId == PageState.Page.PageId && item.ModuleId == PageState.ModuleId);
|
||||
if (module == null)
|
||||
{
|
||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
|
||||
}
|
||||
if (module != null)
|
||||
{
|
||||
var moduleType = Type.GetType(module.ModuleType);
|
||||
if (moduleType != null)
|
||||
{
|
||||
bool authorized = false;
|
||||
if (Constants.DefaultModuleActions.Contains(PageState.Action))
|
||||
{
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList);
|
||||
// pane matches current pane
|
||||
if (Name.ToLower() == pane.ToLower())
|
||||
{
|
||||
if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction)
|
||||
{
|
||||
var moduleType = Type.GetType(module.ModuleType);
|
||||
if (moduleType != null)
|
||||
{
|
||||
bool authorized = false;
|
||||
if (Constants.DefaultModuleActions.Contains(PageState.Action))
|
||||
{
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -100,43 +98,20 @@ else
|
||||
CreateComponent(builder, module);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// module type does not exist
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageState.ModuleId != -1)
|
||||
{
|
||||
Module module = PageState.Modules.FirstOrDefault(item => item.PageId == PageState.Page.PageId && item.ModuleId == PageState.ModuleId);
|
||||
if (module == null)
|
||||
{
|
||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
|
||||
}
|
||||
if (module != null && module.Pane.ToLower() == Name.ToLower())
|
||||
else
|
||||
{
|
||||
// check if user is authorized to view module
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||
if (PageState.ModuleId == -1 || PageState.ModuleId == module.ModuleId)
|
||||
{
|
||||
CreateComponent(builder, module);
|
||||
// check if user is authorized to view module
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||
{
|
||||
CreateComponent(builder, module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower()))
|
||||
{
|
||||
// check if user is authorized to view module
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||
{
|
||||
CreateComponent(builder, module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -22,207 +22,243 @@
|
||||
@DynamicComponent
|
||||
|
||||
@code {
|
||||
private string _absoluteUri;
|
||||
private bool _navigationInterceptionEnabled;
|
||||
private PageState _pagestate;
|
||||
private string _error = "";
|
||||
private string _absoluteUri;
|
||||
private bool _isInternalNavigation = false;
|
||||
private bool _navigationInterceptionEnabled;
|
||||
private PageState _pagestate;
|
||||
private string _error = "";
|
||||
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
PageState PageState { get; set; }
|
||||
[CascadingParameter]
|
||||
PageState PageState { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Action<PageState> OnStateChange { get; set; }
|
||||
[Parameter]
|
||||
public Action<PageState> OnStateChange { get; set; }
|
||||
|
||||
private RenderFragment DynamicComponent { get; set; }
|
||||
private RenderFragment DynamicComponent { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_absoluteUri = NavigationManager.Uri;
|
||||
NavigationManager.LocationChanged += LocationChanged;
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_absoluteUri = NavigationManager.Uri;
|
||||
NavigationManager.LocationChanged += LocationChanged;
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
if (PageState != null)
|
||||
{
|
||||
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
};
|
||||
}
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
if (PageState != null)
|
||||
{
|
||||
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavigationManager.LocationChanged -= LocationChanged;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
NavigationManager.LocationChanged -= LocationChanged;
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (PageState == null)
|
||||
{
|
||||
await Refresh();
|
||||
}
|
||||
}
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (PageState == null)
|
||||
{
|
||||
await Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
||||
private async Task Refresh()
|
||||
{
|
||||
Site site;
|
||||
Page page;
|
||||
User user = null;
|
||||
var editmode = false;
|
||||
var refresh = false;
|
||||
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
|
||||
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);
|
||||
_error = "";
|
||||
private async void LocationChanged(object sender, LocationChangedEventArgs args)
|
||||
{
|
||||
_absoluteUri = args.Location;
|
||||
_isInternalNavigation = true;
|
||||
await Refresh();
|
||||
}
|
||||
|
||||
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
||||
int moduleid = (int.TryParse(route.ModuleId, out moduleid)) ? moduleid : -1;
|
||||
var action = (!string.IsNullOrEmpty(route.Action)) ? route.Action : Constants.DefaultAction;
|
||||
var querystring = ParseQueryString(route.Query);
|
||||
var returnurl = "";
|
||||
if (querystring.ContainsKey("returnurl"))
|
||||
{
|
||||
returnurl = WebUtility.UrlDecode(querystring["returnurl"]);
|
||||
}
|
||||
Task IHandleAfterRender.OnAfterRenderAsync()
|
||||
{
|
||||
if (!_navigationInterceptionEnabled)
|
||||
{
|
||||
_navigationInterceptionEnabled = true;
|
||||
return NavigationInterception.EnableNavigationInterceptionAsync();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// reload the client application from the server if there is a forced reload or the user navigated to a site with a different alias
|
||||
if (querystring.ContainsKey("reload") || (!NavigationManager.ToBaseRelativePath(_absoluteUri).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||
{
|
||||
if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
|
||||
{
|
||||
// post back so that the cookies are set correctly - required on any change to the principal
|
||||
var interop = new Interop(JSRuntime);
|
||||
var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) };
|
||||
string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/");
|
||||
await interop.SubmitForm(url, fields);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
||||
private async Task Refresh()
|
||||
{
|
||||
Site site;
|
||||
Page page;
|
||||
User user = null;
|
||||
var editmode = false;
|
||||
var refresh = false;
|
||||
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
|
||||
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);
|
||||
_error = "";
|
||||
|
||||
// the refresh parameter is used to refresh the client-side PageState
|
||||
if (querystring.ContainsKey("refresh"))
|
||||
{
|
||||
refresh = true;
|
||||
}
|
||||
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
||||
int moduleid = (int.TryParse(route.ModuleId, out moduleid)) ? moduleid : -1;
|
||||
var action = (!string.IsNullOrEmpty(route.Action)) ? route.Action : Constants.DefaultAction;
|
||||
var querystring = Utilities.ParseQueryString(route.Query);
|
||||
var returnurl = "";
|
||||
if (querystring.ContainsKey("returnurl"))
|
||||
{
|
||||
returnurl = WebUtility.UrlDecode(querystring["returnurl"]);
|
||||
}
|
||||
|
||||
if (PageState != null)
|
||||
{
|
||||
editmode = PageState.EditMode;
|
||||
lastsyncdate = PageState.LastSyncDate;
|
||||
}
|
||||
if (PageState?.Page.Path != route.PagePath)
|
||||
{
|
||||
editmode = false; // reset edit mode when navigating to different page
|
||||
}
|
||||
// reload the client application from the server if there is a forced reload or the user navigated to a site with a different alias
|
||||
if (querystring.ContainsKey("reload") || (!NavigationManager.ToBaseRelativePath(_absoluteUri).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||
{
|
||||
if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
|
||||
{
|
||||
// post back so that the cookies are set correctly - required on any change to the principal
|
||||
var interop = new Interop(JSRuntime);
|
||||
var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) };
|
||||
string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/");
|
||||
await interop.SubmitForm(url, fields);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get user
|
||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
if (authState.User.Identity.IsAuthenticated)
|
||||
{
|
||||
user = await UserService.GetUserAsync(authState.User.Identity.Name, SiteState.Alias.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user = PageState.User;
|
||||
}
|
||||
// the refresh parameter is used to refresh the client-side PageState
|
||||
if (querystring.ContainsKey("refresh"))
|
||||
{
|
||||
refresh = true;
|
||||
}
|
||||
|
||||
// process any sync events
|
||||
var sync = await SyncService.GetSyncAsync(lastsyncdate);
|
||||
lastsyncdate = sync.SyncDate;
|
||||
if (sync.SyncEvents.Any())
|
||||
{
|
||||
// reload client application if server was restarted or site runtime/rendermode was modified
|
||||
if (PageState != null && sync.SyncEvents.Exists(item => (item.Action == SyncEventActions.Reload)))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||
return;
|
||||
}
|
||||
// when site information has changed the PageState needs to be refreshed
|
||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
||||
{
|
||||
refresh = true;
|
||||
}
|
||||
// when user information has changed the PageState needs to be refreshed as the list of pages/modules may have changed
|
||||
if (user != null && sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId))
|
||||
{
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
if (PageState != null)
|
||||
{
|
||||
editmode = PageState.EditMode;
|
||||
lastsyncdate = PageState.LastSyncDate;
|
||||
}
|
||||
if (PageState?.Page.Path != route.PagePath)
|
||||
{
|
||||
editmode = false; // reset edit mode when navigating to different page
|
||||
}
|
||||
|
||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||
{
|
||||
site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId);
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
site = PageState.Site;
|
||||
}
|
||||
// get user
|
||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
if (authState.User.Identity.IsAuthenticated)
|
||||
{
|
||||
user = await UserService.GetUserAsync(authState.User.Identity.Name, SiteState.Alias.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user = PageState.User;
|
||||
}
|
||||
|
||||
if (site != null)
|
||||
{
|
||||
if (PageState == null || refresh || PageState.Page.Path != route.PagePath)
|
||||
{
|
||||
page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
page = PageState.Page;
|
||||
}
|
||||
// process any sync events
|
||||
var sync = await SyncService.GetSyncAsync(lastsyncdate);
|
||||
lastsyncdate = sync.SyncDate;
|
||||
if (sync.SyncEvents.Any())
|
||||
{
|
||||
// reload client application if server was restarted or site runtime/rendermode was modified
|
||||
if (PageState != null && sync.SyncEvents.Exists(item => (item.Action == SyncEventActions.Reload)))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||
return;
|
||||
}
|
||||
// when site information has changed the PageState needs to be refreshed
|
||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
||||
{
|
||||
refresh = true;
|
||||
}
|
||||
// when user information has changed the PageState needs to be refreshed as the list of pages/modules may have changed
|
||||
if (user != null && sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId))
|
||||
{
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (page == null && route.PagePath == "") // naked path refers to site home page
|
||||
{
|
||||
if (site.HomePageId != null)
|
||||
{
|
||||
page = site.Pages.FirstOrDefault(item => item.PageId == site.HomePageId);
|
||||
}
|
||||
if (page == null)
|
||||
{
|
||||
// fallback to use the first page in the collection
|
||||
page = site.Pages.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||
{
|
||||
site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId);
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
site = PageState.Site;
|
||||
}
|
||||
|
||||
if (page != null)
|
||||
{
|
||||
// check if user is authorized to view page
|
||||
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
// load additional metadata for current page
|
||||
page = await ProcessPage(page, site, user);
|
||||
if (site != null)
|
||||
{
|
||||
if (PageState == null || refresh || PageState.Page.Path != route.PagePath)
|
||||
{
|
||||
page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
page = PageState.Page;
|
||||
}
|
||||
|
||||
// load additional metadata for modules
|
||||
(page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType);
|
||||
if (page == null && route.PagePath == "") // naked path refers to site home page
|
||||
{
|
||||
if (site.HomePageId != null)
|
||||
{
|
||||
page = site.Pages.FirstOrDefault(item => item.PageId == site.HomePageId);
|
||||
}
|
||||
if (page == null)
|
||||
{
|
||||
// fallback to use the first page in the collection
|
||||
page = site.Pages.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
if (page == null)
|
||||
{
|
||||
// look for personalized page
|
||||
page = await PageService.GetPageAsync(route.PagePath, site.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (user != null && page.IsPersonalizable)
|
||||
{
|
||||
var personalized = await PageService.GetPageAsync(route.PagePath + "/" + user.Username, site.SiteId);
|
||||
if (personalized != null)
|
||||
{
|
||||
// redirect to the personalized page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, personalized.Path, ""), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate page state (which acts as a client-side cache for subsequent requests)
|
||||
_pagestate = new PageState
|
||||
if (page != null)
|
||||
{
|
||||
// check if user is authorized to view page
|
||||
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
// load additional metadata for current page
|
||||
page = ProcessPage(page, site, user, SiteState.Alias);
|
||||
|
||||
// load additional metadata for modules
|
||||
(page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias);
|
||||
|
||||
// populate page state (which acts as a client-side cache for subsequent requests)
|
||||
_pagestate = new PageState
|
||||
{
|
||||
Alias = SiteState.Alias,
|
||||
Site = site,
|
||||
Page = page,
|
||||
User = user,
|
||||
Uri = new Uri(_absoluteUri, UriKind.Absolute),
|
||||
Route = route,
|
||||
QueryString = querystring,
|
||||
UrlParameters = route.UrlParameters,
|
||||
ModuleId = moduleid,
|
||||
@ -232,300 +268,270 @@
|
||||
Runtime = runtime,
|
||||
VisitorId = VisitorId,
|
||||
RemoteIPAddress = SiteState.RemoteIPAddress,
|
||||
ReturnUrl = returnurl
|
||||
ReturnUrl = returnurl,
|
||||
IsInternalNavigation = _isInternalNavigation
|
||||
};
|
||||
|
||||
OnStateChange?.Invoke(_pagestate);
|
||||
await ScrollToFragment(_pagestate.Uri);
|
||||
}
|
||||
}
|
||||
else // page not found
|
||||
{
|
||||
// look for url mapping
|
||||
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
|
||||
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
|
||||
{
|
||||
var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl;
|
||||
NavigationManager.NavigateTo(url, false);
|
||||
}
|
||||
else // not mapped
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
// redirect to login page if user not logged in as they may need to be authenticated
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (route.PagePath != "404")
|
||||
{
|
||||
// redirect to 404 page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to home page as a fallback
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// site does not exist
|
||||
}
|
||||
}
|
||||
OnStateChange?.Invoke(_pagestate);
|
||||
await ScrollToFragment(_pagestate.Uri);
|
||||
}
|
||||
}
|
||||
else // page not found
|
||||
{
|
||||
// look for url mapping
|
||||
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
|
||||
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
|
||||
{
|
||||
var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl;
|
||||
NavigationManager.NavigateTo(url, false);
|
||||
}
|
||||
else // not mapped
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
// redirect to login page if user not logged in as they may need to be authenticated
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (route.PagePath != "404")
|
||||
{
|
||||
// redirect to 404 page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to home page as a fallback
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// site does not exist
|
||||
}
|
||||
}
|
||||
|
||||
private async void LocationChanged(object sender, LocationChangedEventArgs args)
|
||||
{
|
||||
_absoluteUri = args.Location;
|
||||
await Refresh();
|
||||
}
|
||||
private Page ProcessPage(Page page, Site site, User user, Alias alias)
|
||||
{
|
||||
try
|
||||
{
|
||||
page.Panes = new List<string>();
|
||||
page.Resources = new List<Resource>();
|
||||
|
||||
Task IHandleAfterRender.OnAfterRenderAsync()
|
||||
{
|
||||
if (!_navigationInterceptionEnabled)
|
||||
{
|
||||
_navigationInterceptionEnabled = true;
|
||||
return NavigationInterception.EnableNavigationInterceptionAsync();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
// validate theme
|
||||
if (string.IsNullOrEmpty(page.ThemeType))
|
||||
{
|
||||
page.ThemeType = site.DefaultThemeType;
|
||||
}
|
||||
var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType));
|
||||
Type themetype = Type.GetType(page.ThemeType);
|
||||
if (themetype == null || theme == null)
|
||||
{
|
||||
// fallback to default Oqtane theme
|
||||
page.ThemeType = Constants.DefaultTheme;
|
||||
themetype = Type.GetType(Constants.DefaultTheme);
|
||||
theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType));
|
||||
}
|
||||
|
||||
private Dictionary<string, string> ParseQueryString(string query)
|
||||
{
|
||||
Dictionary<string, string> querystring = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // case insensistive keys
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
{
|
||||
if (query.StartsWith("?"))
|
||||
{
|
||||
query = query.Substring(1); // ignore "?"
|
||||
}
|
||||
foreach (string kvp in query.Split('&', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (kvp != "")
|
||||
{
|
||||
if (kvp.Contains("="))
|
||||
{
|
||||
string[] pair = kvp.Split('=');
|
||||
if (!querystring.ContainsKey(pair[0]))
|
||||
{
|
||||
querystring.Add(pair[0], pair[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!querystring.ContainsKey(kvp))
|
||||
{
|
||||
querystring.Add(kvp, "true"); // default parameter when no value is provided
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return querystring;
|
||||
}
|
||||
string panes = "";
|
||||
if (themetype != null && theme != null)
|
||||
{
|
||||
// get resources for theme (ITheme)
|
||||
page.Resources = ManagePageResources(page.Resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
|
||||
private async Task<Page> ProcessPage(Page page, Site site, User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (page.IsPersonalizable && user != null)
|
||||
{
|
||||
// load the personalized page
|
||||
page = await PageService.GetPageAsync(page.PageId, user.UserId);
|
||||
}
|
||||
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||
if (themeobject != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(themeobject.Panes))
|
||||
{
|
||||
panes = themeobject.Panes;
|
||||
}
|
||||
// get resources for theme control
|
||||
page.Resources = ManagePageResources(page.Resources, themeobject.Resources, ResourceLevel.Page, alias, "Themes", themetype.Namespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(page.ThemeType))
|
||||
{
|
||||
page.ThemeType = site.DefaultThemeType;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(panes))
|
||||
{
|
||||
page.Panes = panes.Replace(";", ",").Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
if (!page.Panes.Contains(PaneNames.Default) && !page.Panes.Contains(PaneNames.Admin))
|
||||
{
|
||||
_error = "The Current Theme Does Not Contain A Default Or Admin Pane";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Panes.Add(PaneNames.Admin);
|
||||
_error = "The Current Theme Does Not Contain Any Panes";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// error loading theme or layout
|
||||
}
|
||||
|
||||
page.Panes = new List<string>();
|
||||
page.Resources = new List<Resource>();
|
||||
return page;
|
||||
}
|
||||
|
||||
string panes = "";
|
||||
Type themetype = Type.GetType(page.ThemeType);
|
||||
if (themetype == null)
|
||||
{
|
||||
// fallback
|
||||
page.ThemeType = Constants.DefaultTheme;
|
||||
themetype = Type.GetType(Constants.DefaultTheme);
|
||||
}
|
||||
if (themetype != null)
|
||||
{
|
||||
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||
if (themeobject != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(themeobject.Panes))
|
||||
{
|
||||
panes = themeobject.Panes;
|
||||
}
|
||||
page.Resources = ManagePageResources(page.Resources, themeobject.Resources, ResourceLevel.Page);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(panes))
|
||||
{
|
||||
page.Panes = panes.Replace(";", ",").Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
if (!page.Panes.Contains(PaneNames.Default) && !page.Panes.Contains(PaneNames.Admin))
|
||||
{
|
||||
_error = "The Current Theme Does Not Contain A Default Or Admin Pane";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Panes.Add(PaneNames.Admin);
|
||||
_error = "The Current Theme Does Not Contain Any Panes";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// error loading theme or layout
|
||||
}
|
||||
private (Page Page, List<Module> Modules) ProcessModules(Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype, Alias alias)
|
||||
{
|
||||
var paneindex = new Dictionary<string, int>();
|
||||
foreach (Module module in modules)
|
||||
{
|
||||
// initialize module control properties
|
||||
module.SecurityAccessLevel = SecurityAccessLevel.Host;
|
||||
module.ControlTitle = "";
|
||||
module.Actions = "";
|
||||
module.UseAdminContainer = false;
|
||||
module.PaneModuleIndex = -1;
|
||||
module.PaneModuleCount = 0;
|
||||
|
||||
return page;
|
||||
}
|
||||
if ((module.PageId == page.PageId || module.ModuleId == moduleid))
|
||||
{
|
||||
var typename = Constants.ErrorModule;
|
||||
|
||||
private (Page Page, List<Module> Modules) ProcessModules(Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype)
|
||||
{
|
||||
var paneindex = new Dictionary<string, int>();
|
||||
foreach (Module module in modules)
|
||||
{
|
||||
// initialize module control properties
|
||||
module.SecurityAccessLevel = SecurityAccessLevel.Host;
|
||||
module.ControlTitle = "";
|
||||
module.Actions = "";
|
||||
module.UseAdminContainer = false;
|
||||
module.PaneModuleIndex = -1;
|
||||
module.PaneModuleCount = 0;
|
||||
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
|
||||
{
|
||||
typename = module.ModuleDefinition.ControlTypeTemplate;
|
||||
|
||||
if ((module.PageId == page.PageId || module.ModuleId == moduleid))
|
||||
{
|
||||
var typename = Constants.ErrorModule;
|
||||
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
|
||||
{
|
||||
typename = module.ModuleDefinition.ControlTypeTemplate;
|
||||
// handle default action
|
||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||
{
|
||||
action = module.ModuleDefinition.DefaultAction;
|
||||
}
|
||||
|
||||
// handle default action
|
||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||
{
|
||||
action = module.ModuleDefinition.DefaultAction;
|
||||
}
|
||||
// check if the module defines custom action routes
|
||||
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
||||
{
|
||||
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(';', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (route.StartsWith(action + "="))
|
||||
{
|
||||
typename = route.Replace(action + "=", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the module defines custom action routes
|
||||
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
||||
{
|
||||
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(';', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (route.StartsWith(action + "="))
|
||||
{
|
||||
typename = route.Replace(action + "=", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// get module resources
|
||||
page.Resources = ManagePageResources(page.Resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName));
|
||||
}
|
||||
|
||||
// ensure component exists and implements IModuleControl
|
||||
module.ModuleType = "";
|
||||
if (Constants.DefaultModuleActions.Contains(action, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
typename = typename.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
Type moduletype = Type.GetType(typename, false, true); // case insensitive
|
||||
if (moduletype != null && moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
|
||||
{
|
||||
module.ModuleType = Utilities.GetFullTypeName(moduletype.AssemblyQualifiedName); // get actual type name
|
||||
}
|
||||
// ensure component exists and implements IModuleControl
|
||||
module.ModuleType = "";
|
||||
if (Constants.DefaultModuleActions.Contains(action, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
typename = typename.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
Type moduletype = Type.GetType(typename, false, true); // case insensitive
|
||||
if (moduletype != null && moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
|
||||
{
|
||||
module.ModuleType = Utilities.GetFullTypeName(moduletype.AssemblyQualifiedName); // get actual type name
|
||||
}
|
||||
|
||||
// get additional metadata from IModuleControl interface
|
||||
if (moduletype != null && module.ModuleType != "")
|
||||
{
|
||||
// retrieve module component resources
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
{
|
||||
// settings components are embedded within a framework settings module
|
||||
moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true);
|
||||
if (moduletype != null)
|
||||
{
|
||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module);
|
||||
}
|
||||
}
|
||||
// get additional metadata from IModuleControl interface
|
||||
if (moduletype != null && module.ModuleType != "")
|
||||
{
|
||||
// retrieve module component resources
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
{
|
||||
// settings components are embedded within a framework settings module
|
||||
moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true);
|
||||
if (moduletype != null)
|
||||
{
|
||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// validate that module's pane exists in current page
|
||||
if (page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
|
||||
{
|
||||
// fallback to default pane if it exists
|
||||
if (page.Panes.FindIndex(item => item.Equals(PaneNames.Default, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
module.Pane = PaneNames.Default;
|
||||
}
|
||||
else // otherwise admin pane (legacy)
|
||||
{
|
||||
module.Pane = PaneNames.Admin;
|
||||
}
|
||||
}
|
||||
// validate that module's pane exists in current page
|
||||
if (page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
|
||||
{
|
||||
// fallback to default pane if it exists
|
||||
if (page.Panes.FindIndex(item => item.Equals(PaneNames.Default, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
module.Pane = PaneNames.Default;
|
||||
}
|
||||
else // otherwise admin pane (legacy)
|
||||
{
|
||||
module.Pane = PaneNames.Admin;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate module position within pane
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
paneindex[module.Pane.ToLower()] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
paneindex.Add(module.Pane.ToLower(), 0);
|
||||
}
|
||||
// calculate module position within pane
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
paneindex[module.Pane.ToLower()] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
paneindex.Add(module.Pane.ToLower(), 0);
|
||||
}
|
||||
|
||||
module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
|
||||
module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
|
||||
|
||||
// container fallback
|
||||
if (string.IsNullOrEmpty(module.ContainerType))
|
||||
{
|
||||
module.ContainerType = defaultcontainertype;
|
||||
}
|
||||
}
|
||||
}
|
||||
// container fallback
|
||||
if (string.IsNullOrEmpty(module.ContainerType))
|
||||
{
|
||||
module.ContainerType = defaultcontainertype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
||||
{
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
|
||||
}
|
||||
}
|
||||
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
||||
{
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (page, modules);
|
||||
}
|
||||
return (page, modules);
|
||||
}
|
||||
|
||||
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level)
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
// ensure resource does not exist already
|
||||
if (pageresources.Find(item => item.Url == resource.Url) == null)
|
||||
{
|
||||
resource.Level = level;
|
||||
pageresources.Add(resource);
|
||||
}
|
||||
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name)
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
if (resource.Level != ResourceLevel.Site)
|
||||
{
|
||||
if (resource.Url.StartsWith("~"))
|
||||
{
|
||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||
}
|
||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||
{
|
||||
resource.Url = alias.BaseUrl + resource.Url;
|
||||
}
|
||||
|
||||
// ensure resource does not exist already
|
||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||
{
|
||||
resource.Level = level;
|
||||
resource.Namespace = name;
|
||||
pageresources.Add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pageresources;
|
||||
|
@ -1,59 +1,186 @@
|
||||
@namespace Oqtane.UI
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject SiteState SiteState
|
||||
|
||||
@DynamicComponent
|
||||
|
||||
@code {
|
||||
[CascadingParameter] PageState PageState { get; set; }
|
||||
[CascadingParameter] PageState PageState { get; set; }
|
||||
|
||||
RenderFragment DynamicComponent { get; set; }
|
||||
RenderFragment DynamicComponent { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
// handle page redirection
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Url))
|
||||
{
|
||||
NavigationManager.NavigateTo(PageState.Page.Url);
|
||||
return;
|
||||
}
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
var themeType = Type.GetType(PageState.Page.ThemeType);
|
||||
builder.OpenComponent(0, themeType);
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
var interop = new Interop(JsRuntime);
|
||||
|
||||
// manage stylesheets for this page
|
||||
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
||||
{
|
||||
var prefix = "app-stylesheet-" + resource.Level.ToString().ToLower();
|
||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||
links.Add(new { id = prefix + "-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", insertbefore = prefix });
|
||||
}
|
||||
if (links.Any())
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
// handle page redirection
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Url))
|
||||
{
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
NavigationManager.NavigateTo(PageState.Page.Url);
|
||||
return;
|
||||
}
|
||||
await interop.RemoveElementsById("app-stylesheet-page-", "", "app-stylesheet-page-" + batch + "-00");
|
||||
await interop.RemoveElementsById("app-stylesheet-module-", "", "app-stylesheet-module-" + batch + "-00");
|
||||
|
||||
// set page title
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Page.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||
}
|
||||
}
|
||||
// set page title
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||
{
|
||||
SiteState.Properties.PageTitle = PageState.Page.Title;
|
||||
}
|
||||
else
|
||||
{
|
||||
SiteState.Properties.PageTitle = PageState.Site.Name + " - " + PageState.Page.Name;
|
||||
}
|
||||
|
||||
// set page head content
|
||||
var headcontent = "";
|
||||
|
||||
// favicon
|
||||
var favicon = "favicon.ico";
|
||||
var favicontype = "x-icon";
|
||||
if (PageState.Site.FaviconFileId != null)
|
||||
{
|
||||
favicon = Utilities.FileUrl(PageState.Alias, PageState.Site.FaviconFileId.Value);
|
||||
favicontype = favicon.Substring(favicon.LastIndexOf(".") + 1);
|
||||
}
|
||||
headcontent += $"<link id=\"app-favicon\" rel=\"shortcut icon\" type=\"image/{favicontype}\" href=\"{favicon}\" />\n";
|
||||
|
||||
// head content
|
||||
AddHeadContent(headcontent, PageState.Site.HeadContent);
|
||||
if (!string.IsNullOrEmpty(PageState.Site.HeadContent))
|
||||
{
|
||||
headcontent = AddHeadContent(headcontent, PageState.Site.HeadContent);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(PageState.Page.HeadContent))
|
||||
{
|
||||
headcontent = AddHeadContent(headcontent, PageState.Page.HeadContent);
|
||||
}
|
||||
SiteState.Properties.HeadContent = headcontent;
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
var themeType = Type.GetType(PageState.Page.ThemeType);
|
||||
builder.OpenComponent(0, themeType);
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
|
||||
private string AddHeadContent(string headcontent, string content)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
// format head content, remove scripts, and filter duplicate elements
|
||||
var elements = (">" + content.Replace("\n", "") + "<").Split("><");
|
||||
foreach (var element in elements)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(element) && !element.Contains("script"))
|
||||
{
|
||||
if (!headcontent.Contains("<" + element + ">"))
|
||||
{
|
||||
headcontent += "<" + element + ">" + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return headcontent;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PageState.Page.HeadContent) && PageState.Page.HeadContent.Contains("<script"))
|
||||
{
|
||||
await InjectScripts(PageState.Page.HeadContent, ResourceLocation.Head);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(PageState.Page.BodyContent) && PageState.Page.BodyContent.Contains("<script"))
|
||||
{
|
||||
await InjectScripts(PageState.Page.BodyContent, ResourceLocation.Body);
|
||||
}
|
||||
}
|
||||
|
||||
// style sheets
|
||||
if (PageState.Page.Resources != null && PageState.Page.Resources.Exists(item => item.ResourceType == ResourceType.Stylesheet))
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
||||
{
|
||||
var prefix = "app-stylesheet-" + resource.Level.ToString().ToLower();
|
||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||
links.Add(new { id = prefix + "-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", insertbefore = prefix });
|
||||
}
|
||||
if (links.Any())
|
||||
{
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
}
|
||||
await interop.RemoveElementsById("app-stylesheet-page-", "", "app-stylesheet-page-" + batch + "-00");
|
||||
await interop.RemoveElementsById("app-stylesheet-module-", "", "app-stylesheet-module-" + batch + "-00");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InjectScripts(string content, ResourceLocation location)
|
||||
{
|
||||
// inject scripts into page dynamically
|
||||
var interop = new Interop(JSRuntime);
|
||||
var scripts = new List<object>();
|
||||
var count = 0;
|
||||
var index = content.IndexOf("<script");
|
||||
while (index >= 0)
|
||||
{
|
||||
var script = content.Substring(index, content.IndexOf("</script>", index) + 9 - index);
|
||||
// get script attributes
|
||||
var attributes = script.Substring(0, script.IndexOf(">")).Replace("\"", "").Split(" ");
|
||||
string id = "";
|
||||
string src = "";
|
||||
string integrity = "";
|
||||
string crossorigin = "";
|
||||
string type = "";
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
if (attribute.Contains("="))
|
||||
{
|
||||
var value = attribute.Split("=");
|
||||
switch (value[0])
|
||||
{
|
||||
case "id":
|
||||
id = value[1];
|
||||
break;
|
||||
case "src":
|
||||
src = value[1];
|
||||
break;
|
||||
case "integrity":
|
||||
integrity = value[1];
|
||||
break;
|
||||
case "crossorigin":
|
||||
crossorigin = value[1];
|
||||
break;
|
||||
case "type":
|
||||
type = value[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// inject script
|
||||
if (!string.IsNullOrEmpty(src))
|
||||
{
|
||||
src = (src.Contains("://")) ? src : PageState.Alias.BaseUrl + src;
|
||||
scripts.Add(new { href = src, bundle = "", integrity = integrity, crossorigin = crossorigin, es6module = (type == "module"), location = location });
|
||||
}
|
||||
else
|
||||
{
|
||||
// inline script must have an id attribute
|
||||
if (id == "")
|
||||
{
|
||||
count += 1;
|
||||
id = $"page{PageState.Page.PageId}-script{count}";
|
||||
}
|
||||
index = script.IndexOf(">") + 1;
|
||||
await interop.IncludeScript(id, "", "", "", "", script.Substring(index, script.IndexOf("</script>") - index), location.ToString().ToLower());
|
||||
}
|
||||
index = content.IndexOf("<script", index + 1);
|
||||
}
|
||||
if (scripts.Any())
|
||||
{
|
||||
await interop.IncludeScripts(scripts.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.3</Version>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>4.0.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -29,7 +29,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MySql.EntityFrameworkCore" Version="6.0.0" />
|
||||
<PackageReference Include="MySql.EntityFrameworkCore" Version="7.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.MySQL</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane MySQL Provider</title>
|
||||
@ -12,15 +12,15 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="bin\net6.0\Oqtane.Database.MySQL.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Oqtane.Database.MySQL.pdb" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Mysql.EntityFrameworkCore.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Mysql.Data.dll" target="lib\net6.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.MySQL.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.MySQL.pdb" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Mysql.EntityFrameworkCore.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Mysql.Data.dll" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.3</Version>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>4.0.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -29,9 +29,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" />
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.5" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.PostgreSQL</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane PostgreSQL Provider</title>
|
||||
@ -12,16 +12,16 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="bin\net6.0\Oqtane.Database.PostgreSQL.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Oqtane.Database.PostgreSQL.pdb" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\EFCore.NamingConventions.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Npgsql.EntityFrameworkCore.PostgreSQL.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Npgsql.dll" target="lib\net6.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.PostgreSQL.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.PostgreSQL.pdb" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\EFCore.NamingConventions.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Npgsql.EntityFrameworkCore.PostgreSQL.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Npgsql.dll" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.3</Version>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>4.0.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -29,7 +29,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.SqlServer</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQL Server Provider</title>
|
||||
@ -12,14 +12,14 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="bin\net6.0\Oqtane.Database.SqlServer.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Oqtane.Database.SqlServer.pdb" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Microsoft.EntityFrameworkCore.SqlServer.dll" target="lib\net6.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.SqlServer.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.SqlServer.pdb" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Microsoft.EntityFrameworkCore.SqlServer.dll" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.3</Version>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>4.0.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -29,7 +29,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.Sqlite</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQLite Provider</title>
|
||||
@ -12,14 +12,14 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="bin\net6.0\Oqtane.Database.Sqlite.dll" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Oqtane.Database.Sqlite.pdb" target="lib\net6.0" />
|
||||
<file src="bin\net6.0\Microsoft.EntityFrameworkCore.Sqlite.dll" target="lib\net6.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.Sqlite.dll" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Oqtane.Database.Sqlite.pdb" target="lib\net7.0" />
|
||||
<file src="bin\net7.0\Microsoft.EntityFrameworkCore.Sqlite.dll" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
6
Oqtane.Maui/Head.razor
Normal file
6
Oqtane.Maui/Head.razor
Normal file
@ -0,0 +1,6 @@
|
||||
<DynamicComponent Type="@ComponentType"></DynamicComponent>
|
||||
|
||||
@code {
|
||||
Type ComponentType = Type.GetType("Oqtane.Head, Oqtane.Client");
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
<BlazorWebView HostPage="wwwroot/index.html">
|
||||
<BlazorWebView.RootComponents>
|
||||
<RootComponent Selector="head::after" ComponentType="{x:Type local:Head}" />
|
||||
<RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
|
||||
</BlazorWebView.RootComponents>
|
||||
</BlazorWebView>
|
||||
|
@ -12,8 +12,8 @@ namespace Oqtane.Maui;
|
||||
public static class MauiProgram
|
||||
{
|
||||
// the API service url
|
||||
static string apiurl = "https://www.dnfprojects.com"; // for testing
|
||||
//static string apiurl = "http://localhost:44357"; // for local development (Oqtane.Server must be already running for MAUI client to connect)
|
||||
//static string apiurl = "https://www.dnfprojects.com"; // for testing
|
||||
static string apiurl = "http://localhost:44357"; // for local development (Oqtane.Server must be already running for MAUI client to connect)
|
||||
|
||||
public static MauiApp CreateMauiApp()
|
||||
{
|
||||
|
@ -1,12 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>
|
||||
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
|
||||
<!-- <TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks> -->
|
||||
<!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
|
||||
<!-- <TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks> -->
|
||||
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
|
||||
<OutputType>Exe</OutputType>
|
||||
<Version>3.4.3</Version>
|
||||
<Version>4.0.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -14,7 +14,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||
@ -31,7 +31,7 @@
|
||||
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
||||
|
||||
<!-- Versions -->
|
||||
<ApplicationDisplayVersion>3.4.3</ApplicationDisplayVersion>
|
||||
<ApplicationDisplayVersion>4.0.0</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>1</ApplicationVersion>
|
||||
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
||||
@ -65,14 +65,21 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.3" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Oqtane.Client" Version="3.4.3" />
|
||||
<PackageReference Include="Oqtane.Shared" Version="3.4.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.5" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Oqtane.Client">
|
||||
<HintPath>..\Oqtane.Server\bin\Debug\net7.0\Oqtane.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Oqtane.Shared">
|
||||
<HintPath>..\Oqtane.Server\bin\Debug\net7.0\Oqtane.Shared.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
15
Oqtane.Maui/Resources/Raw/AboutAssets.txt
Normal file
15
Oqtane.Maui/Resources/Raw/AboutAssets.txt
Normal file
@ -0,0 +1,15 @@
|
||||
Any raw assets you want to be deployed with your application can be placed in
|
||||
this directory (and child directories). Deployment of the asset to your application
|
||||
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
|
||||
|
||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
|
||||
These files will be deployed with you package and will be accessible using Essentials:
|
||||
|
||||
async Task LoadMauiAsset()
|
||||
{
|
||||
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
var contents = reader.ReadToEnd();
|
||||
}
|
@ -9,8 +9,8 @@
|
||||
<script src="js/app.js"></script>
|
||||
<script src="js/loadjs.min.js"></script>
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
<link id="app-stylesheet-page" rel="stylesheet" href="css/empty.css" disabled />
|
||||
<link id="app-stylesheet-module" rel="stylesheet" href="css/empty.css" disabled />
|
||||
<link id="app-stylesheet-page" />
|
||||
<link id="app-stylesheet-module" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Client</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,13 +12,13 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\Oqtane.Client\bin\Release\net6.0\Oqtane.Client.dll" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Client\bin\Release\net6.0\Oqtane.Client.pdb" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Client\bin\Release\net7.0\Oqtane.Client.dll" target="lib\net7.0" />
|
||||
<file src="..\Oqtane.Client\bin\Release\net7.0\Oqtane.Client.pdb" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Framework</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -11,8 +11,8 @@
|
||||
<copyright>.NET Foundation</copyright>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.4.3/Oqtane.Framework.3.4.3.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v4.0.0/Oqtane.Framework.4.0.0.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane framework</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Server</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,13 +12,13 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\Oqtane.Server\bin\Release\net6.0\Oqtane.Server.dll" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Server\bin\Release\net6.0\Oqtane.Server.pdb" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Server\bin\Release\net7.0\Oqtane.Server.dll" target="lib\net7.0" />
|
||||
<file src="..\Oqtane.Server\bin\Release\net7.0\Oqtane.Server.pdb" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Shared</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,13 +12,13 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\Oqtane.Shared\bin\Release\net6.0\Oqtane.Shared.dll" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Shared\bin\Release\net6.0\Oqtane.Shared.pdb" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Shared\bin\Release\net7.0\Oqtane.Shared.dll" target="lib\net7.0" />
|
||||
<file src="..\Oqtane.Shared\bin\Release\net7.0\Oqtane.Shared.pdb" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Updater</id>
|
||||
<version>3.4.3</version>
|
||||
<version>4.0.0</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,12 +12,12 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.0</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\Oqtane.Updater\bin\Release\net6.0\publish\*.*" target="lib\net6.0" />
|
||||
<file src="..\Oqtane.Updater\bin\Release\net7.0\publish\*.*" target="lib\net7.0" />
|
||||
<file src="icon.png" target="" />
|
||||
</files>
|
||||
</package>
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.4.3.Install.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.0.Install.zip" -Force
|
@ -8,14 +8,14 @@ nuget.exe pack Oqtane.Client.nuspec
|
||||
nuget.exe pack Oqtane.Server.nuspec
|
||||
nuget.exe pack Oqtane.Shared.nuspec
|
||||
nuget.exe pack Oqtane.Framework.nuspec
|
||||
del /F/Q/S "..\Oqtane.Server\bin\Release\net6.0\publish" > NUL
|
||||
rmdir /Q/S "..\Oqtane.Server\bin\Release\net6.0\publish"
|
||||
del /F/Q/S "..\Oqtane.Server\bin\Release\net7.0\publish" > NUL
|
||||
rmdir /Q/S "..\Oqtane.Server\bin\Release\net7.0\publish"
|
||||
dotnet publish ..\Oqtane.Server\Oqtane.Server.csproj /p:Configuration=Release
|
||||
del /F/Q/S "..\Oqtane.Server\bin\Release\net6.0\publish\wwwroot\Content" > NUL
|
||||
rmdir /Q/S "..\Oqtane.Server\bin\Release\net6.0\publish\wwwroot\Content"
|
||||
del /F/Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content" > NUL
|
||||
rmdir /Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content"
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
set retain=Oqtane.Modules.Admin.Login,Oqtane.Modules.HtmlText,Templates
|
||||
for /D %%i in ("..\Oqtane.Server\bin\Release\net6.0\publish\wwwroot\Modules\*") do (
|
||||
for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Modules\*") do (
|
||||
set /A found=0
|
||||
for %%j in (%retain%) do (
|
||||
if "%%~nxi" == "%%j" set /A found=1
|
||||
@ -23,18 +23,18 @@ if "%%~nxi" == "%%j" set /A found=1
|
||||
if not !found! == 1 rmdir /Q/S "%%i"
|
||||
)
|
||||
set retain=Oqtane.Themes.BlazorTheme,Oqtane.Themes.OqtaneTheme,Templates
|
||||
for /D %%i in ("..\Oqtane.Server\bin\Release\net6.0\publish\wwwroot\Themes\*") do (
|
||||
for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Themes\*") do (
|
||||
set /A found=0
|
||||
for %%j in (%retain%) do (
|
||||
if "%%~nxi" == "%%j" set /A found=1
|
||||
)
|
||||
if not !found! == 1 rmdir /Q/S "%%i"
|
||||
)
|
||||
del "..\Oqtane.Server\bin\Release\net6.0\publish\appsettings.json"
|
||||
ren "..\Oqtane.Server\bin\Release\net6.0\publish\appsettings.release.json" "appsettings.json"
|
||||
del "..\Oqtane.Server\bin\Release\net7.0\publish\appsettings.json"
|
||||
ren "..\Oqtane.Server\bin\Release\net7.0\publish\appsettings.release.json" "appsettings.json"
|
||||
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\install.ps1"
|
||||
del "..\Oqtane.Server\bin\Release\net6.0\publish\appsettings.json"
|
||||
del "..\Oqtane.Server\bin\Release\net6.0\publish\web.config"
|
||||
del "..\Oqtane.Server\bin\Release\net7.0\publish\appsettings.json"
|
||||
del "..\Oqtane.Server\bin\Release\net7.0\publish\web.config"
|
||||
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\upgrade.ps1"
|
||||
dotnet clean -c Release ..\Oqtane.Updater.sln
|
||||
dotnet build -c Release ..\Oqtane.Updater.sln
|
||||
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.4.3.Upgrade.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.0.Upgrade.zip" -Force
|
@ -33,8 +33,10 @@ namespace Oqtane.Controllers
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly IAliasRepository _aliases;
|
||||
private readonly ILogger<InstallationController> _filelogger;
|
||||
private readonly ITenantManager _tenantManager;
|
||||
private readonly ServerStateManager _serverState;
|
||||
|
||||
public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger<InstallationController> filelogger)
|
||||
public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger<InstallationController> filelogger, ITenantManager tenantManager, ServerStateManager serverState)
|
||||
{
|
||||
_configManager = configManager;
|
||||
_installationManager = installationManager;
|
||||
@ -44,6 +46,8 @@ namespace Oqtane.Controllers
|
||||
_accessor = accessor;
|
||||
_aliases = aliases;
|
||||
_filelogger = filelogger;
|
||||
_tenantManager = tenantManager;
|
||||
_serverState = serverState;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -115,7 +119,9 @@ namespace Oqtane.Controllers
|
||||
|
||||
private List<ClientAssembly> GetAssemblyList()
|
||||
{
|
||||
return _cache.GetOrCreate("assemblieslist", entry =>
|
||||
int siteId = _tenantManager.GetAlias().SiteId;
|
||||
|
||||
return _cache.GetOrCreate($"assemblieslist:{siteId}", entry =>
|
||||
{
|
||||
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
var assemblyList = new List<ClientAssembly>();
|
||||
@ -126,78 +132,43 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
hashfilename = false;
|
||||
}
|
||||
|
||||
// get list of assemblies which should be downloaded to client
|
||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies();
|
||||
var list = assemblies.Select(a => a.GetName().Name).ToList();
|
||||
|
||||
// populate assemblies
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
// get site assemblies which should be downloaded to client
|
||||
var assemblies = _serverState.GetServerState(siteId).Assemblies;
|
||||
|
||||
// populate assembly list
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, list[i] + ".dll"), hashfilename));
|
||||
if (assembly != Constants.ClientId)
|
||||
{
|
||||
var filepath = Path.Combine(binFolder, assembly) + ".dll";
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, assembly + ".dll"), hashfilename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insert satellite assemblies at beginning of list
|
||||
foreach (var culture in _localizationManager.GetInstalledCultures())
|
||||
{
|
||||
var assembliesFolderPath = Path.Combine(binFolder, culture);
|
||||
if (culture == Constants.DefaultCulture)
|
||||
if (culture != Constants.DefaultCulture)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Directory.Exists(assembliesFolderPath))
|
||||
{
|
||||
foreach (var resourceFile in Directory.EnumerateFiles(assembliesFolderPath))
|
||||
var assembliesFolderPath = Path.Combine(binFolder, culture);
|
||||
if (Directory.Exists(assembliesFolderPath))
|
||||
{
|
||||
assemblyList.Insert(0, new ClientAssembly(resourceFile, hashfilename));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist"));
|
||||
}
|
||||
}
|
||||
|
||||
// insert module and theme dependencies at beginning of list
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule))))
|
||||
{
|
||||
var instance = Activator.CreateInstance(type) as IModule;
|
||||
foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
|
||||
{
|
||||
var filepath = Path.Combine(binFolder, name.ToLower().EndsWith(".dll") ? name : name + ".dll");
|
||||
if (System.IO.File.Exists(filepath))
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
if (!assemblyList.Exists(item => item.FilePath == filepath))
|
||||
var filepath = Path.Combine(assembliesFolderPath, assembly) + ".resources.dll";
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
assemblyList.Insert(0, new ClientAssembly(filepath, hashfilename));
|
||||
assemblyList.Insert(0, new ClientAssembly(Path.Combine(assembliesFolderPath, assembly + ".resources.dll"), hashfilename));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"Module {instance.ModuleDefinition.ModuleDefinitionName} Dependency {name}.dll Does Not Exist"));
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))))
|
||||
{
|
||||
var instance = Activator.CreateInstance(type) as ITheme;
|
||||
foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
|
||||
else
|
||||
{
|
||||
var filepath = Path.Combine(binFolder, name.ToLower().EndsWith(".dll") ? name : name + ".dll");
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
if (!assemblyList.Exists(item => item.FilePath == filepath))
|
||||
{
|
||||
assemblyList.Insert(0, new ClientAssembly(filepath, hashfilename));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"Theme {instance.Theme.ThemeName} Dependency {name}.dll Does Not Exist"));
|
||||
}
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -240,21 +211,24 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
if (System.IO.File.Exists(assembly.FilePath))
|
||||
if (Path.GetFileNameWithoutExtension(assembly.FilePath) != Constants.ClientId)
|
||||
{
|
||||
using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read))
|
||||
using (var entrystream = archive.CreateEntry(assembly.HashedName).Open())
|
||||
if (System.IO.File.Exists(assembly.FilePath))
|
||||
{
|
||||
filestream.CopyTo(entrystream);
|
||||
using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read))
|
||||
using (var entrystream = archive.CreateEntry(assembly.HashedName).Open())
|
||||
{
|
||||
filestream.CopyTo(entrystream);
|
||||
}
|
||||
}
|
||||
}
|
||||
var pdb = assembly.FilePath.Replace(".dll", ".pdb");
|
||||
if (System.IO.File.Exists(pdb))
|
||||
{
|
||||
using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read))
|
||||
using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open())
|
||||
var pdb = assembly.FilePath.Replace(".dll", ".pdb");
|
||||
if (System.IO.File.Exists(pdb))
|
||||
{
|
||||
filestream.CopyTo(entrystream);
|
||||
using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read))
|
||||
using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open())
|
||||
{
|
||||
filestream.CopyTo(entrystream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,14 +123,14 @@ namespace Oqtane.Controllers
|
||||
if (moduleDefinition.Template.ToLower().Contains("internal"))
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + ".Module." + moduleDefinition.Name + ", Oqtane.Client";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + ".Module." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + "." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString());
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane";
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + ".Module." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString());
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + ".Module." + moduleDefinition.Name + ", " + moduleDefinition.Owner + ".Module." + moduleDefinition.Name + ".Client.Oqtane";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + ".Module." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + ".Module." + moduleDefinition.Name + ".Server.Oqtane";
|
||||
}
|
||||
|
||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
||||
@ -255,10 +255,10 @@ namespace Oqtane.Controllers
|
||||
_modules.DeleteModule(moduleToRemove.ModuleId);
|
||||
}
|
||||
|
||||
|
||||
// remove module definition
|
||||
_moduleDefinitions.DeleteModuleDefinition(id);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, moduledefinition.SiteId, SyncEventActions.Refresh);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
|
||||
}
|
||||
else
|
||||
@ -331,9 +331,9 @@ namespace Oqtane.Controllers
|
||||
if (moduleDefinition.Version == "local")
|
||||
{
|
||||
text = text.Replace("[FrameworkVersion]", Constants.Version);
|
||||
text = text.Replace("[ClientReference]", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net6.0\\Oqtane.Client.dll</HintPath></Reference>");
|
||||
text = text.Replace("[ServerReference]", $"<Reference Include=\"Oqtane.Server\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net6.0\\Oqtane.Server.dll</HintPath></Reference>");
|
||||
text = text.Replace("[SharedReference]", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net6.0\\Oqtane.Shared.dll</HintPath></Reference>");
|
||||
text = text.Replace("[ClientReference]", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net7.0\\Oqtane.Client.dll</HintPath></Reference>");
|
||||
text = text.Replace("[ServerReference]", $"<Reference Include=\"Oqtane.Server\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net7.0\\Oqtane.Server.dll</HintPath></Reference>");
|
||||
text = text.Replace("[SharedReference]", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net7.0\\Oqtane.Shared.dll</HintPath></Reference>");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -10,6 +10,8 @@ using Oqtane.Enums;
|
||||
using Oqtane.Extensions;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Modules.Admin.Users;
|
||||
using System.IO;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
@ -73,19 +75,11 @@ namespace Oqtane.Controllers
|
||||
return pages;
|
||||
}
|
||||
|
||||
// GET api/<controller>/5?userid=x
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
public Page Get(int id, string userid)
|
||||
public Page Get(int id)
|
||||
{
|
||||
Page page = null;
|
||||
if (string.IsNullOrEmpty(userid))
|
||||
{
|
||||
page = _pages.GetPage(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
page = _pages.GetPage(id, int.Parse(userid));
|
||||
}
|
||||
var page = _pages.GetPage(id);
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
|
||||
@ -95,7 +89,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {PageId} {UserId}", id, userid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {PageId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
@ -180,29 +174,30 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
Page page = null;
|
||||
Page parent = _pages.GetPage(id);
|
||||
if (parent != null && parent.SiteId == _alias.SiteId && parent.IsPersonalizable && _userPermissions.GetUser(User).UserId == int.Parse(userid))
|
||||
User user = _userPermissions.GetUser(User);
|
||||
if (parent != null && parent.SiteId == _alias.SiteId && parent.IsPersonalizable && user.UserId == int.Parse(userid))
|
||||
{
|
||||
page = new Page();
|
||||
page.SiteId = parent.SiteId;
|
||||
page.Name = parent.Name;
|
||||
page.Title = parent.Title;
|
||||
page.Path = parent.Path;
|
||||
page.ParentId = parent.PageId;
|
||||
page.Name = user.Username;
|
||||
page.Path = parent.Path + "/" + page.Name;
|
||||
page.Title = parent.Name + " - " + page.Name;
|
||||
page.Order = 0;
|
||||
page.IsNavigation = false;
|
||||
page.Url = "";
|
||||
page.ThemeType = parent.ThemeType;
|
||||
page.DefaultContainerType = parent.DefaultContainerType;
|
||||
page.Icon = parent.Icon;
|
||||
page.PermissionList = new List<Permission> {
|
||||
page.PermissionList = new List<Permission>()
|
||||
{
|
||||
new Permission(PermissionNames.View, int.Parse(userid), true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, int.Parse(userid), true)
|
||||
};
|
||||
page.IsPersonalizable = false;
|
||||
page.UserId = int.Parse(userid);
|
||||
page = _pages.AddPage(page);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Create);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId, SyncEventActions.Refresh);
|
||||
|
||||
// copy modules
|
||||
List<PageModule> pagemodules = _pageModules.GetPageModules(page.SiteId).ToList();
|
||||
@ -213,8 +208,10 @@ namespace Oqtane.Controllers
|
||||
module.PageId = page.PageId;
|
||||
module.ModuleDefinitionName = pm.Module.ModuleDefinitionName;
|
||||
module.AllPages = false;
|
||||
module.PermissionList = new List<Permission> {
|
||||
module.PermissionList = new List<Permission>()
|
||||
{
|
||||
new Permission(PermissionNames.View, int.Parse(userid), true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, int.Parse(userid), true)
|
||||
};
|
||||
module = _modules.AddModule(module);
|
||||
@ -235,6 +232,9 @@ namespace Oqtane.Controllers
|
||||
|
||||
_pageModules.AddPageModule(pagemodule);
|
||||
}
|
||||
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Create);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId, SyncEventActions.Refresh);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -200,6 +200,8 @@ namespace Oqtane.Controllers
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
case EntityNames.Job:
|
||||
case EntityNames.Theme:
|
||||
if (permissionName == PermissionNames.Edit)
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Host);
|
||||
@ -262,6 +264,8 @@ namespace Oqtane.Controllers
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
case EntityNames.Job:
|
||||
case EntityNames.Theme:
|
||||
filter = !User.IsInRole(RoleNames.Host);
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
|
@ -21,6 +21,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
private readonly ISiteRepository _sites;
|
||||
private readonly IPageRepository _pages;
|
||||
private readonly IThemeRepository _themes;
|
||||
private readonly IModuleRepository _modules;
|
||||
private readonly IPageModuleRepository _pageModules;
|
||||
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
||||
@ -32,10 +33,11 @@ namespace Oqtane.Controllers
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public SiteController(ISiteRepository sites, IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger, IMemoryCache cache)
|
||||
public SiteController(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IModuleRepository modules, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger, IMemoryCache cache)
|
||||
{
|
||||
_sites = sites;
|
||||
_pages = pages;
|
||||
_themes = themes;
|
||||
_modules = modules;
|
||||
_pageModules = pageModules;
|
||||
_moduleDefinitions = moduleDefinitions;
|
||||
@ -144,6 +146,9 @@ namespace Oqtane.Controllers
|
||||
var defaultCulture = CultureInfo.GetCultureInfo(Constants.DefaultCulture);
|
||||
site.Languages.Add(new Language { Code = defaultCulture.Name, Name = defaultCulture.DisplayName, Version = Constants.Version, IsDefault = !site.Languages.Any(l => l.IsDefault) });
|
||||
|
||||
// themes
|
||||
site.Themes = _themes.FilterThemes(_themes.GetThemes().ToList());
|
||||
|
||||
return site;
|
||||
}
|
||||
else
|
||||
|
@ -19,7 +19,6 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public IEnumerable<SiteTemplate> Get()
|
||||
{
|
||||
return _siteTemplates.GetSiteTemplates();
|
||||
|
@ -12,6 +12,8 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Text.Json;
|
||||
using System.Net;
|
||||
using System.Reflection.Metadata;
|
||||
using System;
|
||||
|
||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
||||
|
||||
@ -23,14 +25,20 @@ namespace Oqtane.Controllers
|
||||
private readonly IThemeRepository _themes;
|
||||
private readonly IInstallationManager _installationManager;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly ITenantManager _tenantManager;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public ThemeController(IThemeRepository themes, IInstallationManager installationManager, IWebHostEnvironment environment, ILogManager logger)
|
||||
public ThemeController(IThemeRepository themes, IInstallationManager installationManager, IWebHostEnvironment environment, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_themes = themes;
|
||||
_installationManager = installationManager;
|
||||
_environment = environment;
|
||||
_tenantManager = tenantManager;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
@ -41,6 +49,41 @@ namespace Oqtane.Controllers
|
||||
return _themes.GetThemes();
|
||||
}
|
||||
|
||||
// GET api/<controller>/5?siteid=x
|
||||
[HttpGet("{id}")]
|
||||
public Theme Get(int id, string siteid)
|
||||
{
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _themes.GetTheme(id, SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Theme Get Attempt {ThemeId} {SiteId}", id, siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Put(int id, [FromBody] Theme theme)
|
||||
{
|
||||
if (ModelState.IsValid && theme.SiteId == _alias.SiteId && _themes.GetTheme(theme.ThemeId,theme.SiteId) != null)
|
||||
{
|
||||
_themes.UpdateTheme(theme);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Theme, theme.ThemeId, SyncEventActions.Update);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Theme Updated {Theme}", theme);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Theme Put Attempt {Theme}", theme);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/xxx
|
||||
[HttpDelete("{themename}")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
@ -74,7 +117,9 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
|
||||
// remove theme
|
||||
_themes.DeleteTheme(theme.ThemeName);
|
||||
_themes.DeleteTheme(theme.ThemeId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Theme, theme.ThemeId, SyncEventActions.Delete);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, theme.SiteId, SyncEventActions.Refresh);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Removed For {ThemeName}", theme.ThemeName);
|
||||
}
|
||||
else
|
||||
@ -128,12 +173,12 @@ namespace Oqtane.Controllers
|
||||
if (theme.Template.ToLower().Contains("internal"))
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + "." + theme.Name + ", Oqtane.Client";
|
||||
theme.ThemeName = theme.Owner + ".Theme." + theme.Name + ", Oqtane.Client";
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + "." + theme.Name, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + "." + theme.Name + ", " + theme.Owner + "." + theme.Name + ".Client.Oqtane";
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + ".Theme." + theme.Name, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + ".Theme." + theme.Name + ", " + theme.Owner + ".Theme." + theme.Name + ".Client.Oqtane";
|
||||
}
|
||||
|
||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, theme);
|
||||
@ -180,8 +225,8 @@ namespace Oqtane.Controllers
|
||||
if (theme.Version == "local")
|
||||
{
|
||||
text = text.Replace("[FrameworkVersion]", Constants.Version);
|
||||
text = text.Replace("[ClientReference]", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net6.0\\Oqtane.Client.dll</HintPath></Reference>");
|
||||
text = text.Replace("[SharedReference]", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net6.0\\Oqtane.Shared.dll</HintPath></Reference>");
|
||||
text = text.Replace("[ClientReference]", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net7.0\\Oqtane.Client.dll</HintPath></Reference>");
|
||||
text = text.Replace("[SharedReference]", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net7.0\\Oqtane.Shared.dll</HintPath></Reference>");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddSingleton<ILoggerProvider, FileLoggerProvider>();
|
||||
services.AddSingleton<AutoValidateAntiforgeryTokenFilter>();
|
||||
services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
|
||||
services.AddSingleton<ServerStateManager>();
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -200,9 +201,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
|
||||
// set the cookies to allow HttpClient API calls to be authenticated
|
||||
var httpContextAccessor = s.GetRequiredService<IHttpContextAccessor>();
|
||||
foreach (var cookie in httpContextAccessor.HttpContext.Request.Cookies)
|
||||
if (httpContextAccessor.HttpContext != null)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + cookie.Value);
|
||||
foreach (var cookie in httpContextAccessor.HttpContext.Request.Cookies)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + cookie.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
|
@ -199,10 +199,6 @@ namespace Oqtane.Infrastructure
|
||||
if (result.Success)
|
||||
{
|
||||
result = CreateSite(install);
|
||||
if (result.Success)
|
||||
{
|
||||
result = MigrateSites();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -685,77 +681,6 @@ namespace Oqtane.Infrastructure
|
||||
return result;
|
||||
}
|
||||
|
||||
private Installation MigrateSites()
|
||||
{
|
||||
var result = new Installation { Success = false, Message = string.Empty };
|
||||
|
||||
// get site upgrades
|
||||
Dictionary<string, Type> siteupgrades = new Dictionary<string, Type>();
|
||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
||||
foreach (Assembly assembly in assemblies)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes(typeof(ISiteMigration)))
|
||||
{
|
||||
if (Attribute.IsDefined(type, typeof(SiteMigrationAttribute)))
|
||||
{
|
||||
var attribute = (SiteMigrationAttribute)Attribute.GetCustomAttribute(type, typeof(SiteMigrationAttribute));
|
||||
siteupgrades.Add(attribute.AliasName + " " + attribute.Version, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// execute site upgrades
|
||||
if (siteupgrades.Count > 0)
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
var aliases = scope.ServiceProvider.GetRequiredService<IAliasRepository>();
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||
var logger = scope.ServiceProvider.GetRequiredService<ILogManager>();
|
||||
|
||||
foreach (var alias in aliases.GetAliases().ToList().Where(item => item.IsDefault))
|
||||
{
|
||||
foreach (var upgrade in siteupgrades)
|
||||
{
|
||||
var aliasname = upgrade.Key.Split(' ').First();
|
||||
// in the future this equality condition could use RegEx to allow for more flexible matching
|
||||
if (string.Equals(alias.Name, aliasname, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
tenantManager.SetTenant(alias.TenantId);
|
||||
var site = sites.GetSites().FirstOrDefault(item => item.SiteId == alias.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
var version = upgrade.Key.Split(' ').Last();
|
||||
if (string.IsNullOrEmpty(site.Version) || Version.Parse(version) > Version.Parse(site.Version))
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = ActivatorUtilities.CreateInstance(scope.ServiceProvider, upgrade.Value) as ISiteMigration;
|
||||
if (obj != null)
|
||||
{
|
||||
obj.Up(site, alias);
|
||||
site.Version = version;
|
||||
sites.UpdateSite(site);
|
||||
logger.Log(alias.SiteId, Shared.LogLevel.Information, "Site Migration", LogFunction.Other, "Site Migrated Successfully To Version {version} For {Alias}", version, alias.Name);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Log(alias.SiteId, Shared.LogLevel.Error, "Site Migration", LogFunction.Other, ex, "An Error Occurred Executing Site Migration {Type} For {Alias} And Version {Version}", upgrade.Value, alias.Name, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.Success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private string DenormalizeConnectionString(string connectionString)
|
||||
{
|
||||
var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString();
|
||||
|
@ -0,0 +1,24 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure.EventSubscribers
|
||||
{
|
||||
public class CacheInvalidationEventSubscriber : IEventSubscriber
|
||||
{
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
public CacheInvalidationEventSubscriber(IMemoryCache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public void EntityChanged(SyncEvent syncEvent)
|
||||
{
|
||||
if (syncEvent.EntityName == EntityNames.Site && syncEvent.Action == SyncEventActions.Refresh)
|
||||
{
|
||||
_cache.Remove($"site:{syncEvent.TenantId}:{syncEvent.EntityId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Oqtane.Models;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class CacheInvalidationHostedService : IHostedService
|
||||
{
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
public CacheInvalidationHostedService(ISyncManager syncManager, IMemoryCache cache)
|
||||
{
|
||||
_syncManager = syncManager;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
void EntityChanged(object sender, SyncEvent e)
|
||||
{
|
||||
if (e.EntityName == "Site" && e.Action == SyncEventActions.Refresh)
|
||||
{
|
||||
_cache.Remove($"site:{e.TenantId}:{e.EntityId}");
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_syncManager.EntityChanged += EntityChanged;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
_syncManager.EntityChanged -= EntityChanged;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Oqtane.Models;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class EventDistributorHostedService : IHostedService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ILogger<EventDistributorHostedService> _filelogger;
|
||||
|
||||
public EventDistributorHostedService(IServiceProvider serviceProvider, ISyncManager syncManager, IMemoryCache cache, ILogger<EventDistributorHostedService> filelogger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_syncManager = syncManager;
|
||||
_cache = cache;
|
||||
_filelogger = filelogger;
|
||||
}
|
||||
|
||||
void EntityChanged(object sender, SyncEvent syncEvent)
|
||||
{
|
||||
List<Type> eventSubscribers = _cache.GetOrCreate($"eventsubscribers", entry =>
|
||||
{
|
||||
eventSubscribers = new List<Type>();
|
||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
||||
foreach (Assembly assembly in assemblies)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes(typeof(IEventSubscriber)))
|
||||
{
|
||||
eventSubscribers.Add(type);
|
||||
}
|
||||
}
|
||||
entry.Priority = CacheItemPriority.NeverRemove;
|
||||
return eventSubscribers;
|
||||
});
|
||||
|
||||
foreach (var type in eventSubscribers)
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = ActivatorUtilities.CreateInstance(_serviceProvider, type) as IEventSubscriber;
|
||||
if (obj != null)
|
||||
{
|
||||
obj.EntityChanged(syncEvent);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"Error In EventSubscriber {type.AssemblyQualifiedName} - {ex.Message}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_syncManager.EntityChanged += EntityChanged;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
_syncManager.EntityChanged -= EntityChanged;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public interface IEventSubscriber
|
||||
{
|
||||
void EntityChanged(SyncEvent syncEvent);
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
using Oqtane.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
// this interface is for declaring global resources and is useful for scenarios where you want to declare resources in a single location for the entire application
|
||||
public interface IHostResources
|
||||
{
|
||||
[Obsolete("IHostResources is deprecated. Use module or theme scoped Resources in conjunction with ResourceLevel.Site instead.", false)]
|
||||
List<Resource> Resources { get; } // identifies global resources for an application
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
@ -38,17 +39,23 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
await Task.Yield(); // required so that this method does not block startup
|
||||
|
||||
try
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
ILogger<HostedServiceBase> _filelogger = scope.ServiceProvider.GetRequiredService<ILogger<HostedServiceBase>>();
|
||||
|
||||
try
|
||||
{
|
||||
var jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
var jobLogs = scope.ServiceProvider.GetRequiredService<IJobLogRepository>();
|
||||
var tenantRepository = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
|
||||
// get name of job
|
||||
string jobType = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
|
||||
|
||||
// load jobs and find current job
|
||||
IJobRepository jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
Job job = jobs.GetJobs().Where(item => item.JobType == jobType).FirstOrDefault();
|
||||
if (job != null && job.IsEnabled && !job.IsExecuting)
|
||||
{
|
||||
@ -73,7 +80,9 @@ namespace Oqtane.Infrastructure
|
||||
// determine if the job should be run
|
||||
if (NextExecution <= DateTime.UtcNow && (job.EndDate == null || job.EndDate >= DateTime.UtcNow))
|
||||
{
|
||||
IJobLogRepository jobLogs = scope.ServiceProvider.GetRequiredService<IJobLogRepository>();
|
||||
// update the job to indicate it is running
|
||||
job.IsExecuting = true;
|
||||
jobs.UpdateJob(job);
|
||||
|
||||
// create a job log entry
|
||||
JobLog log = new JobLog();
|
||||
@ -84,16 +93,10 @@ namespace Oqtane.Infrastructure
|
||||
log.Notes = "";
|
||||
log = jobLogs.AddJobLog(log);
|
||||
|
||||
// update the job to indicate it is running
|
||||
job.IsExecuting = true;
|
||||
jobs.UpdateJob(job);
|
||||
|
||||
// execute the job
|
||||
try
|
||||
{
|
||||
var notes = "";
|
||||
var tenantRepository = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
foreach (var tenant in tenantRepository.GetTenants())
|
||||
{
|
||||
// set tenant and execute job
|
||||
@ -133,16 +136,19 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wait 1 minute
|
||||
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
|
||||
catch (Exception ex)
|
||||
{
|
||||
// can occur during the initial installation because the database has not yet been created
|
||||
if (!ex.Message.Contains("No database provider has been configured for this DbContext"))
|
||||
{
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"An Error Occurred Executing Scheduled Job: {Name} - {ex}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// can occur during the initial installation as there is no DBContext
|
||||
}
|
||||
|
||||
// wait 1 minute
|
||||
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime CalculateNextExecution(DateTime nextExecution, Job job)
|
||||
@ -191,9 +197,11 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
ILogger<HostedServiceBase> _filelogger = scope.ServiceProvider.GetRequiredService<ILogger<HostedServiceBase>>();
|
||||
|
||||
try
|
||||
{
|
||||
string jobTypeName = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
|
||||
IJobRepository jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
@ -207,7 +215,7 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
else
|
||||
{
|
||||
// auto registration - job will not run on initial installation but will run after restart
|
||||
// auto registration - job will not run on initial installation due to no DBContext but will run after restart
|
||||
job = new Job { JobType = jobTypeName };
|
||||
|
||||
// optional HostedServiceBase properties
|
||||
@ -233,17 +241,21 @@ namespace Oqtane.Infrastructure
|
||||
jobs.AddJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
_executingTask = ExecuteAsync(_cancellationTokenSource.Token);
|
||||
|
||||
if (_executingTask.IsCompleted)
|
||||
catch (Exception ex)
|
||||
{
|
||||
return _executingTask;
|
||||
// can occur during the initial installation because the database has not yet been created
|
||||
if (!ex.Message.Contains("No database provider has been configured for this DbContext"))
|
||||
{
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"An Error Occurred Starting Scheduled Job: {Name} - {ex}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
||||
_executingTask = ExecuteAsync(_cancellationTokenSource.Token);
|
||||
|
||||
if (_executingTask.IsCompleted)
|
||||
{
|
||||
// can occur during the initial installation because this method is called during startup and the database has not yet been created
|
||||
return _executingTask;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
@ -251,9 +263,11 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
ILogger<HostedServiceBase> _filelogger = scope.ServiceProvider.GetRequiredService<ILogger<HostedServiceBase>>();
|
||||
|
||||
try
|
||||
{
|
||||
string jobTypeName = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
|
||||
IJobRepository jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
@ -266,10 +280,11 @@ namespace Oqtane.Infrastructure
|
||||
jobs.UpdateJob(job);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// error updating the job
|
||||
catch (Exception ex)
|
||||
{
|
||||
// error updating the job
|
||||
_filelogger.LogError(Utilities.LogMessage(this, $"An Error Occurred Stopping Scheduled Job: {Name} - {ex}"));
|
||||
}
|
||||
}
|
||||
|
||||
// stop called without start
|
||||
|
@ -42,119 +42,127 @@ namespace Oqtane.Infrastructure
|
||||
// get site settings
|
||||
List<Setting> sitesettings = settingRepository.GetSettings(EntityNames.Site, site.SiteId).ToList();
|
||||
Dictionary<string, string> settings = GetSettings(sitesettings);
|
||||
if (settings.ContainsKey("SMTPHost") && settings["SMTPHost"] != "" &&
|
||||
settings.ContainsKey("SMTPPort") && settings["SMTPPort"] != "" &&
|
||||
settings.ContainsKey("SMTPSSL") && settings["SMTPSSL"] != "" &&
|
||||
settings.ContainsKey("SMTPSender") && settings["SMTPSender"] != "")
|
||||
if (!settings.ContainsKey("SMTPEnabled") || settings["SMTPEnabled"] == "True")
|
||||
{
|
||||
// construct SMTP Client
|
||||
var client = new SmtpClient()
|
||||
if (settings.ContainsKey("SMTPHost") && settings["SMTPHost"] != "" &&
|
||||
settings.ContainsKey("SMTPPort") && settings["SMTPPort"] != "" &&
|
||||
settings.ContainsKey("SMTPSSL") && settings["SMTPSSL"] != "" &&
|
||||
settings.ContainsKey("SMTPSender") && settings["SMTPSender"] != "")
|
||||
{
|
||||
DeliveryMethod = SmtpDeliveryMethod.Network,
|
||||
UseDefaultCredentials = false,
|
||||
Host = settings["SMTPHost"],
|
||||
Port = int.Parse(settings["SMTPPort"]),
|
||||
EnableSsl = bool.Parse(settings["SMTPSSL"])
|
||||
};
|
||||
if (settings["SMTPUsername"] != "" && settings["SMTPPassword"] != "")
|
||||
{
|
||||
client.Credentials = new NetworkCredential(settings["SMTPUsername"], settings["SMTPPassword"]);
|
||||
}
|
||||
|
||||
// iterate through undelivered notifications
|
||||
int sent = 0;
|
||||
List<Notification> notifications = notificationRepository.GetNotifications(site.SiteId, -1, -1).ToList();
|
||||
foreach (Notification notification in notifications)
|
||||
{
|
||||
// get sender and receiver information from user object if not provided
|
||||
if ((string.IsNullOrEmpty(notification.FromEmail) || string.IsNullOrEmpty(notification.FromDisplayName)) && notification.FromUserId != null)
|
||||
// construct SMTP Client
|
||||
var client = new SmtpClient()
|
||||
{
|
||||
var user = userRepository.GetUser(notification.FromUserId.Value);
|
||||
if (user != null)
|
||||
{
|
||||
notification.FromEmail = (string.IsNullOrEmpty(notification.FromEmail)) ? user.Email : notification.FromEmail;
|
||||
notification.FromDisplayName = (string.IsNullOrEmpty(notification.FromDisplayName)) ? user.DisplayName : notification.FromDisplayName;
|
||||
}
|
||||
}
|
||||
if ((string.IsNullOrEmpty(notification.ToEmail) || string.IsNullOrEmpty(notification.ToDisplayName)) && notification.ToUserId != null)
|
||||
DeliveryMethod = SmtpDeliveryMethod.Network,
|
||||
UseDefaultCredentials = false,
|
||||
Host = settings["SMTPHost"],
|
||||
Port = int.Parse(settings["SMTPPort"]),
|
||||
EnableSsl = bool.Parse(settings["SMTPSSL"])
|
||||
};
|
||||
if (settings["SMTPUsername"] != "" && settings["SMTPPassword"] != "")
|
||||
{
|
||||
var user = userRepository.GetUser(notification.ToUserId.Value);
|
||||
if (user != null)
|
||||
{
|
||||
notification.ToEmail = (string.IsNullOrEmpty(notification.ToEmail)) ? user.Email : notification.ToEmail;
|
||||
notification.ToDisplayName = (string.IsNullOrEmpty(notification.ToDisplayName)) ? user.DisplayName : notification.ToDisplayName;
|
||||
}
|
||||
client.Credentials = new NetworkCredential(settings["SMTPUsername"], settings["SMTPPassword"]);
|
||||
}
|
||||
|
||||
// validate recipient
|
||||
if (string.IsNullOrEmpty(notification.ToEmail))
|
||||
// iterate through undelivered notifications
|
||||
int sent = 0;
|
||||
List<Notification> notifications = notificationRepository.GetNotifications(site.SiteId, -1, -1).ToList();
|
||||
foreach (Notification notification in notifications)
|
||||
{
|
||||
log += "Recipient Missing For NotificationId: " + notification.NotificationId + "<br />";
|
||||
notification.IsDeleted = true;
|
||||
notificationRepository.UpdateNotification(notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
MailMessage mailMessage = new MailMessage();
|
||||
|
||||
// sender
|
||||
if (settings.ContainsKey("SMTPRelay") && settings["SMTPRelay"] == "True" && !string.IsNullOrEmpty(notification.FromEmail))
|
||||
// get sender and receiver information from user object if not provided
|
||||
if ((string.IsNullOrEmpty(notification.FromEmail) || string.IsNullOrEmpty(notification.FromDisplayName)) && notification.FromUserId != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(notification.FromDisplayName))
|
||||
var user = userRepository.GetUser(notification.FromUserId.Value);
|
||||
if (user != null)
|
||||
{
|
||||
mailMessage.From = new MailAddress(notification.FromEmail, notification.FromDisplayName);
|
||||
notification.FromEmail = (string.IsNullOrEmpty(notification.FromEmail)) ? user.Email : notification.FromEmail;
|
||||
notification.FromDisplayName = (string.IsNullOrEmpty(notification.FromDisplayName)) ? user.DisplayName : notification.FromDisplayName;
|
||||
}
|
||||
}
|
||||
if ((string.IsNullOrEmpty(notification.ToEmail) || string.IsNullOrEmpty(notification.ToDisplayName)) && notification.ToUserId != null)
|
||||
{
|
||||
var user = userRepository.GetUser(notification.ToUserId.Value);
|
||||
if (user != null)
|
||||
{
|
||||
notification.ToEmail = (string.IsNullOrEmpty(notification.ToEmail)) ? user.Email : notification.ToEmail;
|
||||
notification.ToDisplayName = (string.IsNullOrEmpty(notification.ToDisplayName)) ? user.DisplayName : notification.ToDisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
// validate recipient
|
||||
if (string.IsNullOrEmpty(notification.ToEmail))
|
||||
{
|
||||
log += "Recipient Missing For NotificationId: " + notification.NotificationId + "<br />";
|
||||
notification.IsDeleted = true;
|
||||
notificationRepository.UpdateNotification(notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
MailMessage mailMessage = new MailMessage();
|
||||
|
||||
// sender
|
||||
if (settings.ContainsKey("SMTPRelay") && settings["SMTPRelay"] == "True" && !string.IsNullOrEmpty(notification.FromEmail))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(notification.FromDisplayName))
|
||||
{
|
||||
mailMessage.From = new MailAddress(notification.FromEmail, notification.FromDisplayName);
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.From = new MailAddress(notification.FromEmail);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.From = new MailAddress(notification.FromEmail);
|
||||
mailMessage.From = new MailAddress(settings["SMTPSender"], (!string.IsNullOrEmpty(notification.FromDisplayName)) ? notification.FromDisplayName : site.Name);
|
||||
}
|
||||
|
||||
// recipient
|
||||
if (!string.IsNullOrEmpty(notification.ToDisplayName))
|
||||
{
|
||||
mailMessage.To.Add(new MailAddress(notification.ToEmail, notification.ToDisplayName));
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.To.Add(new MailAddress(notification.ToEmail));
|
||||
}
|
||||
|
||||
// subject
|
||||
mailMessage.Subject = notification.Subject;
|
||||
|
||||
//body
|
||||
mailMessage.Body = notification.Body;
|
||||
|
||||
// encoding
|
||||
mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;
|
||||
mailMessage.BodyEncoding = System.Text.Encoding.UTF8;
|
||||
mailMessage.IsBodyHtml = true;
|
||||
|
||||
// send mail
|
||||
try
|
||||
{
|
||||
client.Send(mailMessage);
|
||||
sent++;
|
||||
notification.IsDelivered = true;
|
||||
notification.DeliveredOn = DateTime.UtcNow;
|
||||
notificationRepository.UpdateNotification(notification);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// error
|
||||
log += ex.Message + "<br />";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.From = new MailAddress(settings["SMTPSender"], (!string.IsNullOrEmpty(notification.FromDisplayName)) ? notification.FromDisplayName : site.Name);
|
||||
}
|
||||
|
||||
// recipient
|
||||
if (!string.IsNullOrEmpty(notification.ToDisplayName))
|
||||
{
|
||||
mailMessage.To.Add(new MailAddress(notification.ToEmail, notification.ToDisplayName));
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.To.Add(new MailAddress(notification.ToEmail));
|
||||
}
|
||||
|
||||
// subject
|
||||
mailMessage.Subject = notification.Subject;
|
||||
|
||||
//body
|
||||
mailMessage.Body = notification.Body;
|
||||
|
||||
// encoding
|
||||
mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;
|
||||
mailMessage.BodyEncoding = System.Text.Encoding.UTF8;
|
||||
|
||||
// send mail
|
||||
try
|
||||
{
|
||||
client.Send(mailMessage);
|
||||
sent++;
|
||||
notification.IsDelivered = true;
|
||||
notification.DeliveredOn = DateTime.UtcNow;
|
||||
notificationRepository.UpdateNotification(notification);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// error
|
||||
log += ex.Message + "<br />";
|
||||
}
|
||||
}
|
||||
log += "Notifications Delivered: " + sent + "<br />";
|
||||
}
|
||||
else
|
||||
{
|
||||
log += "SMTP Not Configured Properly In Site Settings - Host, Port, SSL, And Sender Are All Required" + "<br />";
|
||||
}
|
||||
log += "Notifications Delivered: " + sent + "<br />";
|
||||
}
|
||||
else
|
||||
{
|
||||
log += "SMTP Not Configured Properly In Site Settings - Host, Port, SSL, And Sender Are All Required" + "<br />";
|
||||
log += "SMTP Disabled In Site Settings" + "<br />";
|
||||
}
|
||||
}
|
||||
|
||||
|
13
Oqtane.Server/Infrastructure/ServerState.cs
Normal file
13
Oqtane.Server/Infrastructure/ServerState.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class ServerState
|
||||
{
|
||||
public int SiteId { get; set; }
|
||||
public List<string> Assemblies { get; set; } = new List<string>();
|
||||
public List<Resource>Scripts { get; set; } = new List<Resource>();
|
||||
public bool IsMigrated { get; set; } = false;
|
||||
}
|
||||
}
|
49
Oqtane.Server/Infrastructure/ServerStateManager.cs
Normal file
49
Oqtane.Server/Infrastructure/ServerStateManager.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
// singleton
|
||||
public class ServerStateManager
|
||||
{
|
||||
private List<ServerState> _serverStates { get; set; }
|
||||
|
||||
public ServerStateManager()
|
||||
{
|
||||
_serverStates = new List<ServerState>();
|
||||
}
|
||||
|
||||
public ServerState GetServerState(int siteId)
|
||||
{
|
||||
var serverState = _serverStates.FirstOrDefault(item => item.SiteId == siteId);
|
||||
if (serverState == null)
|
||||
{
|
||||
serverState = new ServerState();
|
||||
serverState.SiteId = siteId;
|
||||
serverState.Assemblies = new List<string>();
|
||||
serverState.Scripts = new List<Resource>();
|
||||
return serverState;
|
||||
}
|
||||
else
|
||||
{
|
||||
return serverState;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetServerState(int siteId, ServerState serverState)
|
||||
{
|
||||
var serverstate = _serverStates.FirstOrDefault(item => item.SiteId == siteId);
|
||||
if (serverstate == null)
|
||||
{
|
||||
serverState.SiteId = siteId;
|
||||
_serverStates.Add(serverState);
|
||||
}
|
||||
else
|
||||
{
|
||||
serverstate.Assemblies = serverState.Assemblies;
|
||||
serverstate.Scripts = serverState.Scripts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -57,10 +57,10 @@ namespace Oqtane.SiteTemplates
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
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, mobile, and desktop applications on .NET Core. It leverages the 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-glow.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 an open source and cross-platform web UI framework for building single-page applications using .NET and C#. Blazor applications can be hosted in a variety of ways. Blazor Server uses SignalR (WebSockets) to host your application on a web server and provide a responsive and robust development experience. Blazor WebAssembly relies on Wasm, an open web standard that does not require plugins in order for applications to run natively in a web browser. Blazor Hybrid is part of .NET MAUI and uses a Web View to render components natively on mobile and desktop devices. Razor components can be used with all of the hosting models without any modification.</p>" +
|
||||
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">.NET Core</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>"
|
||||
Content = "<p><a href=\"https://www.oqtane.org\" target=\"_new\">Oqtane</a> is an open source <b>CMS</b> and <b>Application Framework</b> that provides advanced functionality for developing web, mobile, and desktop applications on .NET. It leverages Blazor to compose a <b>fully dynamic</b> digital experience. 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 and patterns.</p>" +
|
||||
"<p align=\"center\"><a href=\"https://www.oqtane.org\" target=\"_new\"><img class=\"img-fluid\" src=\"oqtane-glow.png\"></a></p><p align=\"center\"><a class=\"btn btn-primary\" href=\"https://www.oqtane.org\" 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 an open source and cross-platform web UI framework for building single-page applications using .NET and C#. Blazor applications can be hosted in a variety of ways. Blazor Server uses SignalR (WebSockets) to host your application on a web server and provide a responsive and robust development experience. Blazor WebAssembly relies on Wasm, an open web standard that does not require plugins in order for applications to run natively in a web browser. Blazor Hybrid is part of .NET MAUI and uses a Web View to render components natively on mobile and desktop devices. Razor components can be shared across all of the hosting models without any modification.</p>" +
|
||||
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">ASP.NET</a>, the popular cross platform development framework from Microsoft that provides powerful tools and libraries for building modern software applications.</p>"
|
||||
},
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "MIT License", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
@ -141,7 +141,7 @@ namespace Oqtane.SiteTemplates
|
||||
Path = "develop",
|
||||
Icon = "oi oi-wrench",
|
||||
IsNavigation = true,
|
||||
IsPersonalizable = true,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
|
@ -192,7 +192,7 @@ namespace Oqtane.Infrastructure
|
||||
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||
foreach (Site site in sites.GetSites().ToList())
|
||||
{
|
||||
sites.CreatePages(site, pageTemplates);
|
||||
sites.CreatePages(site, pageTemplates, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
if (!pages.GetPages(site.SiteId).ToList().Where(item => item.Path == "404").Any())
|
||||
{
|
||||
sites.CreatePages(site, pageTemplates);
|
||||
sites.CreatePages(site, pageTemplates, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
|
||||
namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public class ThemeEntityBuilder : AuditableBaseEntityBuilder<ThemeEntityBuilder>
|
||||
{
|
||||
private const string _entityTableName = "Theme";
|
||||
private readonly PrimaryKey<ThemeEntityBuilder> _primaryKey = new("PK_Theme", x => x.ThemeId);
|
||||
|
||||
public ThemeEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
}
|
||||
|
||||
protected override ThemeEntityBuilder BuildTable(ColumnsBuilder table)
|
||||
{
|
||||
ThemeId = AddAutoIncrementColumn(table, "ThemeId");
|
||||
ThemeName = AddStringColumn(table, "ThemeName", 200);
|
||||
|
||||
AddAuditableColumns(table);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OperationBuilder<AddColumnOperation> ThemeId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> ThemeName { get; private set; }
|
||||
}
|
||||
}
|
28
Oqtane.Server/Migrations/Master/04000001_AddThemeTable.cs
Normal file
28
Oqtane.Server/Migrations/Master/04000001_AddThemeTable.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.04.00.00.01")]
|
||||
public class AddThemeTable : MultiDatabaseMigration
|
||||
{
|
||||
public AddThemeTable(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var themeEntityBuilder = new ThemeEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
themeEntityBuilder.Create();
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
}
|
28
Oqtane.Server/Migrations/Master/04000002_AddThemeName.cs
Normal file
28
Oqtane.Server/Migrations/Master/04000002_AddThemeName.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.04.00.00.02")]
|
||||
public class AddThemeName : MultiDatabaseMigration
|
||||
{
|
||||
public AddThemeName(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var themeEntityBuilder = new ThemeEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
themeEntityBuilder.AddStringColumn("Name", 200, true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
}
|
35
Oqtane.Server/Migrations/Tenant/04000001_AddHeadContent.cs
Normal file
35
Oqtane.Server/Migrations/Tenant/04000001_AddHeadContent.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
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.04.00.00.01")]
|
||||
public class AddHeaderContent : MultiDatabaseMigration
|
||||
{
|
||||
public AddHeaderContent(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
siteEntityBuilder.AddStringColumn("HeadContent", 4000, true);
|
||||
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.AddStringColumn("HeadContent", 4000, true);
|
||||
|
||||
pageEntityBuilder.UpdateColumn("HeadContent", "Meta");
|
||||
pageEntityBuilder.DropColumn("Meta");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user