diff --git a/Oqtane.Client/App.razor b/Oqtane.Client/App.razor index 92b73433..f8366e1c 100644 --- a/Oqtane.Client/App.razor +++ b/Oqtane.Client/App.razor @@ -62,10 +62,6 @@ { SiteState.Alias = _installation.Alias; } - else - { - _installation.Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name"; - } _initialized = true; } diff --git a/Oqtane.Client/Modules/Admin/Logs/Detail.razor b/Oqtane.Client/Modules/Admin/Logs/Detail.razor index 356ac98a..7111572e 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Detail.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Detail.razor @@ -110,7 +110,7 @@ } -@SharedLocalizer["Cancel"] +@SharedLocalizer["Cancel"] @code { private bool _initialized = false; @@ -188,4 +188,16 @@ 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"]); + } + } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index 36d45b47..863db4f6 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -95,6 +95,12 @@ +
+ +
+ +
+
@@ -156,220 +162,222 @@ @code { - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; - private List _themeList; - private List _themes = new List(); - private List _containers = new List(); - private List _pageList; - private string _name; - private string _title; - private string _path = string.Empty; - private string _parentid = "-1"; - private string _insert = ">>"; - private List _children; - private int _childid = -1; - private string _isnavigation = "True"; - private string _isclickable = "True"; - private string _url; - private string _ispersonalizable = "False"; - private string _themetype = string.Empty; - private string _containertype = string.Empty; - private string _icon = string.Empty; - private string _permissions = string.Empty; - private PermissionGrid _permissionGrid; - private Type _themeSettingsType; - private object _themeSettings; - private RenderFragment ThemeSettingsComponent { get; set; } - private bool _refresh = false; - private ElementReference form; - private bool validated = false; + private List _themeList; + private List _themes = new List(); + private List _containers = new List(); + private List _pageList; + private string _name; + private string _title; + private string _meta; + private string _path = string.Empty; + private string _parentid = "-1"; + private string _insert = ">>"; + private List _children; + private int _childid = -1; + private string _isnavigation = "True"; + private string _isclickable = "True"; + private string _url; + private string _ispersonalizable = "False"; + private string _themetype = string.Empty; + private string _containertype = string.Empty; + private string _icon = string.Empty; + private string _permissions = string.Empty; + private PermissionGrid _permissionGrid; + private Type _themeSettingsType; + private object _themeSettings; + private RenderFragment ThemeSettingsComponent { get; set; } + private bool _refresh = false; + private ElementReference form; + private bool validated = false; - protected override async Task OnInitializedAsync() - { - try - { - _themeList = await ThemeService.GetThemesAsync(); - _themes = ThemeService.GetThemeControls(_themeList); - _themetype = PageState.Site.DefaultThemeType; - _containers = ThemeService.GetContainerControls(_themeList, _themetype); - _containertype = PageState.Site.DefaultContainerType; - _pageList = PageState.Pages; - _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); - _permissions = string.Empty; - ThemeSettings(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message); - AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error); - } - } + protected override async Task OnInitializedAsync() + { + try + { + _themeList = await ThemeService.GetThemesAsync(); + _themes = ThemeService.GetThemeControls(_themeList); + _themetype = PageState.Site.DefaultThemeType; + _containers = ThemeService.GetContainerControls(_themeList, _themetype); + _containertype = PageState.Site.DefaultContainerType; + _pageList = PageState.Pages; + _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); + _permissions = string.Empty; + ThemeSettings(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error); + } + } - private async void ParentChanged(ChangeEventArgs e) - { - try - { - _parentid = (string)e.Value; - _children = new List(); - if (_parentid == "-1") - { - foreach (Page p in PageState.Pages.Where(item => item.ParentId == null)) - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) - { - _children.Add(p); - } - } - } - else - { - foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid))) - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) - { - _children.Add(p); - } - } - } - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message); - AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error); - } - } + private async void ParentChanged(ChangeEventArgs e) + { + try + { + _parentid = (string)e.Value; + _children = new List(); + if (_parentid == "-1") + { + foreach (Page p in PageState.Pages.Where(item => item.ParentId == null)) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) + { + _children.Add(p); + } + } + } + else + { + foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid))) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) + { + _children.Add(p); + } + } + } + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message); + AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error); + } + } - private async void ThemeChanged(ChangeEventArgs e) - { - try - { - _themetype = (string)e.Value; - _containers = ThemeService.GetContainerControls(_themeList, _themetype); - _containertype = "-"; - ThemeSettings(); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message); - AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error); - } - } + private async void ThemeChanged(ChangeEventArgs e) + { + try + { + _themetype = (string)e.Value; + _containers = ThemeService.GetContainerControls(_themeList, _themetype); + _containertype = "-"; + ThemeSettings(); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message); + AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error); + } + } - private void ThemeSettings() - { - _themeSettingsType = null; - var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype))); - if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType)) - { - _themeSettingsType = Type.GetType(theme.ThemeSettingsType); - if (_themeSettingsType != null) - { - ThemeSettingsComponent = builder => - { - builder.OpenComponent(0, _themeSettingsType); - builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); }); - builder.CloseComponent(); - }; - } - _refresh = true; - } - } + private void ThemeSettings() + { + _themeSettingsType = null; + var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype))); + if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType)) + { + _themeSettingsType = Type.GetType(theme.ThemeSettingsType); + if (_themeSettingsType != null) + { + ThemeSettingsComponent = builder => + { + builder.OpenComponent(0, _themeSettingsType); + builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); }); + builder.CloseComponent(); + }; + } + _refresh = true; + } + } - private async Task SavePage() - { - validated = true; - var interop = new Interop(JSRuntime); - if (await interop.FormValid(form)) - { - Page page = null; - try - { - if (!string.IsNullOrEmpty(_themetype) && _containertype != "-") - { - page = new Page(); - page.SiteId = PageState.Page.SiteId; - page.Name = _name; - page.Title = _title; + private async Task SavePage() + { + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(form)) + { + Page page = null; + try + { + if (!string.IsNullOrEmpty(_themetype) && _containertype != "-") + { + page = new Page(); + page.SiteId = PageState.Page.SiteId; + page.Name = _name; + page.Title = _title; - if (string.IsNullOrEmpty(_path)) - { - _path = _name; - } - if (_path.Contains("/")) - { - _path = _path.Substring(_path.LastIndexOf("/") + 1); - } + if (string.IsNullOrEmpty(_path)) + { + _path = _name; + } + if (_path.Contains("/")) + { + _path = _path.Substring(_path.LastIndexOf("/") + 1); + } - if (_parentid == "-1") - { - page.ParentId = null; - page.Path = Utilities.GetFriendlyUrl(_path); - } - else - { - page.ParentId = Int32.Parse(_parentid); - var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault(); - if (parent.Path == string.Empty) - { - page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); - } - else - { - page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); - } - } + if (_parentid == "-1") + { + page.ParentId = null; + page.Path = Utilities.GetFriendlyUrl(_path); + } + else + { + page.ParentId = Int32.Parse(_parentid); + var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault(); + if (parent.Path == string.Empty) + { + page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); + } + else + { + page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); + } + } - if(PagePathIsDeleted(page.Path, page.SiteId, _pageList)) - { - AddModuleMessage(string.Format(Localizer["Message.Page.Deleted"], _path), MessageType.Warning); - return; - } + if(PagePathIsDeleted(page.Path, page.SiteId, _pageList)) + { + AddModuleMessage(string.Format(Localizer["Message.Page.Deleted"], _path), MessageType.Warning); + return; + } - if (!PagePathIsUnique(page.Path, page.SiteId, _pageList)) - { - AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning); - return; - } + if (!PagePathIsUnique(page.Path, page.SiteId, _pageList)) + { + AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning); + return; + } - Page child; - switch (_insert) - { - case "<<": - page.Order = 0; - break; - case "<": - child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); - page.Order = child.Order - 1; - break; - case ">": - child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); - page.Order = child.Order + 1; - break; - case ">>": - page.Order = int.MaxValue; - break; - } + Page child; + switch (_insert) + { + case "<<": + page.Order = 0; + break; + case "<": + child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); + page.Order = child.Order - 1; + break; + case ">": + child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); + page.Order = child.Order + 1; + break; + case ">>": + page.Order = int.MaxValue; + break; + } - page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation)); - page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); - page.Url = _url; - page.ThemeType = (_themetype != "-") ? _themetype : string.Empty; - if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType) - { - page.ThemeType = string.Empty; - } - page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty; - if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType) - { - page.DefaultContainerType = string.Empty; - } - page.Icon = (_icon == null ? string.Empty : _icon); - page.Permissions = _permissionGrid.GetPermissions(); - page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable)); - page.UserId = null; + page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation)); + page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); + page.Url = _url; + page.ThemeType = (_themetype != "-") ? _themetype : string.Empty; + if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType) + { + page.ThemeType = string.Empty; + } + page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty; + if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType) + { + page.DefaultContainerType = string.Empty; + } + page.Icon = (_icon == null ? string.Empty : _icon); + page.Permissions = _permissionGrid.GetPermissions(); + page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable)); + page.UserId = null; + page.Meta = _meta; page = await PageService.AddPageAsync(page); await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId); diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index d2edd289..11533da8 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -102,6 +102,12 @@
+
+ +
+ +
+
@@ -200,6 +206,7 @@ private int _pageId; private string _name; private string _title; + private string _meta; private string _path; private string _currentparentid; private string _parentid = "-1"; @@ -243,6 +250,7 @@ { _name = page.Name; _title = page.Title; + _meta = page.Meta; _path = page.Path; _pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList(); @@ -313,77 +321,77 @@ _pageModules.RemoveAll(item => item.PageModuleId == pagemodule.PageModuleId); StateHasChanged(); NavigationManager.NavigateTo(NavigationManager.Uri + "&tab=PageModules"); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message); - AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error); - } - } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message); + AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error); + } + } - private async void ParentChanged(ChangeEventArgs e) - { - try - { - _parentid = (string)e.Value; - _children = new List(); - if (_parentid == "-1") - { - foreach (Page p in PageState.Pages.Where(item => item.ParentId == null)) - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) - { - _children.Add(p); - } - } - } - else - { - foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid))) - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) - { - _children.Add(p); - } - } - } - if (_parentid == _currentparentid) - { - _insert = "="; - } - else - { - _insert = ">>"; - } - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message); - AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error); - } - } + private async void ParentChanged(ChangeEventArgs e) + { + try + { + _parentid = (string)e.Value; + _children = new List(); + if (_parentid == "-1") + { + foreach (Page p in PageState.Pages.Where(item => item.ParentId == null)) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) + { + _children.Add(p); + } + } + } + else + { + foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid))) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) + { + _children.Add(p); + } + } + } + if (_parentid == _currentparentid) + { + _insert = "="; + } + else + { + _insert = ">>"; + } + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message); + AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error); + } + } - private async void ThemeChanged(ChangeEventArgs e) - { - try - { - _themetype = (string)e.Value; - _containers = ThemeService.GetContainerControls(_themeList, _themetype); - _containertype = "-"; - ThemeSettings(); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message); - AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error); - } - } + private async void ThemeChanged(ChangeEventArgs e) + { + try + { + _themetype = (string)e.Value; + _containers = ThemeService.GetContainerControls(_themeList, _themetype); + _containertype = "-"; + ThemeSettings(); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message); + AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error); + } + } - private void ThemeSettings() - { - _themeSettingsType = null; + private void ThemeSettings() + { + _themeSettingsType = null; 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))); @@ -402,97 +410,98 @@ _refresh = true; } } - } + } - private async Task SavePage() - { - validated = true; - var interop = new Interop(JSRuntime); - if (await interop.FormValid(form)) - { - Page page = null; - try - { - if (!string.IsNullOrEmpty(_themetype) && _containertype != "-") - { - page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId); - string currentPath = page.Path; + private async Task SavePage() + { + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(form)) + { + Page page = null; + try + { + if (!string.IsNullOrEmpty(_themetype) && _containertype != "-") + { + page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId); + string currentPath = page.Path; - page.Name = _name; - page.Title = _title; + page.Name = _name; + page.Title = _title; - if (string.IsNullOrEmpty(_path)) - { - _path = _name; - } - if (_path.Contains("/")) - { - _path = _path.Substring(_path.LastIndexOf("/") + 1); - } + if (string.IsNullOrEmpty(_path)) + { + _path = _name; + } + if (_path.Contains("/")) + { + _path = _path.Substring(_path.LastIndexOf("/") + 1); + } - if (_parentid == "-1") - { - page.ParentId = null; - page.Path = Utilities.GetFriendlyUrl(_path); - } - else - { - page.ParentId = Int32.Parse(_parentid); - Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId); - if (parent.Path == string.Empty) - { - page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); - } - else - { - page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); - } - } + if (_parentid == "-1") + { + page.ParentId = null; + page.Path = Utilities.GetFriendlyUrl(_path); + } + else + { + page.ParentId = Int32.Parse(_parentid); + Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId); + if (parent.Path == string.Empty) + { + page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); + } + else + { + page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); + } + } - if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList)) - { - AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning); - return; - } + if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList)) + { + AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning); + return; + } - if (_insert != "=") - { - Page child; - switch (_insert) - { - case "<<": - page.Order = 0; - break; - case "<": - child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); - if (child != null) page.Order = child.Order - 1; - break; - case ">": - child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); - if (child != null) page.Order = child.Order + 1; - break; - case ">>": - page.Order = int.MaxValue; - break; - } - } - page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation)); - page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); - page.Url = _url; - page.ThemeType = (_themetype != "-") ? _themetype : string.Empty; - if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType) - { - page.ThemeType = string.Empty; - } - page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty; - if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType) - { - page.DefaultContainerType = string.Empty; - } - page.Icon = _icon ?? string.Empty; - page.Permissions = _permissionGrid.GetPermissions(); - page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable)); - page.UserId = null; + if (_insert != "=") + { + Page child; + switch (_insert) + { + case "<<": + page.Order = 0; + break; + case "<": + child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); + if (child != null) page.Order = child.Order - 1; + break; + case ">": + child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); + if (child != null) page.Order = child.Order + 1; + break; + case ">>": + page.Order = int.MaxValue; + break; + } + } + page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation)); + page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); + page.Url = _url; + page.ThemeType = (_themetype != "-") ? _themetype : string.Empty; + if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType) + { + page.ThemeType = string.Empty; + } + page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty; + if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType) + { + page.DefaultContainerType = string.Empty; + } + page.Icon = _icon ?? string.Empty; + page.Permissions = _permissionGrid.GetPermissions(); + page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable)); + page.UserId = null; + page.Meta = _meta; page = await PageService.UpdatePageAsync(page); await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId); diff --git a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor index 75273207..3e93cf7c 100644 --- a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor +++ b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor @@ -25,7 +25,7 @@ @Localizer["DeletedOn"] - + @context.Name @context.DeletedBy @@ -56,7 +56,7 @@ @Localizer["DeletedOn"] - + @PageState.Pages.Find(item => item.PageId == context.PageId).Name @context.Title diff --git a/Oqtane.Client/Modules/Admin/Visitors/Detail.razor b/Oqtane.Client/Modules/Admin/Visitors/Detail.razor index cff56939..3078eb1b 100644 --- a/Oqtane.Client/Modules/Admin/Visitors/Detail.razor +++ b/Oqtane.Client/Modules/Admin/Visitors/Detail.razor @@ -70,7 +70,7 @@
} -@SharedLocalizer["Cancel"] +@SharedLocalizer["Cancel"] @code { private bool _initialized = false; @@ -125,4 +125,16 @@ 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"]); + } + } } diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 5eee80aa..402f289b 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -71,11 +71,11 @@
@if (ReadOnly) { - + } else { - + } @@ -83,110 +83,121 @@ @code { - private ElementReference _editorElement; - private ElementReference _toolBar; - private bool _filemanagervisible = false; - private FileManager _fileManager; - private string _content = string.Empty; - private string _original = string.Empty; - private string _message = string.Empty; + private ElementReference _editorElement; + private ElementReference _toolBar; + private bool _filemanagervisible = false; + private FileManager _fileManager; + private string _richhtml = string.Empty; + private string _originalrichhtml = string.Empty; + private string _rawhtml = string.Empty; + private string _originalrawhtml = string.Empty; + private string _message = string.Empty; - [Parameter] - public string Content { get; set; } + [Parameter] + public string Content { get; set; } - [Parameter] - public bool ReadOnly { get; set; } = false; + [Parameter] + public bool ReadOnly { get; set; } = false; - [Parameter] - public string Placeholder { get; set; } = "Enter Your Content..."; + [Parameter] + public string Placeholder { get; set; } = "Enter Your Content..."; - // parameters only applicable to rich text editor - [Parameter] - public RenderFragment ToolbarContent { get; set; } + // parameters only applicable to rich text editor + [Parameter] + public RenderFragment ToolbarContent { get; set; } - [Parameter] - public string Theme { get; set; } = "snow"; + [Parameter] + public string Theme { get; set; } = "snow"; - [Parameter] - public string DebugLevel { get; set; } = "info"; + [Parameter] + public string DebugLevel { get; set; } = "info"; - [Parameter] - public bool AllowFileManagement { get; set; } = true; + [Parameter] + public bool AllowFileManagement { get; set; } = true; - public override List Resources => new List() + public override List Resources => new List() { new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" }, new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" }, new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" } }; - protected override async Task OnParametersSetAsync() - { - _content = Content; // raw HTML - await RefreshRichText(); - } + protected override void OnParametersSet() + { + _richhtml = Content; + _rawhtml = Content; + _originalrawhtml = _rawhtml; // preserve for comparison later + } - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await base.OnAfterRenderAsync(firstRender); + + var interop = new RichTextEditorInterop(JSRuntime); + + if (firstRender) + { + await interop.CreateEditor( + _editorElement, + _toolBar, + ReadOnly, + Placeholder, + Theme, + DebugLevel); + + await interop.LoadEditorContent(_editorElement, _richhtml); + + // preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor) + _originalrichhtml = await interop.GetHtml(_editorElement); + } + else + { + await interop.LoadEditorContent(_editorElement, _richhtml); + } + } + + public void CloseFileManager() + { + _filemanagervisible = false; + _message = string.Empty; + StateHasChanged(); + } + + public void RefreshRichText() + { + _richhtml = _rawhtml; + StateHasChanged(); + } + + public async Task RefreshRawHtml() + { + var interop = new RichTextEditorInterop(JSRuntime); + _rawhtml = await interop.GetHtml(_editorElement); + StateHasChanged(); + } + + public async Task GetHtml() + { + // evaluate raw html content as first priority + if (_rawhtml != _originalrawhtml) + { + return _rawhtml; + } + else + { + // return rich text content if it has changed var interop = new RichTextEditorInterop(JSRuntime); - - await base.OnAfterRenderAsync(firstRender); - - await interop.CreateEditor( - _editorElement, - _toolBar, - ReadOnly, - Placeholder, - Theme, - DebugLevel); - - await interop.LoadEditorContent(_editorElement, Content); - - _content = Content; // raw HTML - - // preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor ) - _original = await interop.GetHtml(_editorElement); - } - } - - public void CloseFileManager() - { - _filemanagervisible = false; - _message = string.Empty; - StateHasChanged(); - } - - public async Task RefreshRichText() - { - var interop = new RichTextEditorInterop(JSRuntime); - await interop.LoadEditorContent(_editorElement, _content); - } - - public async Task RefreshRawHtml() - { - var interop = new RichTextEditorInterop(JSRuntime); - _content = await interop.GetHtml(_editorElement); - StateHasChanged(); - } - - public async Task GetHtml() - { - // get rich text content - var interop = new RichTextEditorInterop(JSRuntime); - string content = await interop.GetHtml(_editorElement); - - if (_original != content) - { - // rich text content has changed - return it - return content; - } - else - { - // return raw html content - return _content; - } + var richhtml = await interop.GetHtml(_editorElement); + if (richhtml != _originalrichhtml) + { + return richhtml; + } + else + { + // return original raw html content + return _originalrawhtml; + } + } } public async Task InsertImage() @@ -212,23 +223,4 @@ } StateHasChanged(); } - - // other rich text editor methods which can be used by developers - public async Task GetText() - { - var interop = new RichTextEditorInterop(JSRuntime); - return await interop.GetText(_editorElement); - } - - public async Task GetContent() - { - var interop = new RichTextEditorInterop(JSRuntime); - return await interop.GetContent(_editorElement); - } - - public async Task EnableEditor(bool mode) - { - var interop = new RichTextEditorInterop(JSRuntime); - await interop.EnableEditor(_editorElement, mode); - } } diff --git a/Oqtane.Client/Modules/HtmlText/Edit.razor b/Oqtane.Client/Modules/HtmlText/Edit.razor index 528cafef..ca86ea95 100644 --- a/Oqtane.Client/Modules/HtmlText/Edit.razor +++ b/Oqtane.Client/Modules/HtmlText/Edit.razor @@ -9,95 +9,186 @@ @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer -@if (_content != null) -{ - - - @SharedLocalizer["Cancel"] - @if (!string.IsNullOrEmpty(_content)) - { -
-
- - } -} + + + @if (_content != null) + { + +
+ + @SharedLocalizer["Cancel"] + @if (!string.IsNullOrEmpty(_content)) + { +
+
+ + } + } +
+ + +
+   +   +   + @SharedLocalizer["CreatedOn"] + @SharedLocalizer["CreatedBy"] +
+ + + + + @context.CreatedOn + @context.CreatedBy + +
+ @((MarkupString)_view) +
+
@code { - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; - public override string Title => "Edit Html/Text"; + public override string Title => "Edit Html/Text"; - public override List Resources => new List() -{ + public override List Resources => new List() + { new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" } }; - private RichTextEditor RichTextEditorHtml; - private bool _allowfilemanagement; - private string _content = null; - private string _createdby; - private DateTime _createdon; - private string _modifiedby; - private DateTime _modifiedon; + private RichTextEditor RichTextEditorHtml; + private bool _allowfilemanagement; + private string _content = null; + private string _createdby; + private DateTime _createdon; + private string _modifiedby; + private DateTime _modifiedon; + private List _htmltexts; + private string _view = ""; - protected override async Task OnInitializedAsync() - { - try - { - _allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true")); + protected override async Task OnInitializedAsync() + { + try + { + _allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true")); + await LoadContent(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Content {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error); + } + } - var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); - if (htmltext != null) - { - _content = htmltext.Content; - _content = Utilities.FormatContent(_content, PageState.Alias, "render"); - _createdby = htmltext.CreatedBy; - _createdon = htmltext.CreatedOn; - _modifiedby = htmltext.ModifiedBy; - _modifiedon = htmltext.ModifiedOn; - } - else - { - _content = string.Empty; - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Content {Error}", ex.Message); - AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error); - } - } + private async Task LoadContent() + { + var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); + if (htmltext != null) + { + _content = htmltext.Content; + _content = Utilities.FormatContent(_content, PageState.Alias, "render"); + _createdby = htmltext.CreatedBy; + _createdon = htmltext.CreatedOn; + _modifiedby = htmltext.ModifiedBy; + _modifiedon = htmltext.ModifiedOn; + } + else + { + _content = string.Empty; + } - private async Task SaveContent() - { - string content = await RichTextEditorHtml.GetHtml(); - content = Utilities.FormatContent(content, PageState.Alias, "save"); + _htmltexts = await HtmlTextService.GetHtmlTextsAsync(ModuleState.ModuleId); + _htmltexts = _htmltexts.OrderByDescending(item => item.CreatedOn).ToList(); - try - { - var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); - if (htmltext != null) - { - htmltext.Content = content; - await HtmlTextService.UpdateHtmlTextAsync(htmltext); - } - else - { - htmltext = new HtmlText(); - htmltext.ModuleId = ModuleState.ModuleId; - htmltext.Content = content; - await HtmlTextService.AddHtmlTextAsync(htmltext); - } + _view = ""; + } - await logger.LogInformation("Content Saved {HtmlText}", htmltext); - NavigationManager.NavigateTo(NavigateUrl()); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Saving Content {Error}", ex.Message); - AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error); - } - } + private async Task SaveContent() + { + string content = await RichTextEditorHtml.GetHtml(); + content = Utilities.FormatContent(content, PageState.Alias, "save"); + + try + { + var htmltext = new HtmlText(); + htmltext.ModuleId = ModuleState.ModuleId; + htmltext.Content = content; + await HtmlTextService.AddHtmlTextAsync(htmltext); + + await logger.LogInformation("Content Saved {HtmlText}", htmltext); + NavigationManager.NavigateTo(NavigateUrl()); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Saving Content {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error); + } + } + + private async Task View(Models.HtmlText htmltext) + { + try + { + htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId); + if (htmltext != null) + { + _view = htmltext.Content; + _view = Utilities.FormatContent(_view, PageState.Alias, "render"); + StateHasChanged(); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Content.View"], MessageType.Error); + } + } + + private async Task Restore(Models.HtmlText htmltext) + { + try + { + htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId); + if (htmltext != null) + { + var content = htmltext.Content; + htmltext = new HtmlText(); + htmltext.ModuleId = ModuleState.ModuleId; + htmltext.Content = content; + await HtmlTextService.AddHtmlTextAsync(htmltext); + await logger.LogInformation("Content Restored {HtmlText}", htmltext); + AddModuleMessage(Localizer["Message.Content.Restored"], MessageType.Success); + await LoadContent(); + StateHasChanged(); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Content.Restore"], MessageType.Error); + } + } + + private async Task Delete(Models.HtmlText htmltext) + { + try + { + htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId); + if (htmltext != null) + { + await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId); + await logger.LogInformation("Content Deleted {HtmlText}", htmltext); + AddModuleMessage(Localizer["Message.Content.Deleted"], MessageType.Success); + await LoadContent(); + StateHasChanged(); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Content.Delete"], MessageType.Error); + } + } } diff --git a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs index 85583f7e..e4dd0174 100644 --- a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs +++ b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Oqtane.Documentation; @@ -13,24 +15,29 @@ namespace Oqtane.Modules.HtmlText.Services private string ApiUrl => CreateApiUrl("HtmlText"); + public async Task> GetHtmlTextsAsync(int moduleId) + { + return await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{ApiUrl}?moduleid={moduleId}", EntityNames.Module, moduleId)); + } + public async Task GetHtmlTextAsync(int moduleId) { return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId)); } + public async Task GetHtmlTextAsync(int htmlTextId, int moduleId) + { + return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId)); + } + public async Task AddHtmlTextAsync(Models.HtmlText htmlText) { await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText); } - public async Task UpdateHtmlTextAsync(Models.HtmlText htmlText) + public async Task DeleteHtmlTextAsync(int htmlTextId, int moduleId) { - await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", EntityNames.Module, htmlText.ModuleId), htmlText); - } - - public async Task DeleteHtmlTextAsync(int moduleId) - { - await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId)); + await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId)); } } } diff --git a/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs index 80d725a9..7ca069c6 100644 --- a/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs +++ b/Oqtane.Client/Modules/HtmlText/Services/IHtmlTextService.cs @@ -1,19 +1,20 @@ using System.Collections.Generic; using System.Threading.Tasks; using Oqtane.Documentation; -using Oqtane.Modules.HtmlText.Models; namespace Oqtane.Modules.HtmlText.Services { [PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")] public interface IHtmlTextService { - Task GetHtmlTextAsync(int ModuleId); + Task> GetHtmlTextsAsync(int moduleId); + + Task GetHtmlTextAsync(int moduleId); + + Task GetHtmlTextAsync(int htmlTextId, int moduleId); Task AddHtmlTextAsync(Models.HtmlText htmltext); - Task UpdateHtmlTextAsync(Models.HtmlText htmltext); - - Task DeleteHtmlTextAsync(int ModuleId); + Task DeleteHtmlTextAsync(int htmlTextId, int moduleId); } } diff --git a/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx index b29a4f1e..71c3f04f 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx @@ -231,4 +231,10 @@ A page with path {0} already exists for the selected parent page in the Recycle Bin. Either recover the page or remove from the Recycle Bin and create it again. + + Optionally enter meta tags (in exactly the form you want them to be included in the page output). + + + Meta: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx index ad6dfd25..5dc82a55 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx @@ -264,4 +264,10 @@ Clickable? + + Optionally enter meta tags (in exactly the form you want them to be included in the page output). + + + Meta: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx b/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx index e2eed7a2..5e1d2160 100644 --- a/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx +++ b/Oqtane.Client/Resources/Modules/HtmlText/Edit.resx @@ -117,10 +117,52 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Are You Sure You Wish To Delete The {0} Version? + + + Are You Sure You Wish To Restore The {0} Version? + + + Created By + + + Created On + + + Delete Version + + + Delete + + + Error Deleting Version + An Error Occurred Loading Content + + Error Restoring Version + An Error Occurred Saving Content + + Error Viewing Version + + + Version Deleted + + + Version Restored + + + Restore Version + + + Restore + + + View + \ No newline at end of file diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index cd5bb63a..d8693bd2 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -17,18 +17,17 @@ using Oqtane.Infrastructure; using Oqtane.Modules; using Oqtane.Repository; using Oqtane.Security; -using Oqtane.Services; using Oqtane.Shared; namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime, string[] supportedCultures) + public static IServiceCollection AddOqtane(this IServiceCollection services, string[] supportedCultures) { LoadAssemblies(); LoadSatelliteAssemblies(supportedCultures); - services.AddOqtaneServices(runtime); + services.AddOqtaneServices(); return services; } @@ -190,7 +189,7 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - private static IServiceCollection AddOqtaneServices(this IServiceCollection services, Runtime runtime) + private static IServiceCollection AddOqtaneServices(this IServiceCollection services) { if (services is null) { @@ -229,14 +228,6 @@ namespace Microsoft.Extensions.DependencyInjection { startup.ConfigureServices(services); } - - if (runtime == Runtime.Server) - { - // register client startup services if running on server - assembly.GetInstances() - .ToList() - .ForEach(x => x.ConfigureServices(services)); - } } return services; } diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index cad82ac9..df58e73a 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -28,14 +28,14 @@ namespace Oqtane.Infrastructure { public class DatabaseManager : IDatabaseManager { - private readonly IConfigurationRoot _config; + private readonly IConfigManager _config; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IWebHostEnvironment _environment; private readonly IMemoryCache _cache; private readonly IConfigManager _configManager; private readonly ILogger _filelogger; - public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger filelogger) + public DatabaseManager(IConfigManager config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger filelogger) { _config = config; _serviceScopeFactory = serviceScopeFactory; diff --git a/Oqtane.Server/Infrastructure/InstallationManager.cs b/Oqtane.Server/Infrastructure/InstallationManager.cs index 22a8176d..41860c5e 100644 --- a/Oqtane.Server/Infrastructure/InstallationManager.cs +++ b/Oqtane.Server/Infrastructure/InstallationManager.cs @@ -125,6 +125,9 @@ namespace Oqtane.Infrastructure case "ref": // ref/net*/... filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2); break; + case "refs": // refs/net*/... + filename = ExtractFile(entry, Path.Combine(binPath, "refs"), 2); + break; } if (filename != "") diff --git a/Oqtane.Server/Infrastructure/LogManager.cs b/Oqtane.Server/Infrastructure/LogManager.cs index afbb1de8..e8f58854 100644 --- a/Oqtane.Server/Infrastructure/LogManager.cs +++ b/Oqtane.Server/Infrastructure/LogManager.cs @@ -14,18 +14,18 @@ namespace Oqtane.Infrastructure public class LogManager : ILogManager { private readonly ILogRepository _logs; - private readonly IConfigurationRoot _config; + private readonly ITenantManager _tenantManager; + private readonly IConfigManager _config; private readonly IUserPermissions _userPermissions; private readonly IHttpContextAccessor _accessor; - private readonly Alias _alias; - public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor) + public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigManager config, IUserPermissions userPermissions, IHttpContextAccessor accessor) { _logs = logs; + _tenantManager = tenantManager; _config = config; _userPermissions = userPermissions; _accessor = accessor; - _alias = tenantManager.GetAlias(); } public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args) @@ -48,9 +48,13 @@ namespace Oqtane.Infrastructure Log log = new Log(); log.SiteId = siteId; - if (log.SiteId == -1 && _alias != null) + if (log.SiteId == -1) { - log.SiteId = _alias.SiteId; + var alias = _tenantManager.GetAlias(); + if (alias != null) + { + log.SiteId = alias.SiteId; + } } if (log.SiteId == -1) return; // logs must be site specific diff --git a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs index 189a44c9..9a748d96 100644 --- a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs +++ b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; namespace Oqtane.Infrastructure { @@ -16,8 +15,8 @@ namespace Oqtane.Infrastructure public async Task Invoke(HttpContext context) { // check if framework is installed - var config = context.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration; - if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection"))) + var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager; + if (config.IsInstalled()) { // get alias var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager; diff --git a/Oqtane.Server/Migrations/Tenant/03000104_AddVisitorReferrer.cs b/Oqtane.Server/Migrations/Tenant/03000105_AddVisitorReferrer.cs similarity index 100% rename from Oqtane.Server/Migrations/Tenant/03000104_AddVisitorReferrer.cs rename to Oqtane.Server/Migrations/Tenant/03000105_AddVisitorReferrer.cs diff --git a/Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs b/Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs new file mode 100644 index 00000000..9dea0d49 --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/03000301_AddMetaToPage.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.03.00.03.01")] + public class AddPageMeta : MultiDatabaseMigration + { + public AddPageMeta(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); + pageEntityBuilder.AddStringColumn("Meta", 2000, true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); + pageEntityBuilder.DropColumn("Meta"); + } + } +} diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs index 020d6e48..f269650b 100644 --- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs +++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs @@ -8,6 +8,8 @@ using Oqtane.Infrastructure; using Oqtane.Controllers; using System.Net; using Oqtane.Documentation; +using System.Collections.Generic; +using System.Linq; namespace Oqtane.Modules.HtmlText.Controllers { @@ -22,18 +24,60 @@ namespace Oqtane.Modules.HtmlText.Controllers _htmlText = htmlText; } - // GET api//5 - [HttpGet("{id}")] - [Authorize(Policy = PolicyNames.ViewModule)] - public Models.HtmlText Get(int id) + // GET: api/?moduleid=x + [HttpGet] + [Authorize(Roles = RoleNames.Registered)] + public IEnumerable Get(string moduleId) { - if (AuthEntityId(EntityNames.Module) == id) + if (int.TryParse(moduleId, out int ModuleId) && AuthEntityId(EntityNames.Module) == ModuleId) + { + return _htmlText.GetHtmlTexts(ModuleId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {ModuleId}", moduleId); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } + + // GET api//5 + [HttpGet("{moduleid}")] + [Authorize(Policy = PolicyNames.ViewModule)] + public Models.HtmlText Get(int moduleId) + { + if (AuthEntityId(EntityNames.Module) == moduleId) + { + var htmltexts = _htmlText.GetHtmlTexts(moduleId); + if (htmltexts != null && htmltexts.Any()) + { + return htmltexts.OrderByDescending(item => item.CreatedOn).First(); + } + else + { + return null; + } + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {ModuleId}", moduleId); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } + + // GET api//5/6 + [HttpGet("{id}/{moduleid}")] + [Authorize(Policy = PolicyNames.ViewModule)] + public Models.HtmlText Get(int id, int moduleId) + { + if (AuthEntityId(EntityNames.Module) == moduleId) { return _htmlText.GetHtmlText(id); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Get Attempt {ModuleId}", id); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Get Attempt {HtmlTextId}", id); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } @@ -53,27 +97,7 @@ namespace Oqtane.Modules.HtmlText.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Post Attempt {HtmlText}", htmlText); - HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; - return null; - } - } - - // PUT api//5 - [ValidateAntiForgeryToken] - [HttpPut("{id}")] - [Authorize(Policy = PolicyNames.EditModule)] - public Models.HtmlText Put(int id, [FromBody] Models.HtmlText htmlText) - { - if (ModelState.IsValid && AuthEntityId(EntityNames.Module) == htmlText.ModuleId) - { - htmlText = _htmlText.UpdateHtmlText(htmlText); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Html/Text Updated {HtmlText}", htmlText); - return htmlText; - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Put Attempt {HtmlText}", htmlText); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Post Attempt {HtmlText}", htmlText); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } @@ -81,18 +105,18 @@ namespace Oqtane.Modules.HtmlText.Controllers // DELETE api//5 [ValidateAntiForgeryToken] - [HttpDelete("{id}")] + [HttpDelete("{id}/{moduleid}")] [Authorize(Policy = PolicyNames.EditModule)] - public void Delete(int id) + public void Delete(int id, int moduleId) { - if (AuthEntityId(EntityNames.Module) == id) + if (AuthEntityId(EntityNames.Module) == moduleId) { _htmlText.DeleteHtmlText(id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Html/Text Deleted {HtmlTextId}", id); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HtmlText Delete Attempt {ModuleId}", id); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Html/Text Delete Attempt {HtmlTextId}", id); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } diff --git a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs index f9a862e8..6179c40c 100644 --- a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs +++ b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs @@ -43,19 +43,10 @@ namespace Oqtane.Modules.HtmlText.Manager public void ImportModule(Module module, string content, string version) { content = WebUtility.HtmlDecode(content); - var htmlText = _htmlText.GetHtmlText(module.ModuleId); - if (htmlText != null) - { - htmlText.Content = content; - _htmlText.UpdateHtmlText(htmlText); - } - else - { - htmlText = new Models.HtmlText(); - htmlText.ModuleId = module.ModuleId; - htmlText.Content = content; - _htmlText.AddHtmlText(htmlText); - } + var htmlText = new Models.HtmlText(); + htmlText.ModuleId = module.ModuleId; + htmlText.Content = content; + _htmlText.AddHtmlText(htmlText); } public bool Install(Tenant tenant, string version) diff --git a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs index a2229f0e..6f6d8e6d 100644 --- a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs +++ b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using System.Linq; using Oqtane.Modules.HtmlText.Models; using Oqtane.Documentation; +using System.Collections.Generic; namespace Oqtane.Modules.HtmlText.Repository { @@ -15,11 +16,15 @@ namespace Oqtane.Modules.HtmlText.Repository _db = context; } - public Models.HtmlText GetHtmlText(int moduleId) + public IEnumerable GetHtmlTexts(int moduleId) { - return _db.HtmlText.FirstOrDefault(item => item.ModuleId == moduleId); + return _db.HtmlText.Where(item => item.ModuleId == moduleId); } + public Models.HtmlText GetHtmlText(int htmlTextId) + { + return _db.HtmlText.Find(htmlTextId); + } public Models.HtmlText AddHtmlText(Models.HtmlText htmlText) { @@ -28,16 +33,9 @@ namespace Oqtane.Modules.HtmlText.Repository return htmlText; } - public Models.HtmlText UpdateHtmlText(Models.HtmlText htmlText) + public void DeleteHtmlText(int htmlTextId) { - _db.Entry(htmlText).State = EntityState.Modified; - _db.SaveChanges(); - return htmlText; - } - - public void DeleteHtmlText(int moduleId) - { - Models.HtmlText htmlText = _db.HtmlText.FirstOrDefault(item => item.ModuleId == moduleId); + Models.HtmlText htmlText = _db.HtmlText.FirstOrDefault(item => item.HtmlTextId == htmlTextId); if (htmlText != null) _db.HtmlText.Remove(htmlText); _db.SaveChanges(); } diff --git a/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs b/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs index 014c5adc..44be5973 100644 --- a/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs +++ b/Oqtane.Server/Modules/HtmlText/Repository/IHtmlTextRepository.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Oqtane.Documentation; using Oqtane.Modules.HtmlText.Models; @@ -6,9 +7,9 @@ namespace Oqtane.Modules.HtmlText.Repository [PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")] public interface IHtmlTextRepository { - Models.HtmlText GetHtmlText(int moduleId); + IEnumerable GetHtmlTexts(int moduleId); + Models.HtmlText GetHtmlText(int htmlTextId); Models.HtmlText AddHtmlText(Models.HtmlText htmlText); - Models.HtmlText UpdateHtmlText(Models.HtmlText htmlText); - void DeleteHtmlText(int moduleId); + void DeleteHtmlText(int htmlTextId); } } diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index 86827eba..4b56af10 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -8,6 +8,7 @@ @Model.Title + @Html.Raw(@Model.Meta) @if (!string.IsNullOrEmpty(Model.PWAScript)) @@ -20,34 +21,42 @@ @Html.Raw(Model.HeadResources) - @(Html.AntiForgeryToken()) - - -
- - An error has occurred. This application may no longer respond until reloaded. - - - An unhandled exception has occurred. See browser dev tools for details. - - Reload - 🗙 -
- - - - @if (Model.Runtime == "WebAssembly") - { - - } - else - { - - } - @if (!string.IsNullOrEmpty(Model.PWAScript)) + @if (string.IsNullOrEmpty(Model.Message)) { - @Html.Raw(Model.PWAScript) + @(Html.AntiForgeryToken()) + + + +
+ + An error has occurred. This application may no longer respond until reloaded. + + + An unhandled exception has occurred. See browser dev tools for details. + + Reload + 🗙 +
+ + + + @if (Model.Runtime == "WebAssembly") + { + + } + else + { + + } + @if (!string.IsNullOrEmpty(Model.PWAScript)) + { + @Html.Raw(Model.PWAScript) + } + @Html.Raw(Model.BodyResources) + } + else + { +
@Model.Message
} - @Html.Raw(Model.BodyResources) diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 1c6259b8..7c76e354 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -25,7 +25,7 @@ namespace Oqtane.Pages { public class HostModel : PageModel { - private IConfiguration _configuration; + private IConfigManager _configuration; private readonly ITenantManager _tenantManager; private readonly ILocalizationManager _localizationManager; private readonly ILanguageRepository _languages; @@ -38,7 +38,7 @@ namespace Oqtane.Pages private readonly ISettingRepository _settings; 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; _tenantManager = tenantManager; @@ -63,9 +63,11 @@ namespace Oqtane.Pages public string HeadResources = ""; public string BodyResources = ""; public string Title = ""; + public string Meta = ""; public string FavIcon = "favicon.ico"; public string PWAScript = ""; public string ThemeType = ""; + public string Message = ""; public IActionResult OnGet() { @@ -83,7 +85,7 @@ namespace Oqtane.Pages } // if framework is installed - if (!string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) + if (_configuration.IsInstalled()) { var alias = _tenantManager.GetAlias(); if (alias != null) @@ -108,7 +110,7 @@ namespace Oqtane.Pages } var site = _sites.GetSite(alias.SiteId); - if (site != null) + if (site != null && !site.IsDeleted) { Route route = new Route(url, alias.Path); @@ -148,6 +150,7 @@ namespace Oqtane.Pages { Title = Title + " - " + page.Name; } + Meta = page.Meta; // include theme resources if (!string.IsNullOrEmpty(page.ThemeType)) @@ -165,42 +168,50 @@ namespace Oqtane.Pages return RedirectPermanent(url); } } - } - // include global resources - var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); - 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()) + // include global resources + var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); + foreach (Assembly assembly in assemblies) { - // use default language if specified otherwise use first language in collection - culture = (languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First()).Code; + ProcessHostResources(assembly); + ProcessModuleControls(assembly); + ProcessThemeControls(assembly); } - 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=", ""); + // 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 + 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(); diff --git a/Oqtane.Server/Repository/Context/MasterDBContext.cs b/Oqtane.Server/Repository/Context/MasterDBContext.cs index 58b80d59..d607749d 100644 --- a/Oqtane.Server/Repository/Context/MasterDBContext.cs +++ b/Oqtane.Server/Repository/Context/MasterDBContext.cs @@ -1,19 +1,16 @@ using System; -using System.Collections.Generic; -using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Migrations; using Oqtane.Models; -using Microsoft.Extensions.Configuration; using Oqtane.Databases.Interfaces; using Oqtane.Extensions; -using Oqtane.Interfaces; using Oqtane.Migrations.Framework; using Oqtane.Repository.Databases.Interfaces; using Oqtane.Shared; using System.Threading.Tasks; using System.Threading; +using Oqtane.Infrastructure; // ReSharper disable BuiltInTypeReferenceStyleForMemberAccess // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -24,14 +21,14 @@ namespace Oqtane.Repository public class MasterDBContext : DbContext, IMultiDatabase { private readonly IHttpContextAccessor _accessor; - private readonly IConfiguration _configuration; + private readonly IConfigManager _config; private string _connectionString; private string _databaseType; - public MasterDBContext(DbContextOptions options, IHttpContextAccessor accessor, IConfiguration configuration) : base(options) + public MasterDBContext(DbContextOptions options, IHttpContextAccessor accessor, IConfigManager config) : base(options) { _accessor = accessor; - _configuration = configuration; + _config = config; } public IDatabase ActiveDatabase { get; private set; } @@ -40,15 +37,15 @@ namespace Oqtane.Repository { optionsBuilder.ReplaceService(); - 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()); } - _databaseType = _configuration.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey]; + _databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey]; } if (!String.IsNullOrEmpty(_databaseType)) diff --git a/Oqtane.Server/Security/PrincipalValidator.cs b/Oqtane.Server/Security/PrincipalValidator.cs index 170e20ff..46f9f3c7 100644 --- a/Oqtane.Server/Security/PrincipalValidator.cs +++ b/Oqtane.Server/Security/PrincipalValidator.cs @@ -6,7 +6,6 @@ using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Models; using System.Collections.Generic; -using Microsoft.Extensions.Configuration; namespace Oqtane.Security { @@ -17,8 +16,8 @@ namespace Oqtane.Security if (context != null && context.Principal.Identity.IsAuthenticated) { // check if framework is installed - var config = context.HttpContext.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration; - if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection"))) + var config = context.HttpContext.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager; + if (config.IsInstalled()) { var tenantManager = context.HttpContext.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager; var alias = tenantManager.GetAlias(); diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index eb6a26a2..83cb5a6a 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -21,7 +21,6 @@ namespace Oqtane { public class Startup { - private readonly Runtime _runtime; private readonly bool _useSwagger; private readonly IWebHostEnvironment _env; private readonly string[] _supportedCultures; @@ -36,7 +35,6 @@ namespace Oqtane Configuration = builder.Build(); _supportedCultures = localizationManager.GetSupportedCultures(); - _runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server; //add possibility to switch off swagger on production. _useSwagger = Configuration.GetSection("UseSwagger").Value != "false"; @@ -115,7 +113,7 @@ namespace Oqtane services.AddOqtaneTransientServices(); // load the external assemblies into the app domain, install services - services.AddOqtane(_runtime, _supportedCultures); + services.AddOqtane(_supportedCultures); services.AddOqtaneDbContext(); services.AddMvc() diff --git a/Oqtane.Shared/Models/Page.cs b/Oqtane.Shared/Models/Page.cs index e11661f1..ff2fdfc3 100644 --- a/Oqtane.Shared/Models/Page.cs +++ b/Oqtane.Shared/Models/Page.cs @@ -61,7 +61,12 @@ namespace Oqtane.Models /// Reference to a Container which will be used for modules on this page. /// public string DefaultContainerType { get; set; } - + + /// + /// Meta tags to be included in the head of the page + /// + public string Meta { get; set; } + /// /// Icon file for this page. /// TODO: unclear what this is for, and what icon library is used. Probably FontAwesome?