ability to specify if a theme is enabled for a site
This commit is contained in:
parent
666f9c2db9
commit
98c2f012ee
|
@ -308,7 +308,7 @@
|
||||||
{
|
{
|
||||||
moduledefinition.Categories = _categories;
|
moduledefinition.Categories = _categories;
|
||||||
}
|
}
|
||||||
moduledefinition.IsEnabled = (_isenabled == null ? true : Boolean.Parse(_isenabled));
|
moduledefinition.IsEnabled = (_isenabled == null ? true : bool.Parse(_isenabled));
|
||||||
moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
|
moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
|
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
|
||||||
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
|
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
|
||||||
|
|
|
@ -103,7 +103,6 @@
|
||||||
|
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private List<Theme> _themes;
|
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _title;
|
private string _title;
|
||||||
private string _containerType;
|
private string _containerType;
|
||||||
|
@ -124,11 +123,10 @@
|
||||||
private string modifiedby;
|
private string modifiedby;
|
||||||
private DateTime modifiedon;
|
private DateTime modifiedon;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
_title = ModuleState.Title;
|
_title = ModuleState.Title;
|
||||||
_themes = await ThemeService.GetThemesAsync();
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||||
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
|
|
||||||
_containerType = ModuleState.ContainerType;
|
_containerType = ModuleState.ContainerType;
|
||||||
_allPages = ModuleState.AllPages.ToString();
|
_allPages = ModuleState.AllPages.ToString();
|
||||||
_permissions = ModuleState.PermissionList;
|
_permissions = ModuleState.PermissionList;
|
||||||
|
@ -173,7 +171,7 @@
|
||||||
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
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))
|
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
||||||
{
|
{
|
||||||
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<TabStrip Refresh="@_refresh">
|
<TabStrip Refresh="@_refresh">
|
||||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
<TabPanel Name="Settings" ResourceKey="Settings">
|
||||||
@if (_themeList != null)
|
@if (PageState.Site.Themes != null)
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
|
@ -175,7 +175,6 @@
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
private List<Theme> _themeList;
|
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _name;
|
private string _name;
|
||||||
|
@ -207,10 +206,9 @@
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themeList = await ThemeService.GetThemesAsync();
|
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||||
_themes = ThemeService.GetThemeControls(_themeList);
|
|
||||||
_themetype = PageState.Site.DefaultThemeType;
|
_themetype = PageState.Site.DefaultThemeType;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = PageState.Site.DefaultContainerType;
|
_containertype = PageState.Site.DefaultContainerType;
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
|
@ -262,7 +260,7 @@
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = "-";
|
_containertype = "-";
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
@ -277,7 +275,7 @@
|
||||||
private void ThemeSettings()
|
private void ThemeSettings()
|
||||||
{
|
{
|
||||||
_themeSettingsType = null;
|
_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))
|
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
||||||
{
|
{
|
||||||
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<TabStrip Refresh="@_refresh">
|
<TabStrip Refresh="@_refresh">
|
||||||
<TabPanel Name="Settings" ResourceKey="Settings" Heading=@Localizer["Settings.Heading"]>
|
<TabPanel Name="Settings" ResourceKey="Settings" Heading=@Localizer["Settings.Heading"]>
|
||||||
@if (_themeList != null)
|
@if (PageState.Site.Themes != null)
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
|
@ -210,7 +210,6 @@
|
||||||
|
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private List<Theme> _themeList;
|
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private int _pageId;
|
private int _pageId;
|
||||||
|
@ -251,8 +250,7 @@
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||||
_themeList = await ThemeService.GetThemesAsync();
|
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||||
_themes = ThemeService.GetThemeControls(_themeList);
|
|
||||||
|
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||||
|
@ -294,7 +292,7 @@
|
||||||
{
|
{
|
||||||
_themetype = PageState.Site.DefaultThemeType;
|
_themetype = PageState.Site.DefaultThemeType;
|
||||||
}
|
}
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = page.DefaultContainerType;
|
_containertype = page.DefaultContainerType;
|
||||||
if (string.IsNullOrEmpty(_containertype))
|
if (string.IsNullOrEmpty(_containertype))
|
||||||
{
|
{
|
||||||
|
@ -396,7 +394,7 @@
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = "-";
|
_containertype = "-";
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
@ -413,7 +411,7 @@
|
||||||
_themeSettingsType = null;
|
_themeSettingsType = null;
|
||||||
if (PageState.QueryString.ContainsKey("cp")) // can only be displayed if invoked from Control Panel
|
if (PageState.QueryString.ContainsKey("cp")) // can only be displayed if invoked from Control Panel
|
||||||
{
|
{
|
||||||
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))
|
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
||||||
{
|
{
|
||||||
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
||||||
|
|
|
@ -330,7 +330,6 @@
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private List<Theme> _themeList;
|
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
|
@ -383,7 +382,6 @@
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themeList = await ThemeService.GetThemesAsync();
|
|
||||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||||
if (site != null)
|
if (site != null)
|
||||||
{
|
{
|
||||||
|
@ -405,9 +403,9 @@
|
||||||
{
|
{
|
||||||
_faviconfileid = site.FaviconFileId.Value;
|
_faviconfileid = site.FaviconFileId.Value;
|
||||||
}
|
}
|
||||||
_themes = ThemeService.GetThemeControls(_themeList);
|
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
|
|
||||||
|
@ -484,7 +482,7 @@
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
if (_themetype != "-")
|
if (_themetype != "-")
|
||||||
{
|
{
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
161
Oqtane.Client/Modules/Admin/Themes/Edit.razor
Normal file
161
Oqtane.Client/Modules/Admin/Themes/Edit.razor
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
@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" disabled />
|
||||||
|
</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.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 style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
<th>@SharedLocalizer["Version"]</th>
|
<th>@SharedLocalizer["Version"]</th>
|
||||||
|
<th>@Localizer["Enabled"]</th>
|
||||||
<th>@SharedLocalizer["Expires"]</th>
|
<th>@SharedLocalizer["Expires"]</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<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>
|
<td>
|
||||||
@if (context.AssemblyName != Constants.ClientId)
|
@if (context.AssemblyName != Constants.ClientId)
|
||||||
{
|
{
|
||||||
|
@ -36,6 +37,16 @@ else
|
||||||
</td>
|
</td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.Version</td>
|
<td>@context.Version</td>
|
||||||
|
<td>
|
||||||
|
@if (context.IsEnabled)
|
||||||
|
{
|
||||||
|
<span>@SharedLocalizer["Yes"]</span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span>@SharedLocalizer["No"]</span>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@((MarkupString)PurchaseLink(context.PackageName))
|
@((MarkupString)PurchaseLink(context.PackageName))
|
||||||
</td>
|
</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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -168,4 +168,13 @@
|
||||||
<data name="PackageName.Text" xml:space="preserve">
|
<data name="PackageName.Text" xml:space="preserve">
|
||||||
<value>Package Name:</value>
|
<value>Package Name:</value>
|
||||||
</data>
|
</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>
|
</root>
|
|
@ -144,4 +144,7 @@
|
||||||
<data name="ViewTheme.Text" xml:space="preserve">
|
<data name="ViewTheme.Text" xml:space="preserve">
|
||||||
<value>View</value>
|
<value>View</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Enabled" xml:space="preserve">
|
||||||
|
<value>Enabled?</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -16,6 +16,14 @@ namespace Oqtane.Services
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<Theme>> GetThemesAsync();
|
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>
|
/// <summary>
|
||||||
/// Returns a list of <see cref="ThemeControl"/>s from the given themes
|
/// Returns a list of <see cref="ThemeControl"/>s from the given themes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -39,6 +47,13 @@ namespace Oqtane.Services
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates a existing theem
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="theme"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task UpdateThemeAsync(Theme theme);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes a theme
|
/// Deletes a theme
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -20,6 +20,10 @@ namespace Oqtane.Services
|
||||||
List<Theme> themes = await GetJsonAsync<List<Theme>>(ApiUrl);
|
List<Theme> themes = await GetJsonAsync<List<Theme>>(ApiUrl);
|
||||||
return themes.OrderBy(item => item.Name).ToList();
|
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 List<ThemeControl> GetThemeControls(List<Theme> themes)
|
public List<ThemeControl> GetThemeControls(List<Theme> themes)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +42,11 @@ namespace Oqtane.Services
|
||||||
.SelectMany(item => item.Containers).ToList();
|
.SelectMany(item => item.Containers).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateThemeAsync(Theme theme)
|
||||||
|
{
|
||||||
|
await PutJsonAsync($"{ApiUrl}/{theme.ThemeId}", theme);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteThemeAsync(string themeName)
|
public async Task DeleteThemeAsync(string themeName)
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{ApiUrl}/{themeName}");
|
await DeleteAsync($"{ApiUrl}/{themeName}");
|
||||||
|
|
|
@ -256,7 +256,7 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove module definition
|
// remove module definition
|
||||||
_moduleDefinitions.DeleteModuleDefinition(id, siteid);
|
_moduleDefinitions.DeleteModuleDefinition(id);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ using Oqtane.Infrastructure;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System;
|
||||||
|
|
||||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
||||||
|
|
||||||
|
@ -23,14 +25,20 @@ namespace Oqtane.Controllers
|
||||||
private readonly IThemeRepository _themes;
|
private readonly IThemeRepository _themes;
|
||||||
private readonly IInstallationManager _installationManager;
|
private readonly IInstallationManager _installationManager;
|
||||||
private readonly IWebHostEnvironment _environment;
|
private readonly IWebHostEnvironment _environment;
|
||||||
|
private readonly ITenantManager _tenantManager;
|
||||||
|
private readonly ISyncManager _syncManager;
|
||||||
private readonly ILogManager _logger;
|
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;
|
_themes = themes;
|
||||||
_installationManager = installationManager;
|
_installationManager = installationManager;
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
|
_tenantManager = tenantManager;
|
||||||
|
_syncManager = syncManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_alias = tenantManager.GetAlias();
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/<controller>
|
// GET: api/<controller>
|
||||||
|
@ -41,6 +49,41 @@ namespace Oqtane.Controllers
|
||||||
return _themes.GetThemes();
|
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
|
// DELETE api/<controller>/xxx
|
||||||
[HttpDelete("{themename}")]
|
[HttpDelete("{themename}")]
|
||||||
[Authorize(Roles = RoleNames.Host)]
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
@ -74,7 +117,7 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove theme
|
// remove theme
|
||||||
_themes.DeleteTheme(theme.ThemeName);
|
//_themes.DeleteTheme(theme.ThemeName);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Removed For {ThemeName}", theme.ThemeName);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Removed For {ThemeName}", theme.ThemeName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,6 +68,7 @@ namespace Oqtane.Repository
|
||||||
public virtual DbSet<Job> Job { get; set; }
|
public virtual DbSet<Job> Job { get; set; }
|
||||||
public virtual DbSet<JobLog> JobLog { get; set; }
|
public virtual DbSet<JobLog> JobLog { get; set; }
|
||||||
public virtual DbSet<Setting> Setting { get; set; }
|
public virtual DbSet<Setting> Setting { get; set; }
|
||||||
|
public virtual DbSet<Theme> Theme { get; set; }
|
||||||
|
|
||||||
public override int SaveChanges()
|
public override int SaveChanges()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Oqtane.Repository
|
||||||
IEnumerable<ModuleDefinition> GetModuleDefinitions(int siteId);
|
IEnumerable<ModuleDefinition> GetModuleDefinitions(int siteId);
|
||||||
ModuleDefinition GetModuleDefinition(int moduleDefinitionId, int siteId);
|
ModuleDefinition GetModuleDefinition(int moduleDefinitionId, int siteId);
|
||||||
void UpdateModuleDefinition(ModuleDefinition moduleDefinition);
|
void UpdateModuleDefinition(ModuleDefinition moduleDefinition);
|
||||||
void DeleteModuleDefinition(int moduleDefinitionId, int siteId);
|
void DeleteModuleDefinition(int moduleDefinitionId);
|
||||||
ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition);
|
ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ namespace Oqtane.Repository
|
||||||
public interface IThemeRepository
|
public interface IThemeRepository
|
||||||
{
|
{
|
||||||
IEnumerable<Theme> GetThemes();
|
IEnumerable<Theme> GetThemes();
|
||||||
|
Theme GetTheme(int themeId, int siteId);
|
||||||
|
void UpdateTheme(Theme theme);
|
||||||
|
void DeleteTheme(int themeId);
|
||||||
List<Theme> FilterThemes(List<Theme> themes);
|
List<Theme> FilterThemes(List<Theme> themes);
|
||||||
void DeleteTheme(string ThemeName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace Oqtane.Repository
|
||||||
_cache.Remove($"moduledefinitions:{_tenants.GetAlias().SiteKey}");
|
_cache.Remove($"moduledefinitions:{_tenants.GetAlias().SiteKey}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteModuleDefinition(int moduleDefinitionId,int siteId)
|
public void DeleteModuleDefinition(int moduleDefinitionId)
|
||||||
{
|
{
|
||||||
ModuleDefinition moduleDefinition = _db.ModuleDefinition.Find(moduleDefinitionId);
|
ModuleDefinition moduleDefinition = _db.ModuleDefinition.Find(moduleDefinitionId);
|
||||||
_settings.DeleteSettings(EntityNames.ModuleDefinition, moduleDefinitionId);
|
_settings.DeleteSettings(EntityNames.ModuleDefinition, moduleDefinitionId);
|
||||||
|
@ -126,48 +126,48 @@ namespace Oqtane.Repository
|
||||||
private List<ModuleDefinition> ProcessModuleDefinitions(int siteId)
|
private List<ModuleDefinition> ProcessModuleDefinitions(int siteId)
|
||||||
{
|
{
|
||||||
// get module assemblies
|
// get module assemblies
|
||||||
List<ModuleDefinition> moduleDefinitions = LoadModuleDefinitionsFromAssemblies();
|
List<ModuleDefinition> ModuleDefinitions = LoadModuleDefinitionsFromAssemblies();
|
||||||
|
|
||||||
// get module definitions in database
|
// get module definitions in database
|
||||||
List<ModuleDefinition> moduledefs = _db.ModuleDefinition.ToList();
|
List<ModuleDefinition> moduledefinitions = _db.ModuleDefinition.ToList();
|
||||||
|
|
||||||
// sync module assemblies with database
|
// sync module assemblies with database
|
||||||
foreach (ModuleDefinition moduledefinition in moduleDefinitions)
|
foreach (ModuleDefinition ModuleDefinition in ModuleDefinitions)
|
||||||
{
|
{
|
||||||
ModuleDefinition moduledef = moduledefs.Where(item => item.ModuleDefinitionName == moduledefinition.ModuleDefinitionName).FirstOrDefault();
|
ModuleDefinition moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionName == ModuleDefinition.ModuleDefinitionName).FirstOrDefault();
|
||||||
if (moduledef == null)
|
if (moduledefinition == null)
|
||||||
{
|
{
|
||||||
// new module definition
|
// new module definition
|
||||||
moduledef = new ModuleDefinition { ModuleDefinitionName = moduledefinition.ModuleDefinitionName };
|
moduledefinition = new ModuleDefinition { ModuleDefinitionName = ModuleDefinition.ModuleDefinitionName };
|
||||||
_db.ModuleDefinition.Add(moduledef);
|
_db.ModuleDefinition.Add(moduledefinition);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
moduledefinition.Version = "";
|
ModuleDefinition.Version = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// override user customizable property values
|
// override user customizable property values
|
||||||
moduledefinition.Name = (!string.IsNullOrEmpty(moduledef.Name)) ? moduledef.Name : moduledefinition.Name;
|
ModuleDefinition.Name = (!string.IsNullOrEmpty(moduledefinition.Name)) ? moduledefinition.Name : ModuleDefinition.Name;
|
||||||
moduledefinition.Description = (!string.IsNullOrEmpty(moduledef.Description)) ? moduledef.Description : moduledefinition.Description;
|
ModuleDefinition.Description = (!string.IsNullOrEmpty(moduledefinition.Description)) ? moduledefinition.Description : ModuleDefinition.Description;
|
||||||
moduledefinition.Categories = (!string.IsNullOrEmpty(moduledef.Categories)) ? moduledef.Categories : moduledefinition.Categories;
|
ModuleDefinition.Categories = (!string.IsNullOrEmpty(moduledefinition.Categories)) ? moduledefinition.Categories : ModuleDefinition.Categories;
|
||||||
// manage releaseversions in cases where it was not provided or is lower than the module version
|
// manage releaseversions in cases where it was not provided or is lower than the module version
|
||||||
if (string.IsNullOrEmpty(moduledefinition.ReleaseVersions) || Version.Parse(moduledefinition.Version).CompareTo(Version.Parse(moduledefinition.ReleaseVersions.Split(',').Last())) > 0)
|
if (string.IsNullOrEmpty(ModuleDefinition.ReleaseVersions) || Version.Parse(ModuleDefinition.Version).CompareTo(Version.Parse(ModuleDefinition.ReleaseVersions.Split(',').Last())) > 0)
|
||||||
{
|
{
|
||||||
moduledefinition.ReleaseVersions = moduledefinition.Version;
|
ModuleDefinition.ReleaseVersions = ModuleDefinition.Version;
|
||||||
}
|
}
|
||||||
moduledefinition.Version = moduledef.Version;
|
ModuleDefinition.Version = moduledefinition.Version;
|
||||||
// remove module definition from list as it is already synced
|
// remove module definition from list as it is already synced
|
||||||
moduledefs.Remove(moduledef);
|
moduledefinitions.Remove(moduledefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
moduledefinition.ModuleDefinitionId = moduledef.ModuleDefinitionId;
|
ModuleDefinition.ModuleDefinitionId = moduledefinition.ModuleDefinitionId;
|
||||||
moduledefinition.CreatedBy = moduledef.CreatedBy;
|
ModuleDefinition.CreatedBy = moduledefinition.CreatedBy;
|
||||||
moduledefinition.CreatedOn = moduledef.CreatedOn;
|
ModuleDefinition.CreatedOn = moduledefinition.CreatedOn;
|
||||||
moduledefinition.ModifiedBy = moduledef.ModifiedBy;
|
ModuleDefinition.ModifiedBy = moduledefinition.ModifiedBy;
|
||||||
moduledefinition.ModifiedOn = moduledef.ModifiedOn;
|
ModuleDefinition.ModifiedOn = moduledefinition.ModifiedOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// any remaining module definitions are orphans
|
// any remaining module definitions are orphans
|
||||||
foreach (ModuleDefinition moduledefinition in moduledefs)
|
foreach (ModuleDefinition moduledefinition in moduledefinitions)
|
||||||
{
|
{
|
||||||
_db.ModuleDefinition.Remove(moduledefinition); // delete
|
_db.ModuleDefinition.Remove(moduledefinition); // delete
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
|
@ -181,8 +181,8 @@ namespace Oqtane.Repository
|
||||||
// get settings for site
|
// get settings for site
|
||||||
var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList();
|
var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList();
|
||||||
|
|
||||||
// populate module definition permissions
|
// populate module definition site settings and permissions
|
||||||
foreach (ModuleDefinition moduledefinition in moduleDefinitions)
|
foreach (ModuleDefinition moduledefinition in ModuleDefinitions)
|
||||||
{
|
{
|
||||||
moduledefinition.SiteId = siteId;
|
moduledefinition.SiteId = siteId;
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ namespace Oqtane.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up any orphaned permissions
|
// clean up any orphaned permissions
|
||||||
var ids = new HashSet<int>(moduleDefinitions.Select(item => item.ModuleDefinitionId));
|
var ids = new HashSet<int>(ModuleDefinitions.Select(item => item.ModuleDefinitionId));
|
||||||
foreach (var permission in permissions.Where(item => !ids.Contains(item.EntityId)))
|
foreach (var permission in permissions.Where(item => !ids.Contains(item.EntityId)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -232,7 +232,7 @@ namespace Oqtane.Repository
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return moduleDefinitions;
|
return ModuleDefinitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ModuleDefinition> LoadModuleDefinitionsFromAssemblies()
|
private List<ModuleDefinition> LoadModuleDefinitionsFromAssemblies()
|
||||||
|
|
|
@ -4,39 +4,168 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Security;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.Themes;
|
using Oqtane.Themes;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class ThemeRepository : IThemeRepository
|
public class ThemeRepository : IThemeRepository
|
||||||
{
|
{
|
||||||
|
private MasterDBContext _db;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly ITenantManager _tenants;
|
||||||
|
private readonly ISettingRepository _settings;
|
||||||
|
private readonly string settingprefix = "SiteEnabled:";
|
||||||
|
|
||||||
public ThemeRepository(IMemoryCache cache)
|
public ThemeRepository(MasterDBContext context, IMemoryCache cache, ITenantManager tenants, ISettingRepository settings)
|
||||||
{
|
{
|
||||||
|
_db = context;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_tenants = tenants;
|
||||||
|
_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Theme> GetThemes()
|
public IEnumerable<Theme> GetThemes()
|
||||||
{
|
{
|
||||||
return LoadThemes();
|
// for consistency siteid should be passed in as parameter, but this would require breaking change
|
||||||
|
return LoadThemes(_tenants.GetAlias().SiteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Theme> LoadThemes()
|
public Theme GetTheme(int themeId, int siteId)
|
||||||
{
|
{
|
||||||
// get module definitions
|
List<Theme> themes = LoadThemes(siteId);
|
||||||
List<Theme> themes = _cache.GetOrCreate("themes", entry =>
|
return themes.Find(item => item.ThemeId == themeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTheme(Theme theme)
|
||||||
|
{
|
||||||
|
_db.Entry(theme).State = EntityState.Modified;
|
||||||
|
_db.SaveChanges();
|
||||||
|
|
||||||
|
var settingname = $"{settingprefix}{_tenants.GetAlias().SiteKey}";
|
||||||
|
var setting = _settings.GetSetting(EntityNames.Theme, theme.ThemeId, settingname);
|
||||||
|
if (setting == null)
|
||||||
|
{
|
||||||
|
_settings.AddSetting(new Setting { EntityName = EntityNames.Theme, EntityId = theme.ThemeId, SettingName = settingname, SettingValue = theme.IsEnabled.ToString(), IsPrivate = true });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setting.SettingValue = theme.IsEnabled.ToString();
|
||||||
|
_settings.UpdateSetting(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Remove($"themes:{_tenants.GetAlias().SiteKey}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteTheme(int themeId)
|
||||||
|
{
|
||||||
|
Theme theme = _db.Theme.Find(themeId);
|
||||||
|
_settings.DeleteSettings(EntityNames.Theme, themeId);
|
||||||
|
_db.Theme.Remove(theme);
|
||||||
|
_db.SaveChanges();
|
||||||
|
_cache.Remove($"themes:{_tenants.GetAlias().SiteKey}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Theme> FilterThemes(List<Theme> themes)
|
||||||
|
{
|
||||||
|
var Themes = new List<Theme>();
|
||||||
|
|
||||||
|
foreach (Theme theme in themes.Where(item => item.IsEnabled))
|
||||||
|
{
|
||||||
|
var Theme = new Theme();
|
||||||
|
Theme.ThemeName = theme.ThemeName;
|
||||||
|
Theme.Name = theme.Name;
|
||||||
|
Theme.Resources = theme.Resources;
|
||||||
|
Theme.Themes = theme.Themes;
|
||||||
|
Theme.Containers = theme.Containers;
|
||||||
|
Themes.Add(Theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Theme> LoadThemes(int siteId)
|
||||||
|
{
|
||||||
|
// get themes
|
||||||
|
List<Theme> themes = _cache.GetOrCreate($"themes:{_tenants.GetAlias().SiteKey}", entry =>
|
||||||
{
|
{
|
||||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||||
return LoadThemesFromAssemblies();
|
return ProcessThemes(siteId);
|
||||||
});
|
});
|
||||||
|
|
||||||
return themes;
|
return themes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Theme> ProcessThemes(int siteId)
|
||||||
|
{
|
||||||
|
// get themes
|
||||||
|
List<Theme> Themes = LoadThemesFromAssemblies();
|
||||||
|
|
||||||
|
// get themes in database
|
||||||
|
List<Theme> themes = _db.Theme.ToList();
|
||||||
|
|
||||||
|
// sync theme assemblies with database
|
||||||
|
foreach (Theme Theme in Themes)
|
||||||
|
{
|
||||||
|
Theme theme = themes.Where(item => item.ThemeName == Theme.ThemeName).FirstOrDefault();
|
||||||
|
if (theme == null)
|
||||||
|
{
|
||||||
|
// new theme
|
||||||
|
theme = new Theme { ThemeName = Theme.ThemeName };
|
||||||
|
_db.Theme.Add(theme);
|
||||||
|
_db.SaveChanges();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// remove theme from list as it is already synced
|
||||||
|
themes.Remove(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
Theme.ThemeId = theme.ThemeId;
|
||||||
|
Theme.CreatedBy = theme.CreatedBy;
|
||||||
|
Theme.CreatedOn = theme.CreatedOn;
|
||||||
|
Theme.ModifiedBy = theme.ModifiedBy;
|
||||||
|
Theme.ModifiedOn = theme.ModifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// any remaining themes are orphans
|
||||||
|
foreach (Theme theme in themes)
|
||||||
|
{
|
||||||
|
_db.Theme.Remove(theme); // delete
|
||||||
|
_db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteId != -1)
|
||||||
|
{
|
||||||
|
// get settings for site
|
||||||
|
var settings = _settings.GetSettings(EntityNames.Theme).ToList();
|
||||||
|
|
||||||
|
// populate theme site settings
|
||||||
|
foreach (Theme theme in Themes)
|
||||||
|
{
|
||||||
|
theme.SiteId = siteId;
|
||||||
|
|
||||||
|
var setting = settings.FirstOrDefault(item => item.EntityId == theme.ThemeId && item.SettingName == $"{settingprefix}{_tenants.GetAlias().SiteKey}");
|
||||||
|
if (setting != null)
|
||||||
|
{
|
||||||
|
theme.IsEnabled = bool.Parse(setting.SettingValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theme.IsEnabled = theme.IsAutoEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Themes;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Theme> LoadThemesFromAssemblies()
|
private List<Theme> LoadThemesFromAssemblies()
|
||||||
{
|
{
|
||||||
List<Theme> themes = new List<Theme>();
|
List<Theme> themes = new List<Theme>();
|
||||||
|
@ -143,28 +272,5 @@ namespace Oqtane.Repository
|
||||||
}
|
}
|
||||||
return themes;
|
return themes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Theme> FilterThemes(List<Theme> themes)
|
|
||||||
{
|
|
||||||
var Themes = new List<Theme>();
|
|
||||||
|
|
||||||
foreach (Theme theme in themes)
|
|
||||||
{
|
|
||||||
var Theme = new Theme();
|
|
||||||
Theme.ThemeName = theme.ThemeName;
|
|
||||||
Theme.Name = theme.Name;
|
|
||||||
Theme.Resources = theme.Resources;
|
|
||||||
Theme.Themes = theme.Themes;
|
|
||||||
Theme.Containers = theme.Containers;
|
|
||||||
Themes.Add(Theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Themes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteTheme(string ThemeName)
|
|
||||||
{
|
|
||||||
_cache.Remove("themes");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Oqtane.Models
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Information about a Theme in Oqtane.
|
/// Information about a Theme in Oqtane.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Theme
|
public class Theme : ModelBase
|
||||||
{
|
{
|
||||||
public Theme()
|
public Theme()
|
||||||
{
|
{
|
||||||
|
@ -25,68 +25,81 @@ namespace Oqtane.Models
|
||||||
Resources = null;
|
Resources = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference to the <see cref="Theme"/>.
|
||||||
|
/// </summary>
|
||||||
|
public int ThemeId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Full Namespace / Identifier of the Theme.
|
/// Full Namespace / Identifier of the Theme.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ThemeName { get; set; }
|
public string ThemeName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
// additional ITheme properties
|
||||||
/// Nice Name of the Theme.
|
[NotMapped]
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[NotMapped]
|
||||||
/// Version as determined by the DLL / NuGet Package.
|
|
||||||
/// </summary>
|
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[NotMapped]
|
||||||
/// Author / Creator of the Theme.
|
|
||||||
/// </summary>
|
|
||||||
public string Owner { get; set; }
|
public string Owner { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[NotMapped]
|
||||||
/// URL (in NuGet) of the Theme
|
|
||||||
/// </summary>
|
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[NotMapped]
|
||||||
/// Author Contact information
|
|
||||||
/// </summary>
|
|
||||||
public string Contact { get; set; }
|
public string Contact { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[NotMapped]
|
||||||
/// Theme License, like `MIT` etc.
|
|
||||||
/// </summary>
|
|
||||||
public string License { get; set; }
|
public string License { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[NotMapped]
|
||||||
/// Theme Dependencies (DLLs) which the system will check if they exist
|
|
||||||
/// </summary>
|
|
||||||
public string Dependencies { get; set; }
|
public string Dependencies { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
public string ThemeSettingsType { get; set; } // added in 2.0.2
|
public string ThemeSettingsType { get; set; } // added in 2.0.2
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
public string ContainerSettingsType { get; set; } // added in 2.0.2
|
public string ContainerSettingsType { get; set; } // added in 2.0.2
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
public string PackageName { get; set; } // added in 2.1.0
|
public string PackageName { get; set; } // added in 2.1.0
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
public List<Resource> Resources { get; set; } // added in 4.0.0
|
public List<Resource> Resources { get; set; } // added in 4.0.0
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public bool IsAutoEnabled { get; set; } = true; // added in 4.0.0
|
||||||
|
|
||||||
|
|
||||||
// internal properties
|
// internal properties
|
||||||
|
[NotMapped]
|
||||||
|
public int SiteId { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
[NotMapped]
|
||||||
public string AssemblyName { get; set; }
|
public string AssemblyName { get; set; }
|
||||||
|
[NotMapped]
|
||||||
public List<ThemeControl> Themes { get; set; }
|
public List<ThemeControl> Themes { get; set; }
|
||||||
|
[NotMapped]
|
||||||
public List<ThemeControl> Containers { get; set; }
|
public List<ThemeControl> Containers { get; set; }
|
||||||
|
[NotMapped]
|
||||||
public string Template { get; set; }
|
public string Template { get; set; }
|
||||||
|
|
||||||
#region Obsolete Properties
|
#region Obsolete Properties
|
||||||
|
|
||||||
[Obsolete("This property is obsolete. Use Themes instead.", false)]
|
[Obsolete("This property is obsolete. Use Themes instead.", false)]
|
||||||
|
[NotMapped]
|
||||||
public string ThemeControls { get; set; }
|
public string ThemeControls { get; set; }
|
||||||
[Obsolete("This property is obsolete. Use Layouts instead.", false)]
|
[Obsolete("This property is obsolete. Use Layouts instead.", false)]
|
||||||
|
[NotMapped]
|
||||||
public string PaneLayouts { get; set; }
|
public string PaneLayouts { get; set; }
|
||||||
[Obsolete("This property is obsolete. Use Containers instead.", false)]
|
[Obsolete("This property is obsolete. Use Containers instead.", false)]
|
||||||
|
[NotMapped]
|
||||||
public string ContainerControls { get; set; }
|
public string ContainerControls { get; set; }
|
||||||
[Obsolete("This property is obsolete.", false)]
|
[Obsolete("This property is obsolete.", false)]
|
||||||
|
[NotMapped]
|
||||||
public List<ThemeControl> Layouts { get; set; }
|
public List<ThemeControl> Layouts { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace Oqtane.Shared
|
||||||
public const string Setting = "Setting";
|
public const string Setting = "Setting";
|
||||||
public const string Site = "Site";
|
public const string Site = "Site";
|
||||||
public const string Tenant = "Tenant";
|
public const string Tenant = "Tenant";
|
||||||
|
public const string Theme = "Theme";
|
||||||
public const string UrlMapping = "UrlMapping";
|
public const string UrlMapping = "UrlMapping";
|
||||||
public const string User = "User";
|
public const string User = "User";
|
||||||
public const string UserRole = "UserRole";
|
public const string UserRole = "UserRole";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user