Merge pull request #1984 from sbwalker/dev
resolved UI error when closing Event Log and Visitor Management, made button class consistent in Recycle Bin, refactored RichTextEditor, made use of ConfigManager consistently throughout framework, added support for deleted Sites, removed reference to Runtime in Startup as it is now set per Site, added versioning to Html/Text, added Meta tag support to Page Management
This commit is contained in:
commit
48ae6df4b7
@ -62,10 +62,6 @@
|
|||||||
{
|
{
|
||||||
SiteState.Alias = _installation.Alias;
|
SiteState.Alias = _installation.Alias;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_installation.Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name";
|
|
||||||
}
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl(PageState.Page.Path, "level=" + PageState.QueryString["level"] + "&function=" + PageState.QueryString["function"] + "&rows=" + PageState.QueryString["rows"] + "&page=" + PageState.QueryString["page"])">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@CloseUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
@ -188,4 +188,16 @@
|
|||||||
AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string CloseUrl()
|
||||||
|
{
|
||||||
|
if (!PageState.QueryString.ContainsKey("level"))
|
||||||
|
{
|
||||||
|
return NavigateUrl();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NavigateUrl(PageState.Page.Path, "level=" + PageState.QueryString["level"] + "&function=" + PageState.QueryString["function"] + "&rows=" + PageState.QueryString["rows"] + "&page=" + PageState.QueryString["page"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,12 @@
|
|||||||
<input id="title" class="form-control" @bind="@_title" />
|
<input id="title" class="form-control" @bind="@_title" />
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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>
|
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -156,220 +162,222 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
private List<Theme> _themeList;
|
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 List<Page> _pageList;
|
private List<Page> _pageList;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _title;
|
private string _title;
|
||||||
private string _path = string.Empty;
|
private string _meta;
|
||||||
private string _parentid = "-1";
|
private string _path = string.Empty;
|
||||||
private string _insert = ">>";
|
private string _parentid = "-1";
|
||||||
private List<Page> _children;
|
private string _insert = ">>";
|
||||||
private int _childid = -1;
|
private List<Page> _children;
|
||||||
private string _isnavigation = "True";
|
private int _childid = -1;
|
||||||
private string _isclickable = "True";
|
private string _isnavigation = "True";
|
||||||
private string _url;
|
private string _isclickable = "True";
|
||||||
private string _ispersonalizable = "False";
|
private string _url;
|
||||||
private string _themetype = string.Empty;
|
private string _ispersonalizable = "False";
|
||||||
private string _containertype = string.Empty;
|
private string _themetype = string.Empty;
|
||||||
private string _icon = string.Empty;
|
private string _containertype = string.Empty;
|
||||||
private string _permissions = string.Empty;
|
private string _icon = string.Empty;
|
||||||
private PermissionGrid _permissionGrid;
|
private string _permissions = string.Empty;
|
||||||
private Type _themeSettingsType;
|
private PermissionGrid _permissionGrid;
|
||||||
private object _themeSettings;
|
private Type _themeSettingsType;
|
||||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
private object _themeSettings;
|
||||||
private bool _refresh = false;
|
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||||
private ElementReference form;
|
private bool _refresh = false;
|
||||||
private bool validated = false;
|
private ElementReference form;
|
||||||
|
private bool validated = false;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themeList = await ThemeService.GetThemesAsync();
|
_themeList = await ThemeService.GetThemesAsync();
|
||||||
_themes = ThemeService.GetThemeControls(_themeList);
|
_themes = ThemeService.GetThemeControls(_themeList);
|
||||||
_themetype = PageState.Site.DefaultThemeType;
|
_themetype = PageState.Site.DefaultThemeType;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||||
_containertype = PageState.Site.DefaultContainerType;
|
_containertype = PageState.Site.DefaultContainerType;
|
||||||
_pageList = PageState.Pages;
|
_pageList = PageState.Pages;
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||||
_permissions = string.Empty;
|
_permissions = string.Empty;
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
|
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ParentChanged(ChangeEventArgs e)
|
private async void ParentChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
if (_parentid == "-1")
|
if (_parentid == "-1")
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ThemeChanged(ChangeEventArgs e)
|
private async void ThemeChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||||
_containertype = "-";
|
_containertype = "-";
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = _themeList.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);
|
||||||
if (_themeSettingsType != null)
|
if (_themeSettingsType != null)
|
||||||
{
|
{
|
||||||
ThemeSettingsComponent = builder =>
|
ThemeSettingsComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _themeSettingsType);
|
builder.OpenComponent(0, _themeSettingsType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_refresh = true;
|
_refresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SavePage()
|
private async Task SavePage()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
Page page = null;
|
Page page = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||||
{
|
{
|
||||||
page = new Page();
|
page = new Page();
|
||||||
page.SiteId = PageState.Page.SiteId;
|
page.SiteId = PageState.Page.SiteId;
|
||||||
page.Name = _name;
|
page.Name = _name;
|
||||||
page.Title = _title;
|
page.Title = _title;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_path))
|
if (string.IsNullOrEmpty(_path))
|
||||||
{
|
{
|
||||||
_path = _name;
|
_path = _name;
|
||||||
}
|
}
|
||||||
if (_path.Contains("/"))
|
if (_path.Contains("/"))
|
||||||
{
|
{
|
||||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parentid == "-1")
|
if (_parentid == "-1")
|
||||||
{
|
{
|
||||||
page.ParentId = null;
|
page.ParentId = null;
|
||||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
page.ParentId = Int32.Parse(_parentid);
|
page.ParentId = Int32.Parse(_parentid);
|
||||||
var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
|
var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
|
||||||
if (parent.Path == string.Empty)
|
if (parent.Path == string.Empty)
|
||||||
{
|
{
|
||||||
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
|
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(PagePathIsDeleted(page.Path, page.SiteId, _pageList))
|
if(PagePathIsDeleted(page.Path, page.SiteId, _pageList))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Page.Deleted"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.Page.Deleted"], _path), MessageType.Warning);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PagePathIsUnique(page.Path, page.SiteId, _pageList))
|
if (!PagePathIsUnique(page.Path, page.SiteId, _pageList))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Page child;
|
Page child;
|
||||||
switch (_insert)
|
switch (_insert)
|
||||||
{
|
{
|
||||||
case "<<":
|
case "<<":
|
||||||
page.Order = 0;
|
page.Order = 0;
|
||||||
break;
|
break;
|
||||||
case "<":
|
case "<":
|
||||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||||
page.Order = child.Order - 1;
|
page.Order = child.Order - 1;
|
||||||
break;
|
break;
|
||||||
case ">":
|
case ">":
|
||||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||||
page.Order = child.Order + 1;
|
page.Order = child.Order + 1;
|
||||||
break;
|
break;
|
||||||
case ">>":
|
case ">>":
|
||||||
page.Order = int.MaxValue;
|
page.Order = int.MaxValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
|
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
|
||||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||||
page.Url = _url;
|
page.Url = _url;
|
||||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||||
{
|
{
|
||||||
page.ThemeType = string.Empty;
|
page.ThemeType = string.Empty;
|
||||||
}
|
}
|
||||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||||
{
|
{
|
||||||
page.DefaultContainerType = string.Empty;
|
page.DefaultContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||||
page.Permissions = _permissionGrid.GetPermissions();
|
page.Permissions = _permissionGrid.GetPermissions();
|
||||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||||
page.UserId = null;
|
page.UserId = null;
|
||||||
|
page.Meta = _meta;
|
||||||
|
|
||||||
page = await PageService.AddPageAsync(page);
|
page = await PageService.AddPageAsync(page);
|
||||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||||
|
@ -102,6 +102,12 @@
|
|||||||
<input id="title" class="form-control" @bind="@_title" maxlength="200"/>
|
<input id="title" class="form-control" @bind="@_title" maxlength="200"/>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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>
|
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -200,6 +206,7 @@
|
|||||||
private int _pageId;
|
private int _pageId;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _title;
|
private string _title;
|
||||||
|
private string _meta;
|
||||||
private string _path;
|
private string _path;
|
||||||
private string _currentparentid;
|
private string _currentparentid;
|
||||||
private string _parentid = "-1";
|
private string _parentid = "-1";
|
||||||
@ -243,6 +250,7 @@
|
|||||||
{
|
{
|
||||||
_name = page.Name;
|
_name = page.Name;
|
||||||
_title = page.Title;
|
_title = page.Title;
|
||||||
|
_meta = page.Meta;
|
||||||
_path = page.Path;
|
_path = page.Path;
|
||||||
_pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList();
|
_pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList();
|
||||||
|
|
||||||
@ -313,77 +321,77 @@
|
|||||||
_pageModules.RemoveAll(item => item.PageModuleId == pagemodule.PageModuleId);
|
_pageModules.RemoveAll(item => item.PageModuleId == pagemodule.PageModuleId);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
NavigationManager.NavigateTo(NavigationManager.Uri + "&tab=PageModules");
|
NavigationManager.NavigateTo(NavigationManager.Uri + "&tab=PageModules");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message);
|
await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ParentChanged(ChangeEventArgs e)
|
private async void ParentChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
if (_parentid == "-1")
|
if (_parentid == "-1")
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_parentid == _currentparentid)
|
if (_parentid == _currentparentid)
|
||||||
{
|
{
|
||||||
_insert = "=";
|
_insert = "=";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_insert = ">>";
|
_insert = ">>";
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ThemeChanged(ChangeEventArgs e)
|
private async void ThemeChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||||
_containertype = "-";
|
_containertype = "-";
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThemeSettings()
|
private void ThemeSettings()
|
||||||
{
|
{
|
||||||
_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 = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||||
@ -402,97 +410,98 @@
|
|||||||
_refresh = true;
|
_refresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SavePage()
|
private async Task SavePage()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
Page page = null;
|
Page page = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||||
{
|
{
|
||||||
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||||
string currentPath = page.Path;
|
string currentPath = page.Path;
|
||||||
|
|
||||||
page.Name = _name;
|
page.Name = _name;
|
||||||
page.Title = _title;
|
page.Title = _title;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_path))
|
if (string.IsNullOrEmpty(_path))
|
||||||
{
|
{
|
||||||
_path = _name;
|
_path = _name;
|
||||||
}
|
}
|
||||||
if (_path.Contains("/"))
|
if (_path.Contains("/"))
|
||||||
{
|
{
|
||||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parentid == "-1")
|
if (_parentid == "-1")
|
||||||
{
|
{
|
||||||
page.ParentId = null;
|
page.ParentId = null;
|
||||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
page.ParentId = Int32.Parse(_parentid);
|
page.ParentId = Int32.Parse(_parentid);
|
||||||
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
|
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
|
||||||
if (parent.Path == string.Empty)
|
if (parent.Path == string.Empty)
|
||||||
{
|
{
|
||||||
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
|
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList))
|
if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_insert != "=")
|
if (_insert != "=")
|
||||||
{
|
{
|
||||||
Page child;
|
Page child;
|
||||||
switch (_insert)
|
switch (_insert)
|
||||||
{
|
{
|
||||||
case "<<":
|
case "<<":
|
||||||
page.Order = 0;
|
page.Order = 0;
|
||||||
break;
|
break;
|
||||||
case "<":
|
case "<":
|
||||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
||||||
if (child != null) page.Order = child.Order - 1;
|
if (child != null) page.Order = child.Order - 1;
|
||||||
break;
|
break;
|
||||||
case ">":
|
case ">":
|
||||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
||||||
if (child != null) page.Order = child.Order + 1;
|
if (child != null) page.Order = child.Order + 1;
|
||||||
break;
|
break;
|
||||||
case ">>":
|
case ">>":
|
||||||
page.Order = int.MaxValue;
|
page.Order = int.MaxValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
|
page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
|
||||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||||
page.Url = _url;
|
page.Url = _url;
|
||||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||||
{
|
{
|
||||||
page.ThemeType = string.Empty;
|
page.ThemeType = string.Empty;
|
||||||
}
|
}
|
||||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||||
{
|
{
|
||||||
page.DefaultContainerType = string.Empty;
|
page.DefaultContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
page.Icon = _icon ?? string.Empty;
|
page.Icon = _icon ?? string.Empty;
|
||||||
page.Permissions = _permissionGrid.GetPermissions();
|
page.Permissions = _permissionGrid.GetPermissions();
|
||||||
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
||||||
page.UserId = null;
|
page.UserId = null;
|
||||||
|
page.Meta = _meta;
|
||||||
|
|
||||||
page = await PageService.UpdatePageAsync(page);
|
page = await PageService.UpdatePageAsync(page);
|
||||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<th>@Localizer["DeletedOn"]</th>
|
<th>@Localizer["DeletedOn"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td>
|
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">Restore</button></td>
|
||||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.DeletedBy</td>
|
<td>@context.DeletedBy</td>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<th>@Localizer["DeletedOn"]</th>
|
<th>@Localizer["DeletedOn"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">@Localizer["Restore"]</button></td>
|
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
||||||
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||||
<td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td>
|
<td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td>
|
||||||
<td>@context.Title</td>
|
<td>@context.Title</td>
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl(PageState.Page.Path, "type=" + PageState.QueryString["type"] + "&days=" + PageState.QueryString["days"] + "&page=" + PageState.QueryString["page"])">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@CloseUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
@ -125,4 +125,16 @@
|
|||||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string CloseUrl()
|
||||||
|
{
|
||||||
|
if (!PageState.QueryString.ContainsKey("type"))
|
||||||
|
{
|
||||||
|
return NavigateUrl();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NavigateUrl(PageState.Page.Path, "type=" + PageState.QueryString["type"] + "&days=" + PageState.QueryString["days"] + "&page=" + PageState.QueryString["page"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,11 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (ReadOnly)
|
@if (ReadOnly)
|
||||||
{
|
{
|
||||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10" readonly></textarea>
|
<textarea class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10"></textarea>
|
<textarea class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
@ -83,109 +83,103 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ElementReference _editorElement;
|
private ElementReference _editorElement;
|
||||||
private ElementReference _toolBar;
|
private ElementReference _toolBar;
|
||||||
private bool _filemanagervisible = false;
|
private bool _filemanagervisible = false;
|
||||||
private FileManager _fileManager;
|
private FileManager _fileManager;
|
||||||
private string _content = string.Empty;
|
private string _rawhtml = string.Empty;
|
||||||
private string _original = string.Empty;
|
private string _richhtml = string.Empty;
|
||||||
private string _message = string.Empty;
|
private string _original = string.Empty;
|
||||||
|
private string _message = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ReadOnly { get; set; } = false;
|
public bool ReadOnly { get; set; } = false;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Placeholder { get; set; } = "Enter Your Content...";
|
public string Placeholder { get; set; } = "Enter Your Content...";
|
||||||
|
|
||||||
// parameters only applicable to rich text editor
|
// parameters only applicable to rich text editor
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment ToolbarContent { get; set; }
|
public RenderFragment ToolbarContent { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Theme { get; set; } = "snow";
|
public string Theme { get; set; } = "snow";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string DebugLevel { get; set; } = "info";
|
public string DebugLevel { get; set; } = "info";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AllowFileManagement { get; set; } = true;
|
public bool AllowFileManagement { get; set; } = true;
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" },
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" },
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
_content = Content; // raw HTML
|
_rawhtml = Content;
|
||||||
await RefreshRichText();
|
_richhtml = Content;
|
||||||
}
|
_original = _rawhtml; // preserve original content for comparison
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
{
|
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
|
||||||
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
var interop = new RichTextEditorInterop(JSRuntime);
|
||||||
|
|
||||||
await interop.CreateEditor(
|
if (firstRender)
|
||||||
_editorElement,
|
{
|
||||||
_toolBar,
|
await interop.CreateEditor(
|
||||||
ReadOnly,
|
_editorElement,
|
||||||
Placeholder,
|
_toolBar,
|
||||||
Theme,
|
ReadOnly,
|
||||||
DebugLevel);
|
Placeholder,
|
||||||
|
Theme,
|
||||||
|
DebugLevel);
|
||||||
|
}
|
||||||
|
|
||||||
await interop.LoadEditorContent(_editorElement, Content);
|
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||||
|
}
|
||||||
|
|
||||||
_content = Content; // raw HTML
|
public void CloseFileManager()
|
||||||
|
{
|
||||||
|
_filemanagervisible = false;
|
||||||
|
_message = string.Empty;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
// preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
|
public void RefreshRichText()
|
||||||
_original = await interop.GetHtml(_editorElement);
|
{
|
||||||
}
|
_richhtml = _rawhtml;
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseFileManager()
|
|
||||||
{
|
|
||||||
_filemanagervisible = false;
|
|
||||||
_message = string.Empty;
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshRichText()
|
|
||||||
{
|
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
|
||||||
await interop.LoadEditorContent(_editorElement, _content);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RefreshRawHtml()
|
public async Task RefreshRawHtml()
|
||||||
{
|
{
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
var interop = new RichTextEditorInterop(JSRuntime);
|
||||||
_content = await interop.GetHtml(_editorElement);
|
_rawhtml = await interop.GetHtml(_editorElement);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetHtml()
|
public async Task<string> GetHtml()
|
||||||
{
|
{
|
||||||
// get rich text content
|
// return raw content if it has changed
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
if (_original != _rawhtml)
|
||||||
string content = await interop.GetHtml(_editorElement);
|
|
||||||
|
|
||||||
if (_original != content)
|
|
||||||
{
|
{
|
||||||
// rich text content has changed - return it
|
return _rawhtml;
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// return raw html content
|
// otherwise return rich text content
|
||||||
return _content;
|
var interop = new RichTextEditorInterop(JSRuntime);
|
||||||
|
return await interop.GetHtml(_editorElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,23 +206,4 @@
|
|||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// other rich text editor methods which can be used by developers
|
|
||||||
public async Task<string> GetText()
|
|
||||||
{
|
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
|
||||||
return await interop.GetText(_editorElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> GetContent()
|
|
||||||
{
|
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
|
||||||
return await interop.GetContent(_editorElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task EnableEditor(bool mode)
|
|
||||||
{
|
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
|
||||||
await interop.EnableEditor(_editorElement, mode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,95 +9,186 @@
|
|||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (_content != null)
|
<TabStrip>
|
||||||
{
|
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
||||||
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" @ref="@RichTextEditorHtml"></RichTextEditor>
|
@if (_content != null)
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
{
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" @ref="@RichTextEditorHtml"></RichTextEditor>
|
||||||
@if (!string.IsNullOrEmpty(_content))
|
<br />
|
||||||
{
|
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
||||||
<br />
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
<br />
|
@if (!string.IsNullOrEmpty(_content))
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
{
|
||||||
}
|
<br />
|
||||||
}
|
<br />
|
||||||
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel Name="Versions" Heading="Versions" ResourceKey="Versions">
|
||||||
|
<Pager Items="@_htmltexts">
|
||||||
|
<Header>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
<th>@SharedLocalizer["CreatedOn"]</th>
|
||||||
|
<th>@SharedLocalizer["CreatedBy"]</th>
|
||||||
|
</Header>
|
||||||
|
<Row>
|
||||||
|
<td><ActionLink Action="View" Security="SecurityAccessLevel.Edit" OnClick="@(async () => await View(context))" ResourceKey="View" /></td>
|
||||||
|
<td><ActionDialog Header="Restore Version" Message="@string.Format(Localizer["Confirm.Restore"], context.CreatedOn)" Action="Restore" Security="SecurityAccessLevel.Edit" Class="btn btn-success" OnClick="@(async () => await Restore(context))" ResourceKey="Restore" /></td>
|
||||||
|
<td><ActionDialog Header="Delete Version" Message="@string.Format(Localizer["Confirm.Delete"], context.CreatedOn)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" /></td>
|
||||||
|
<td>@context.CreatedOn</td>
|
||||||
|
<td>@context.CreatedBy</td>
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
@((MarkupString)_view)
|
||||||
|
</TabPanel>
|
||||||
|
</TabStrip>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
public override string Title => "Edit Html/Text";
|
public override string Title => "Edit Html/Text";
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
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.bubble.css" },
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
||||||
};
|
};
|
||||||
|
|
||||||
private RichTextEditor RichTextEditorHtml;
|
private RichTextEditor RichTextEditorHtml;
|
||||||
private bool _allowfilemanagement;
|
private bool _allowfilemanagement;
|
||||||
private string _content = null;
|
private string _content = null;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
private DateTime _modifiedon;
|
private DateTime _modifiedon;
|
||||||
|
private List<Models.HtmlText> _htmltexts;
|
||||||
|
private string _view = "";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
||||||
|
await LoadContent();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
private async Task LoadContent()
|
||||||
if (htmltext != null)
|
{
|
||||||
{
|
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||||
_content = htmltext.Content;
|
if (htmltext != null)
|
||||||
_content = Utilities.FormatContent(_content, PageState.Alias, "render");
|
{
|
||||||
_createdby = htmltext.CreatedBy;
|
_content = htmltext.Content;
|
||||||
_createdon = htmltext.CreatedOn;
|
_content = Utilities.FormatContent(_content, PageState.Alias, "render");
|
||||||
_modifiedby = htmltext.ModifiedBy;
|
_createdby = htmltext.CreatedBy;
|
||||||
_modifiedon = htmltext.ModifiedOn;
|
_createdon = htmltext.CreatedOn;
|
||||||
}
|
_modifiedby = htmltext.ModifiedBy;
|
||||||
else
|
_modifiedon = htmltext.ModifiedOn;
|
||||||
{
|
}
|
||||||
_content = string.Empty;
|
else
|
||||||
}
|
{
|
||||||
}
|
_content = string.Empty;
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveContent()
|
_htmltexts = await HtmlTextService.GetHtmlTextsAsync(ModuleState.ModuleId);
|
||||||
{
|
_htmltexts = _htmltexts.OrderByDescending(item => item.CreatedOn).ToList();
|
||||||
string content = await RichTextEditorHtml.GetHtml();
|
|
||||||
content = Utilities.FormatContent(content, PageState.Alias, "save");
|
|
||||||
|
|
||||||
try
|
_view = "";
|
||||||
{
|
}
|
||||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
|
||||||
if (htmltext != null)
|
|
||||||
{
|
|
||||||
htmltext.Content = content;
|
|
||||||
await HtmlTextService.UpdateHtmlTextAsync(htmltext);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
htmltext = new HtmlText();
|
|
||||||
htmltext.ModuleId = ModuleState.ModuleId;
|
|
||||||
htmltext.Content = content;
|
|
||||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
|
||||||
}
|
|
||||||
|
|
||||||
await logger.LogInformation("Content Saved {HtmlText}", htmltext);
|
private async Task SaveContent()
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
{
|
||||||
}
|
string content = await RichTextEditorHtml.GetHtml();
|
||||||
catch (Exception ex)
|
content = Utilities.FormatContent(content, PageState.Alias, "save");
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
|
try
|
||||||
AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
|
{
|
||||||
}
|
var htmltext = new HtmlText();
|
||||||
}
|
htmltext.ModuleId = ModuleState.ModuleId;
|
||||||
|
htmltext.Content = content;
|
||||||
|
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||||
|
|
||||||
|
await logger.LogInformation("Content Saved {HtmlText}", htmltext);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task View(Models.HtmlText htmltext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||||
|
if (htmltext != null)
|
||||||
|
{
|
||||||
|
_view = htmltext.Content;
|
||||||
|
_view = Utilities.FormatContent(_view, PageState.Alias, "render");
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Content.View"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Restore(Models.HtmlText htmltext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
||||||
|
if (htmltext != null)
|
||||||
|
{
|
||||||
|
var content = htmltext.Content;
|
||||||
|
htmltext = new HtmlText();
|
||||||
|
htmltext.ModuleId = ModuleState.ModuleId;
|
||||||
|
htmltext.Content = content;
|
||||||
|
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||||
|
await logger.LogInformation("Content Restored {HtmlText}", htmltext);
|
||||||
|
AddModuleMessage(Localizer["Message.Content.Restored"], MessageType.Success);
|
||||||
|
await LoadContent();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Content.Restore"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Delete(Models.HtmlText htmltext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
||||||
|
if (htmltext != null)
|
||||||
|
{
|
||||||
|
await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||||
|
await logger.LogInformation("Content Deleted {HtmlText}", htmltext);
|
||||||
|
AddModuleMessage(Localizer["Message.Content.Deleted"], MessageType.Success);
|
||||||
|
await LoadContent();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Content.Delete"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
@ -13,24 +15,29 @@ namespace Oqtane.Modules.HtmlText.Services
|
|||||||
|
|
||||||
private string ApiUrl => CreateApiUrl("HtmlText");
|
private string ApiUrl => CreateApiUrl("HtmlText");
|
||||||
|
|
||||||
|
public async Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<List<Models.HtmlText>>(CreateAuthorizationPolicyUrl($"{ApiUrl}?moduleid={moduleId}", EntityNames.Module, moduleId));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Models.HtmlText> GetHtmlTextAsync(int moduleId)
|
public async Task<Models.HtmlText> GetHtmlTextAsync(int moduleId)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
|
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
|
||||||
{
|
{
|
||||||
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateHtmlTextAsync(Models.HtmlText htmlText)
|
public async Task DeleteHtmlTextAsync(int htmlTextId, int moduleId)
|
||||||
{
|
{
|
||||||
await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteHtmlTextAsync(int moduleId)
|
|
||||||
{
|
|
||||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Modules.HtmlText.Models;
|
|
||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Services
|
namespace Oqtane.Modules.HtmlText.Services
|
||||||
{
|
{
|
||||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||||
public interface IHtmlTextService
|
public interface IHtmlTextService
|
||||||
{
|
{
|
||||||
Task<Models.HtmlText> GetHtmlTextAsync(int ModuleId);
|
Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId);
|
||||||
|
|
||||||
|
Task<Models.HtmlText> GetHtmlTextAsync(int moduleId);
|
||||||
|
|
||||||
|
Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId);
|
||||||
|
|
||||||
Task AddHtmlTextAsync(Models.HtmlText htmltext);
|
Task AddHtmlTextAsync(Models.HtmlText htmltext);
|
||||||
|
|
||||||
Task UpdateHtmlTextAsync(Models.HtmlText htmltext);
|
Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
|
||||||
|
|
||||||
Task DeleteHtmlTextAsync(int ModuleId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,4 +231,10 @@
|
|||||||
<data name="Message.Page.Deleted" xml:space="preserve">
|
<data name="Message.Page.Deleted" xml:space="preserve">
|
||||||
<value>A page with path {0} already exists for the selected parent page in the Recycle Bin. Either recover the page or remove from the Recycle Bin and create it again.</value>
|
<value>A page with path {0} already exists for the selected parent page in the Recycle Bin. Either recover the page or remove from the Recycle Bin and create it again.</value>
|
||||||
</data>
|
</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>
|
||||||
|
<data name="Meta.Text" xml:space="preserve">
|
||||||
|
<value>Meta:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -264,4 +264,10 @@
|
|||||||
<data name="Clickable.Text" xml:space="preserve">
|
<data name="Clickable.Text" xml:space="preserve">
|
||||||
<value>Clickable?</value>
|
<value>Clickable?</value>
|
||||||
</data>
|
</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>
|
||||||
|
<data name="Meta.Text" xml:space="preserve">
|
||||||
|
<value>Meta:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -117,10 +117,52 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="Confirm.Delete" xml:space="preserve">
|
||||||
|
<value>Are You Sure You Wish To Delete The {0} Version?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirm.Restore" xml:space="preserve">
|
||||||
|
<value>Are You Sure You Wish To Restore The {0} Version?</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreatedBy" xml:space="preserve">
|
||||||
|
<value>Created By</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreatedOn" xml:space="preserve">
|
||||||
|
<value>Created On</value>
|
||||||
|
</data>
|
||||||
|
<data name="Delete.Header" xml:space="preserve">
|
||||||
|
<value>Delete Version</value>
|
||||||
|
</data>
|
||||||
|
<data name="Delete.Text" xml:space="preserve">
|
||||||
|
<value>Delete</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.Content.Delete" xml:space="preserve">
|
||||||
|
<value>Error Deleting Version</value>
|
||||||
|
</data>
|
||||||
<data name="Error.Content.Load" xml:space="preserve">
|
<data name="Error.Content.Load" xml:space="preserve">
|
||||||
<value>An Error Occurred Loading Content</value>
|
<value>An Error Occurred Loading Content</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Error.Content.Restore" xml:space="preserve">
|
||||||
|
<value>Error Restoring Version</value>
|
||||||
|
</data>
|
||||||
<data name="Error.Content.Save" xml:space="preserve">
|
<data name="Error.Content.Save" xml:space="preserve">
|
||||||
<value>An Error Occurred Saving Content</value>
|
<value>An Error Occurred Saving Content</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Error.Content.View" xml:space="preserve">
|
||||||
|
<value>Error Viewing Version</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Content.Deleted" xml:space="preserve">
|
||||||
|
<value>Version Deleted</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Content.Restored" xml:space="preserve">
|
||||||
|
<value>Version Restored</value>
|
||||||
|
</data>
|
||||||
|
<data name="Restore.Header" xml:space="preserve">
|
||||||
|
<value>Restore Version</value>
|
||||||
|
</data>
|
||||||
|
<data name="Restore.Text" xml:space="preserve">
|
||||||
|
<value>Restore</value>
|
||||||
|
</data>
|
||||||
|
<data name="View.Text" xml:space="preserve">
|
||||||
|
<value>View</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -17,18 +17,17 @@ using Oqtane.Infrastructure;
|
|||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using Oqtane.Services;
|
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
public static class OqtaneServiceCollectionExtensions
|
public static class OqtaneServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime, string[] supportedCultures)
|
public static IServiceCollection AddOqtane(this IServiceCollection services, string[] supportedCultures)
|
||||||
{
|
{
|
||||||
LoadAssemblies();
|
LoadAssemblies();
|
||||||
LoadSatelliteAssemblies(supportedCultures);
|
LoadSatelliteAssemblies(supportedCultures);
|
||||||
services.AddOqtaneServices(runtime);
|
services.AddOqtaneServices();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
@ -190,7 +189,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddOqtaneServices(this IServiceCollection services, Runtime runtime)
|
private static IServiceCollection AddOqtaneServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
if (services is null)
|
if (services is null)
|
||||||
{
|
{
|
||||||
@ -229,14 +228,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
{
|
{
|
||||||
startup.ConfigureServices(services);
|
startup.ConfigureServices(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime == Runtime.Server)
|
|
||||||
{
|
|
||||||
// register client startup services if running on server
|
|
||||||
assembly.GetInstances<IClientStartup>()
|
|
||||||
.ToList()
|
|
||||||
.ForEach(x => x.ConfigureServices(services));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,14 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
public class DatabaseManager : IDatabaseManager
|
public class DatabaseManager : IDatabaseManager
|
||||||
{
|
{
|
||||||
private readonly IConfigurationRoot _config;
|
private readonly IConfigManager _config;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly IWebHostEnvironment _environment;
|
private readonly IWebHostEnvironment _environment;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly IConfigManager _configManager;
|
private readonly IConfigManager _configManager;
|
||||||
private readonly ILogger<DatabaseManager> _filelogger;
|
private readonly ILogger<DatabaseManager> _filelogger;
|
||||||
|
|
||||||
public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger<DatabaseManager> filelogger)
|
public DatabaseManager(IConfigManager config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger<DatabaseManager> filelogger)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
|
@ -14,18 +14,18 @@ namespace Oqtane.Infrastructure
|
|||||||
public class LogManager : ILogManager
|
public class LogManager : ILogManager
|
||||||
{
|
{
|
||||||
private readonly ILogRepository _logs;
|
private readonly ILogRepository _logs;
|
||||||
private readonly IConfigurationRoot _config;
|
private readonly ITenantManager _tenantManager;
|
||||||
|
private readonly IConfigManager _config;
|
||||||
private readonly IUserPermissions _userPermissions;
|
private readonly IUserPermissions _userPermissions;
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
private readonly Alias _alias;
|
|
||||||
|
|
||||||
public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor)
|
public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigManager config, IUserPermissions userPermissions, IHttpContextAccessor accessor)
|
||||||
{
|
{
|
||||||
_logs = logs;
|
_logs = logs;
|
||||||
|
_tenantManager = tenantManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
_userPermissions = userPermissions;
|
_userPermissions = userPermissions;
|
||||||
_accessor = accessor;
|
_accessor = accessor;
|
||||||
_alias = tenantManager.GetAlias();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args)
|
public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args)
|
||||||
@ -48,9 +48,13 @@ namespace Oqtane.Infrastructure
|
|||||||
Log log = new Log();
|
Log log = new Log();
|
||||||
|
|
||||||
log.SiteId = siteId;
|
log.SiteId = siteId;
|
||||||
if (log.SiteId == -1 && _alias != null)
|
if (log.SiteId == -1)
|
||||||
{
|
{
|
||||||
log.SiteId = _alias.SiteId;
|
var alias = _tenantManager.GetAlias();
|
||||||
|
if (alias != null)
|
||||||
|
{
|
||||||
|
log.SiteId = alias.SiteId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (log.SiteId == -1) return; // logs must be site specific
|
if (log.SiteId == -1) return; // logs must be site specific
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
@ -16,8 +15,8 @@ namespace Oqtane.Infrastructure
|
|||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
// check if framework is installed
|
// check if framework is installed
|
||||||
var config = context.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
|
var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager;
|
||||||
if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection")))
|
if (config.IsInstalled())
|
||||||
{
|
{
|
||||||
// get alias
|
// get alias
|
||||||
var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager;
|
var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager;
|
||||||
|
29
Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs
Normal file
29
Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.03.00.03.01")]
|
||||||
|
public class AddPageMeta : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public AddPageMeta(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
pageEntityBuilder.AddStringColumn("Meta", 2000, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
pageEntityBuilder.DropColumn("Meta");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ using Oqtane.Infrastructure;
|
|||||||
using Oqtane.Controllers;
|
using Oqtane.Controllers;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Controllers
|
namespace Oqtane.Modules.HtmlText.Controllers
|
||||||
{
|
{
|
||||||
@ -22,18 +24,60 @@ namespace Oqtane.Modules.HtmlText.Controllers
|
|||||||
_htmlText = htmlText;
|
_htmlText = htmlText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET api/<controller>/5
|
// GET: api/<controller>?moduleid=x
|
||||||
[HttpGet("{id}")]
|
[HttpGet]
|
||||||
[Authorize(Policy = PolicyNames.ViewModule)]
|
[Authorize(Roles = RoleNames.Registered)]
|
||||||
public Models.HtmlText Get(int id)
|
public IEnumerable<Models.HtmlText> Get(string moduleId)
|
||||||
{
|
{
|
||||||
if (AuthEntityId(EntityNames.Module) == id)
|
if (int.TryParse(moduleId, out int ModuleId) && AuthEntityId(EntityNames.Module) == ModuleId)
|
||||||
|
{
|
||||||
|
return _htmlText.GetHtmlTexts(ModuleId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {ModuleId}", moduleId);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/5
|
||||||
|
[HttpGet("{moduleid}")]
|
||||||
|
[Authorize(Policy = PolicyNames.ViewModule)]
|
||||||
|
public Models.HtmlText Get(int moduleId)
|
||||||
|
{
|
||||||
|
if (AuthEntityId(EntityNames.Module) == moduleId)
|
||||||
|
{
|
||||||
|
var htmltexts = _htmlText.GetHtmlTexts(moduleId);
|
||||||
|
if (htmltexts != null && htmltexts.Any())
|
||||||
|
{
|
||||||
|
return htmltexts.OrderByDescending(item => item.CreatedOn).First();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {ModuleId}", moduleId);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/5/6
|
||||||
|
[HttpGet("{id}/{moduleid}")]
|
||||||
|
[Authorize(Policy = PolicyNames.ViewModule)]
|
||||||
|
public Models.HtmlText Get(int id, int moduleId)
|
||||||
|
{
|
||||||
|
if (AuthEntityId(EntityNames.Module) == moduleId)
|
||||||
{
|
{
|
||||||
return _htmlText.GetHtmlText(id);
|
return _htmlText.GetHtmlText(id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Get Attempt {ModuleId}", id);
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {HtmlTextId}", id);
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -53,27 +97,7 @@ namespace Oqtane.Modules.HtmlText.Controllers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Post Attempt {HtmlText}", htmlText);
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Post Attempt {HtmlText}", htmlText);
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT api/<controller>/5
|
|
||||||
[ValidateAntiForgeryToken]
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
[Authorize(Policy = PolicyNames.EditModule)]
|
|
||||||
public Models.HtmlText Put(int id, [FromBody] Models.HtmlText htmlText)
|
|
||||||
{
|
|
||||||
if (ModelState.IsValid && AuthEntityId(EntityNames.Module) == htmlText.ModuleId)
|
|
||||||
{
|
|
||||||
htmlText = _htmlText.UpdateHtmlText(htmlText);
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Html/Text Updated {HtmlText}", htmlText);
|
|
||||||
return htmlText;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Put Attempt {HtmlText}", htmlText);
|
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -81,18 +105,18 @@ namespace Oqtane.Modules.HtmlText.Controllers
|
|||||||
|
|
||||||
// DELETE api/<controller>/5
|
// DELETE api/<controller>/5
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}/{moduleid}")]
|
||||||
[Authorize(Policy = PolicyNames.EditModule)]
|
[Authorize(Policy = PolicyNames.EditModule)]
|
||||||
public void Delete(int id)
|
public void Delete(int id, int moduleId)
|
||||||
{
|
{
|
||||||
if (AuthEntityId(EntityNames.Module) == id)
|
if (AuthEntityId(EntityNames.Module) == moduleId)
|
||||||
{
|
{
|
||||||
_htmlText.DeleteHtmlText(id);
|
_htmlText.DeleteHtmlText(id);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Html/Text Deleted {HtmlTextId}", id);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Html/Text Deleted {HtmlTextId}", id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Delete Attempt {ModuleId}", id);
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Delete Attempt {HtmlTextId}", id);
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,19 +43,10 @@ namespace Oqtane.Modules.HtmlText.Manager
|
|||||||
public void ImportModule(Module module, string content, string version)
|
public void ImportModule(Module module, string content, string version)
|
||||||
{
|
{
|
||||||
content = WebUtility.HtmlDecode(content);
|
content = WebUtility.HtmlDecode(content);
|
||||||
var htmlText = _htmlText.GetHtmlText(module.ModuleId);
|
var htmlText = new Models.HtmlText();
|
||||||
if (htmlText != null)
|
htmlText.ModuleId = module.ModuleId;
|
||||||
{
|
htmlText.Content = content;
|
||||||
htmlText.Content = content;
|
_htmlText.AddHtmlText(htmlText);
|
||||||
_htmlText.UpdateHtmlText(htmlText);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
htmlText = new Models.HtmlText();
|
|
||||||
htmlText.ModuleId = module.ModuleId;
|
|
||||||
htmlText.Content = content;
|
|
||||||
_htmlText.AddHtmlText(htmlText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Install(Tenant tenant, string version)
|
public bool Install(Tenant tenant, string version)
|
||||||
|
@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Oqtane.Modules.HtmlText.Models;
|
using Oqtane.Modules.HtmlText.Models;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Repository
|
namespace Oqtane.Modules.HtmlText.Repository
|
||||||
{
|
{
|
||||||
@ -15,11 +16,15 @@ namespace Oqtane.Modules.HtmlText.Repository
|
|||||||
_db = context;
|
_db = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Models.HtmlText GetHtmlText(int moduleId)
|
public IEnumerable<Models.HtmlText> GetHtmlTexts(int moduleId)
|
||||||
{
|
{
|
||||||
return _db.HtmlText.FirstOrDefault(item => item.ModuleId == moduleId);
|
return _db.HtmlText.Where(item => item.ModuleId == moduleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Models.HtmlText GetHtmlText(int htmlTextId)
|
||||||
|
{
|
||||||
|
return _db.HtmlText.Find(htmlTextId);
|
||||||
|
}
|
||||||
|
|
||||||
public Models.HtmlText AddHtmlText(Models.HtmlText htmlText)
|
public Models.HtmlText AddHtmlText(Models.HtmlText htmlText)
|
||||||
{
|
{
|
||||||
@ -28,16 +33,9 @@ namespace Oqtane.Modules.HtmlText.Repository
|
|||||||
return htmlText;
|
return htmlText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Models.HtmlText UpdateHtmlText(Models.HtmlText htmlText)
|
public void DeleteHtmlText(int htmlTextId)
|
||||||
{
|
{
|
||||||
_db.Entry(htmlText).State = EntityState.Modified;
|
Models.HtmlText htmlText = _db.HtmlText.FirstOrDefault(item => item.HtmlTextId == htmlTextId);
|
||||||
_db.SaveChanges();
|
|
||||||
return htmlText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteHtmlText(int moduleId)
|
|
||||||
{
|
|
||||||
Models.HtmlText htmlText = _db.HtmlText.FirstOrDefault(item => item.ModuleId == moduleId);
|
|
||||||
if (htmlText != null) _db.HtmlText.Remove(htmlText);
|
if (htmlText != null) _db.HtmlText.Remove(htmlText);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Modules.HtmlText.Models;
|
using Oqtane.Modules.HtmlText.Models;
|
||||||
|
|
||||||
@ -6,9 +7,9 @@ namespace Oqtane.Modules.HtmlText.Repository
|
|||||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||||
public interface IHtmlTextRepository
|
public interface IHtmlTextRepository
|
||||||
{
|
{
|
||||||
Models.HtmlText GetHtmlText(int moduleId);
|
IEnumerable<Models.HtmlText> GetHtmlTexts(int moduleId);
|
||||||
|
Models.HtmlText GetHtmlText(int htmlTextId);
|
||||||
Models.HtmlText AddHtmlText(Models.HtmlText htmlText);
|
Models.HtmlText AddHtmlText(Models.HtmlText htmlText);
|
||||||
Models.HtmlText UpdateHtmlText(Models.HtmlText htmlText);
|
void DeleteHtmlText(int htmlTextId);
|
||||||
void DeleteHtmlText(int moduleId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>@Model.Title</title>
|
<title>@Model.Title</title>
|
||||||
|
@Model.Meta
|
||||||
<base href="~/" />
|
<base href="~/" />
|
||||||
<link id="app-favicon" rel="shortcut icon" type="image/x-icon" href="@Model.FavIcon" />
|
<link id="app-favicon" rel="shortcut icon" type="image/x-icon" href="@Model.FavIcon" />
|
||||||
@if (!string.IsNullOrEmpty(Model.PWAScript))
|
@if (!string.IsNullOrEmpty(Model.PWAScript))
|
||||||
@ -20,34 +21,42 @@
|
|||||||
@Html.Raw(Model.HeadResources)
|
@Html.Raw(Model.HeadResources)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@(Html.AntiForgeryToken())
|
@if (string.IsNullOrEmpty(Model.Message))
|
||||||
<component type="typeof(Oqtane.App)" render-mode="@Model.RenderMode" param-AntiForgeryToken="@Model.AntiForgeryToken" param-Runtime="@Model.Runtime" param-RenderMode="@Model.RenderMode.ToString()" param-VisitorId="@Model.VisitorId" param-RemoteIPAddress="@Model.RemoteIPAddress" />
|
|
||||||
|
|
||||||
<div id="blazor-error-ui">
|
|
||||||
<environment include="Staging,Production">
|
|
||||||
An error has occurred. This application may no longer respond until reloaded.
|
|
||||||
</environment>
|
|
||||||
<environment include="Development">
|
|
||||||
An unhandled exception has occurred. See browser dev tools for details.
|
|
||||||
</environment>
|
|
||||||
<a href="" class="reload">Reload</a>
|
|
||||||
<a class="dismiss">🗙</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="js/interop.js"></script>
|
|
||||||
|
|
||||||
@if (Model.Runtime == "WebAssembly")
|
|
||||||
{
|
|
||||||
<script src="_framework/blazor.webassembly.js"></script>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<script src="_framework/blazor.server.js"></script>
|
|
||||||
}
|
|
||||||
@if (!string.IsNullOrEmpty(Model.PWAScript))
|
|
||||||
{
|
{
|
||||||
@Html.Raw(Model.PWAScript)
|
@(Html.AntiForgeryToken())
|
||||||
|
|
||||||
|
<component type="typeof(Oqtane.App)" render-mode="@Model.RenderMode" param-AntiForgeryToken="@Model.AntiForgeryToken" param-Runtime="@Model.Runtime" param-RenderMode="@Model.RenderMode.ToString()" param-VisitorId="@Model.VisitorId" param-RemoteIPAddress="@Model.RemoteIPAddress" />
|
||||||
|
|
||||||
|
<div id="blazor-error-ui">
|
||||||
|
<environment include="Staging,Production">
|
||||||
|
An error has occurred. This application may no longer respond until reloaded.
|
||||||
|
</environment>
|
||||||
|
<environment include="Development">
|
||||||
|
An unhandled exception has occurred. See browser dev tools for details.
|
||||||
|
</environment>
|
||||||
|
<a href="" class="reload">Reload</a>
|
||||||
|
<a class="dismiss">🗙</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="js/interop.js"></script>
|
||||||
|
|
||||||
|
@if (Model.Runtime == "WebAssembly")
|
||||||
|
{
|
||||||
|
<script src="_framework/blazor.webassembly.js"></script>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<script src="_framework/blazor.server.js"></script>
|
||||||
|
}
|
||||||
|
@if (!string.IsNullOrEmpty(Model.PWAScript))
|
||||||
|
{
|
||||||
|
@Html.Raw(Model.PWAScript)
|
||||||
|
}
|
||||||
|
@Html.Raw(Model.BodyResources)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="app-alert">@Model.Message</div>
|
||||||
}
|
}
|
||||||
@Html.Raw(Model.BodyResources)
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -25,7 +25,7 @@ namespace Oqtane.Pages
|
|||||||
{
|
{
|
||||||
public class HostModel : PageModel
|
public class HostModel : PageModel
|
||||||
{
|
{
|
||||||
private IConfiguration _configuration;
|
private IConfigManager _configuration;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly ILocalizationManager _localizationManager;
|
private readonly ILocalizationManager _localizationManager;
|
||||||
private readonly ILanguageRepository _languages;
|
private readonly ILanguageRepository _languages;
|
||||||
@ -38,7 +38,7 @@ namespace Oqtane.Pages
|
|||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ILogManager logger)
|
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ILogManager logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
@ -63,9 +63,11 @@ namespace Oqtane.Pages
|
|||||||
public string HeadResources = "";
|
public string HeadResources = "";
|
||||||
public string BodyResources = "";
|
public string BodyResources = "";
|
||||||
public string Title = "";
|
public string Title = "";
|
||||||
|
public string Meta = "";
|
||||||
public string FavIcon = "favicon.ico";
|
public string FavIcon = "favicon.ico";
|
||||||
public string PWAScript = "";
|
public string PWAScript = "";
|
||||||
public string ThemeType = "";
|
public string ThemeType = "";
|
||||||
|
public string Message = "";
|
||||||
|
|
||||||
public IActionResult OnGet()
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
@ -83,7 +85,7 @@ namespace Oqtane.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if framework is installed
|
// if framework is installed
|
||||||
if (!string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection")))
|
if (_configuration.IsInstalled())
|
||||||
{
|
{
|
||||||
var alias = _tenantManager.GetAlias();
|
var alias = _tenantManager.GetAlias();
|
||||||
if (alias != null)
|
if (alias != null)
|
||||||
@ -108,7 +110,7 @@ namespace Oqtane.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
var site = _sites.GetSite(alias.SiteId);
|
var site = _sites.GetSite(alias.SiteId);
|
||||||
if (site != null)
|
if (site != null && !site.IsDeleted)
|
||||||
{
|
{
|
||||||
Route route = new Route(url, alias.Path);
|
Route route = new Route(url, alias.Path);
|
||||||
|
|
||||||
@ -148,6 +150,7 @@ namespace Oqtane.Pages
|
|||||||
{
|
{
|
||||||
Title = Title + " - " + page.Name;
|
Title = Title + " - " + page.Name;
|
||||||
}
|
}
|
||||||
|
Meta = page.Meta;
|
||||||
|
|
||||||
// include theme resources
|
// include theme resources
|
||||||
if (!string.IsNullOrEmpty(page.ThemeType))
|
if (!string.IsNullOrEmpty(page.ThemeType))
|
||||||
@ -165,42 +168,50 @@ namespace Oqtane.Pages
|
|||||||
return RedirectPermanent(url);
|
return RedirectPermanent(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// include global resources
|
// include global resources
|
||||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
||||||
foreach (Assembly assembly in assemblies)
|
foreach (Assembly assembly in assemblies)
|
||||||
{
|
|
||||||
ProcessHostResources(assembly);
|
|
||||||
ProcessModuleControls(assembly);
|
|
||||||
ProcessThemeControls(assembly);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set culture if not specified
|
|
||||||
string culture = HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName];
|
|
||||||
if (culture == null)
|
|
||||||
{
|
|
||||||
// get default language for site
|
|
||||||
var languages = _languages.GetLanguages(alias.SiteId);
|
|
||||||
if (languages.Any())
|
|
||||||
{
|
{
|
||||||
// use default language if specified otherwise use first language in collection
|
ProcessHostResources(assembly);
|
||||||
culture = (languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First()).Code;
|
ProcessModuleControls(assembly);
|
||||||
|
ProcessThemeControls(assembly);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
culture = _localizationManager.GetDefaultCulture();
|
|
||||||
}
|
|
||||||
SetLocalizationCookie(culture);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set language for page
|
// set culture if not specified
|
||||||
if (!string.IsNullOrEmpty(culture))
|
string culture = HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName];
|
||||||
{
|
if (culture == null)
|
||||||
// localization cookie value in form of c=en|uic=en
|
{
|
||||||
Language = culture.Split('|')[0];
|
// get default language for site
|
||||||
Language = Language.Replace("c=", "");
|
var languages = _languages.GetLanguages(alias.SiteId);
|
||||||
|
if (languages.Any())
|
||||||
|
{
|
||||||
|
// use default language if specified otherwise use first language in collection
|
||||||
|
culture = (languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First()).Code;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
culture = _localizationManager.GetDefaultCulture();
|
||||||
|
}
|
||||||
|
SetLocalizationCookie(culture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set language for page
|
||||||
|
if (!string.IsNullOrEmpty(culture))
|
||||||
|
{
|
||||||
|
// localization cookie value in form of c=en|uic=en
|
||||||
|
Language = culture.Split('|')[0];
|
||||||
|
Language = Language.Replace("c=", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message = "Site Is Either Disabled Or Not Configured Correctly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Page();
|
return Page();
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Oqtane.Databases.Interfaces;
|
using Oqtane.Databases.Interfaces;
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
using Oqtane.Interfaces;
|
|
||||||
using Oqtane.Migrations.Framework;
|
using Oqtane.Migrations.Framework;
|
||||||
using Oqtane.Repository.Databases.Interfaces;
|
using Oqtane.Repository.Databases.Interfaces;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
|
||||||
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
@ -24,14 +21,14 @@ namespace Oqtane.Repository
|
|||||||
public class MasterDBContext : DbContext, IMultiDatabase
|
public class MasterDBContext : DbContext, IMultiDatabase
|
||||||
{
|
{
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfigManager _config;
|
||||||
private string _connectionString;
|
private string _connectionString;
|
||||||
private string _databaseType;
|
private string _databaseType;
|
||||||
|
|
||||||
public MasterDBContext(DbContextOptions<MasterDBContext> options, IHttpContextAccessor accessor, IConfiguration configuration) : base(options)
|
public MasterDBContext(DbContextOptions<MasterDBContext> options, IHttpContextAccessor accessor, IConfigManager config) : base(options)
|
||||||
{
|
{
|
||||||
_accessor = accessor;
|
_accessor = accessor;
|
||||||
_configuration = configuration;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDatabase ActiveDatabase { get; private set; }
|
public IDatabase ActiveDatabase { get; private set; }
|
||||||
@ -40,15 +37,15 @@ namespace Oqtane.Repository
|
|||||||
{
|
{
|
||||||
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
|
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
|
||||||
|
|
||||||
if(_configuration != null)
|
if(_config != null)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection")))
|
if (_config.IsInstalled())
|
||||||
{
|
{
|
||||||
_connectionString = _configuration.GetConnectionString("DefaultConnection")
|
_connectionString = _config.GetConnectionString("DefaultConnection")
|
||||||
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
_databaseType = _configuration.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
_databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(_databaseType))
|
if (!String.IsNullOrEmpty(_databaseType))
|
||||||
|
@ -6,7 +6,6 @@ using Oqtane.Infrastructure;
|
|||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
namespace Oqtane.Security
|
namespace Oqtane.Security
|
||||||
{
|
{
|
||||||
@ -17,8 +16,8 @@ namespace Oqtane.Security
|
|||||||
if (context != null && context.Principal.Identity.IsAuthenticated)
|
if (context != null && context.Principal.Identity.IsAuthenticated)
|
||||||
{
|
{
|
||||||
// check if framework is installed
|
// check if framework is installed
|
||||||
var config = context.HttpContext.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
|
var config = context.HttpContext.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager;
|
||||||
if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection")))
|
if (config.IsInstalled())
|
||||||
{
|
{
|
||||||
var tenantManager = context.HttpContext.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager;
|
var tenantManager = context.HttpContext.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager;
|
||||||
var alias = tenantManager.GetAlias();
|
var alias = tenantManager.GetAlias();
|
||||||
|
@ -21,7 +21,6 @@ namespace Oqtane
|
|||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
private readonly Runtime _runtime;
|
|
||||||
private readonly bool _useSwagger;
|
private readonly bool _useSwagger;
|
||||||
private readonly IWebHostEnvironment _env;
|
private readonly IWebHostEnvironment _env;
|
||||||
private readonly string[] _supportedCultures;
|
private readonly string[] _supportedCultures;
|
||||||
@ -36,7 +35,6 @@ namespace Oqtane
|
|||||||
Configuration = builder.Build();
|
Configuration = builder.Build();
|
||||||
|
|
||||||
_supportedCultures = localizationManager.GetSupportedCultures();
|
_supportedCultures = localizationManager.GetSupportedCultures();
|
||||||
_runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server;
|
|
||||||
|
|
||||||
//add possibility to switch off swagger on production.
|
//add possibility to switch off swagger on production.
|
||||||
_useSwagger = Configuration.GetSection("UseSwagger").Value != "false";
|
_useSwagger = Configuration.GetSection("UseSwagger").Value != "false";
|
||||||
@ -115,7 +113,7 @@ namespace Oqtane
|
|||||||
services.AddOqtaneTransientServices();
|
services.AddOqtaneTransientServices();
|
||||||
|
|
||||||
// load the external assemblies into the app domain, install services
|
// load the external assemblies into the app domain, install services
|
||||||
services.AddOqtane(_runtime, _supportedCultures);
|
services.AddOqtane(_supportedCultures);
|
||||||
services.AddOqtaneDbContext();
|
services.AddOqtaneDbContext();
|
||||||
|
|
||||||
services.AddMvc()
|
services.AddMvc()
|
||||||
|
@ -61,7 +61,12 @@ namespace Oqtane.Models
|
|||||||
/// Reference to a Container which will be used for modules on this page.
|
/// Reference to a Container which will be used for modules on this page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DefaultContainerType { get; set; }
|
public string DefaultContainerType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Meta tags to be included in the head of the page
|
||||||
|
/// </summary>
|
||||||
|
public string Meta { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Icon file for this page.
|
/// Icon file for this page.
|
||||||
/// TODO: unclear what this is for, and what icon library is used. Probably FontAwesome?
|
/// TODO: unclear what this is for, and what icon library is used. Probably FontAwesome?
|
||||||
|
Loading…
x
Reference in New Issue
Block a user