From cbcec0481a0ec80b1b7a2cfa829c1876b2d3f799 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 24 May 2020 19:12:47 -0700 Subject: [PATCH 01/16] removed "Select Container, Theme, Layout" options --- Oqtane.Client/Modules/Admin/Site/Index.razor | 3 --- 1 file changed, 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 3f3425f6..69a2bbfa 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -56,7 +56,6 @@ - @foreach (KeyValuePair panelayout in _panelayouts) { @@ -91,7 +89,6 @@ - - - - - - + + @foreach (KeyValuePair panelayout in _panelayouts) { - + if (panelayout.Key == _layouttype) + { + + } + else + { + + } } - else - { - - } - } - - - + + + + } @@ -199,8 +202,8 @@ Cancel @code { - private Dictionary _themes; - private Dictionary _panelayouts; + private Dictionary _themes = new Dictionary(); + private Dictionary _panelayouts = new Dictionary(); private Dictionary _containers = new Dictionary(); private List _themeList; private List _pageList; @@ -233,9 +236,6 @@ _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); _themes = ThemeService.GetThemeTypes(_themeList); - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); - _containers = ThemeService.GetContainerTypes(_themeList); - _permissions = string.Empty; } catch (Exception ex) @@ -288,11 +288,15 @@ if (_themetype != "-") { _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); + _containers = ThemeService.GetContainerTypes(_themeList, _themetype); } else { _panelayouts = new Dictionary(); + _containers = new Dictionary(); } + _layouttype = "-"; + _containertype = "-"; StateHasChanged(); } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index b25f6b2e..4c399950 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -127,27 +127,30 @@ - - - - - - + + @foreach (KeyValuePair panelayout in _panelayouts) { - + if (panelayout.Key == _layouttype) + { + + } + else + { + + } } - else - { - - } - } - - - + + + + } @@ -212,8 +215,8 @@ Cancel @code { - private Dictionary _themes; - private Dictionary _panelayouts; + private Dictionary _themes = new Dictionary(); + private Dictionary _panelayouts = new Dictionary(); private Dictionary _containers = new Dictionary(); private List _themeList; private List _pageList; @@ -257,7 +260,6 @@ _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); _themes = ThemeService.GetThemeTypes(_themeList); - _containers = ThemeService.GetContainerTypes(_themeList); _pageId = Int32.Parse(PageState.QueryString["id"]); var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId); @@ -291,12 +293,13 @@ { _themetype = "-"; } - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); + _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, page.ThemeType); _layouttype = page.LayoutType; if (_layouttype == PageState.Site.DefaultLayoutType) { _layouttype = "-"; } + _containers = ThemeService.GetContainerTypes(_themeList, page.ThemeType); _containertype = page.DefaultContainerType; if (string.IsNullOrEmpty(_containertype)) { @@ -370,11 +373,15 @@ if (_themetype != "-") { _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); + _containers = ThemeService.GetContainerTypes(_themeList, _themetype); } else { _panelayouts = new Dictionary(); + _containers = new Dictionary(); } + _layouttype = "-"; + _containertype = "-"; StateHasChanged(); } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 69a2bbfa..0f271b7a 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -56,6 +56,7 @@ - - - - - - - - + @if (_panelayouts.Count > 0) + { + + + + + + + + + } - + @foreach (KeyValuePair item in _themes) { @@ -46,27 +46,30 @@ else - - - - - - - - + @if (_panelayouts.Count > 0) + { + + + + + + + + + } - + @foreach (SiteTemplate siteTemplate in _siteTemplates) { @@ -218,10 +221,10 @@ else private string _name = string.Empty; private string _urls = string.Empty; - private string _themetype = string.Empty; - private string _layouttype = string.Empty; - private string _containertype = string.Empty; - private string _sitetemplatetype = string.Empty; + private string _themetype = "-"; + private string _layouttype = "-"; + private string _containertype = "-"; + private string _sitetemplatetype = "-"; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; @@ -231,7 +234,6 @@ else _tenants = await TenantService.GetTenantsAsync(); _urls = PageState.Alias.Name; _themes = ThemeService.GetThemeTypes(_themeList); - _containers = ThemeService.GetContainerTypes(_themeList); _siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync(); } @@ -266,12 +268,15 @@ else if (_themetype != string.Empty) { _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); + _containers = ThemeService.GetContainerTypes(_themeList, _themetype); } else { _panelayouts = new Dictionary(); + _containers = new Dictionary(); } - + _layouttype = "-"; + _containertype = "-"; StateHasChanged(); } catch (Exception ex) @@ -283,7 +288,7 @@ else private async Task SaveSite() { - if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)) && !string.IsNullOrEmpty(_containertype) && !string.IsNullOrEmpty(_sitetemplatetype)) + if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && (_panelayouts.Count == 0 || _layouttype != "-") && _containertype != "-" && _sitetemplatetype != "-") { var duplicates = new List(); var aliases = await AliasService.GetAliasesAsync(); diff --git a/Oqtane.Client/Modules/Admin/Sites/Edit.razor b/Oqtane.Client/Modules/Admin/Sites/Edit.razor index 698892a7..75e6133f 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Edit.razor @@ -39,7 +39,7 @@ - - - - - - - - + @if (_panelayouts.Count > 0) + { + + + + + + + + + } -
-
- - + @if (_pane.Length > 1) + { +
+
+ + +
-
+ }
@@ -244,47 +246,41 @@ } } + protected string Pane + { + get => _pane; + private set + { + if (_pane != value) + { + _pane = value; + _ = UpdateSettingsAsync(); + } + } + } + + protected string Description { get; private set; } = ""; - protected string Pane { get; private set; } = ""; + protected string Title { get; private set; } = ""; protected string ContainerType { get; private set; } = ""; protected string Message { get; private set; } = ""; [Parameter] - public string ButtonClass { get; set; } + public string ButtonClass { get; set; } = "btn-outline-secondary"; [Parameter] - public string CardClass { get; set; } + public string CardClass { get; set; } = "card border-secondary mb-3"; [Parameter] - public string HeaderClass { get; set; } + public string HeaderClass { get; set; } = "card-header"; [Parameter] - public string BodyClass { get; set; } + public string BodyClass { get; set; } = "card-body"; protected override async Task OnInitializedAsync() { - if (string.IsNullOrEmpty(ButtonClass)) - { - ButtonClass = "btn-outline-secondary"; - } - - if (string.IsNullOrEmpty(CardClass)) - { - CardClass = "card border-secondary mb-3"; - } - - if (string.IsNullOrEmpty(HeaderClass)) - { - HeaderClass = "card-header"; - } - - if (string.IsNullOrEmpty(BodyClass)) - { - BodyClass = "card-body"; - } - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions)) { _pages?.Clear(); @@ -298,15 +294,11 @@ } await LoadSettingsAsync(); - var panes = PageState.Page.Panes; - Pane = panes.Count() == 1 ? panes.SingleOrDefault() : ""; var themes = await ThemeService.GetThemesAsync(); _containers = ThemeService.GetContainerTypes(themes, PageState.Page.ThemeType); ContainerType = PageState.Site.DefaultContainerType; - _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList(); - _categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList(); } } @@ -526,18 +518,24 @@ } } - private string settingName = "CP-category"; + private string settingCategory = "CP-category"; + private string settingPane = "CP-pane"; + private string _pane = ""; private async Task LoadSettingsAsync() { Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); - _category = SettingService.GetSetting(settings, settingName, "Common"); + _category = SettingService.GetSetting(settings, settingCategory, "Common"); + var pane = SettingService.GetSetting(settings, settingPane, ""); + _pane = PageState.Page.Panes.Contains(pane) ? pane : PageState.Page.Panes.FirstOrDefault(); } private async Task UpdateSettingsAsync() { Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); - SettingService.SetSetting(settings, settingName, _category); + SettingService.SetSetting(settings, settingCategory, _category); + SettingService.SetSetting(settings, settingPane, _pane); await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); } + } From 1b7ca45d4af428aedef01afe79bb86673aaa3ee8 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 1 Jun 2020 14:58:46 -0400 Subject: [PATCH 07/16] Added support for friendly names and thumbnails in theme, layout, and container components. Added fallback support during loading for themes, layout, and containers. --- .../Modules/Admin/Modules/Settings.razor | 8 ++-- Oqtane.Client/Modules/Admin/Pages/Add.razor | 40 ++++++++-------- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 44 ++++++++--------- Oqtane.Client/Modules/Admin/Site/Index.razor | 42 ++++++++-------- Oqtane.Client/Modules/Admin/Sites/Add.razor | 36 +++++++------- Oqtane.Client/Modules/Admin/Sites/Edit.razor | 42 ++++++++-------- .../Services/Interfaces/IThemeService.cs | 6 +-- Oqtane.Client/Services/ThemeService.cs | 44 ++++------------- Oqtane.Client/Themes/ContainerBase.cs | 2 + .../Themes/Controls/ControlPanel.razor | 8 ++-- Oqtane.Client/Themes/IContainerControl.cs | 2 + Oqtane.Client/Themes/ILayoutControl.cs | 4 +- Oqtane.Client/Themes/LayoutBase.cs | 2 + .../Themes/OqtaneTheme/Container.razor | 6 ++- .../Themes/OqtaneTheme/Default.razor | 2 + .../Themes/OqtaneTheme/MultiPane.razor | 4 +- .../Themes/OqtaneTheme/NoTitle.razor | 6 ++- .../Themes/OqtaneTheme/SinglePane.razor | 2 + Oqtane.Client/Themes/ThemeBase.cs | 2 + Oqtane.Client/UI/ContainerBuilder.razor | 15 ++---- Oqtane.Client/UI/PaneLayout.razor | 12 ++--- Oqtane.Client/UI/ThemeBuilder.razor | 15 ++---- Oqtane.Server/Repository/ThemeRepository.cs | 48 +++++++++++++------ Oqtane.Shared/Interfaces/IThemeControl.cs | 4 +- Oqtane.Shared/Models/Theme.cs | 16 +++++-- Oqtane.Shared/Models/ThemeControl.cs | 10 ++++ 26 files changed, 222 insertions(+), 200 deletions(-) create mode 100644 Oqtane.Shared/Models/ThemeControl.cs diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index 9216a0d5..5abb6fdf 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -25,9 +25,9 @@ @@ -85,7 +85,7 @@ Cancel @code { - private Dictionary _containers; + private List _containers = new List(); private string _title; private string _containerType; private string _allPages = "false"; @@ -105,7 +105,7 @@ protected override async Task OnInitializedAsync() { _title = ModuleState.Title; - _containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync(), PageState.Page.ThemeType); + _containers = ThemeService.GetContainerControls(await ThemeService.GetThemesAsync(), PageState.Page.ThemeType); _containerType = ModuleState.ContainerType; if (!string.IsNullOrEmpty(PageState.Page.DefaultContainerType) && _containerType == PageState.Page.DefaultContainerType) { diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index f5fb7a1a..2970d442 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -102,21 +102,21 @@ - @if (_panelayouts.Count > 0) + @if (_layouts.Count > 0) { @@ -125,15 +125,15 @@ @@ -147,9 +147,9 @@ @@ -202,10 +202,10 @@ Cancel @code { - private Dictionary _themes = new Dictionary(); - private Dictionary _panelayouts = new Dictionary(); - private Dictionary _containers = new Dictionary(); private List _themeList; + private List _themes = new List(); + private List _layouts = new List(); + private List _containers = new List(); private List _pageList; private string _name; private string _title; @@ -235,7 +235,7 @@ _pageList = PageState.Pages; _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); - _themes = ThemeService.GetThemeTypes(_themeList); + _themes = ThemeService.GetThemeControls(_themeList); _permissions = string.Empty; } catch (Exception ex) @@ -287,13 +287,13 @@ _themetype = (string)e.Value; if (_themetype != "-") { - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); } else { - _panelayouts = new Dictionary(); - _containers = new Dictionary(); + _layouts = new List(); + _containers = new List(); } _layouttype = "-"; _containertype = "-"; @@ -311,7 +311,7 @@ Page page = null; try { - if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype))) + if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || !string.IsNullOrEmpty(_layouttype))) { page = new Page(); page.SiteId = PageState.Page.SiteId; diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 4c399950..305420d5 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -113,21 +113,21 @@ - @if (_panelayouts.Count > 0) + @if (_layouts.Count > 0) { @@ -136,15 +136,15 @@ @@ -158,9 +158,9 @@ @@ -215,10 +215,10 @@ Cancel @code { - private Dictionary _themes = new Dictionary(); - private Dictionary _panelayouts = new Dictionary(); - private Dictionary _containers = new Dictionary(); private List _themeList; + private List _themes = new List(); + private List _layouts = new List(); + private List _containers = new List(); private List _pageList; private int _pageId; private string _name; @@ -255,11 +255,11 @@ { try { - _themeList = await ThemeService.GetThemesAsync(); _pageList = PageState.Pages; _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); - _themes = ThemeService.GetThemeTypes(_themeList); + _themeList = await ThemeService.GetThemesAsync(); + _themes = ThemeService.GetThemeControls(_themeList); _pageId = Int32.Parse(PageState.QueryString["id"]); var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId); @@ -293,13 +293,13 @@ { _themetype = "-"; } - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, page.ThemeType); + _layouts = ThemeService.GetLayoutControls(_themeList, page.ThemeType); _layouttype = page.LayoutType; if (_layouttype == PageState.Site.DefaultLayoutType) { _layouttype = "-"; } - _containers = ThemeService.GetContainerTypes(_themeList, page.ThemeType); + _containers = ThemeService.GetContainerControls(_themeList, page.ThemeType); _containertype = page.DefaultContainerType; if (string.IsNullOrEmpty(_containertype)) { @@ -372,13 +372,13 @@ _themetype = (string)e.Value; if (_themetype != "-") { - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); } else { - _panelayouts = new Dictionary(); - _containers = new Dictionary(); + _layouts = new List(); + _containers = new List(); } _layouttype = "-"; _containertype = "-"; diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 1d5ae583..9d4e4611 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -57,21 +57,21 @@ - @if (_panelayouts.Count > 0) + @if (_layouts.Count > 0) { @@ -80,9 +80,9 @@ @@ -95,9 +95,9 @@ @@ -211,10 +211,10 @@ } @code { - private Dictionary _themes = new Dictionary(); - private Dictionary _panelayouts = new Dictionary(); - private Dictionary _containers = new Dictionary(); private List _themeList; + private List _themes = new List(); + private List _layouts = new List(); + private List _containers = new List(); private string _name = string.Empty; private List _tenantList; private string _tenant = string.Empty; @@ -274,10 +274,11 @@ _faviconfileid = site.FaviconFileId.Value; } + _themes = ThemeService.GetThemeControls(_themeList); _themetype = site.DefaultThemeType; - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); _layouttype = site.DefaultLayoutType; - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); _containertype = site.DefaultContainerType; _allowregistration = site.AllowRegistration.ToString(); @@ -318,9 +319,6 @@ _deletedon = site.DeletedOn; _isdeleted = site.IsDeleted.ToString(); } - - _themes = ThemeService.GetThemeTypes(_themeList); - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); } catch (Exception ex) { @@ -336,13 +334,13 @@ _themetype = (string)e.Value; if (_themetype != "-") { - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); } else { - _panelayouts = new Dictionary(); - _containers = new Dictionary(); + _layouts = new List(); + _containers = new List(); } _layouttype = "-"; _containertype = "-"; @@ -359,7 +357,7 @@ { try { - if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_panelayouts.Count == 0 || _layouttype != "-") && _containertype != "-") + if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-") { var unique = true; foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 85f2e962..b2b9414d 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -39,14 +39,14 @@ else - @if (_panelayouts.Count > 0) + @if (_layouts.Count > 0) { @@ -55,9 +55,9 @@ else @@ -70,9 +70,9 @@ else @@ -201,11 +201,11 @@ else } @code { - private Dictionary _themes = new Dictionary(); - private Dictionary _panelayouts = new Dictionary(); - private Dictionary _containers = new Dictionary(); - private List _siteTemplates; private List _themeList; + private List _themes = new List(); + private List _layouts = new List(); + private List _containers = new List(); + private List _siteTemplates; private List _tenants; private string _tenantid = "-"; @@ -230,10 +230,10 @@ else protected override async Task OnInitializedAsync() { - _themeList = await ThemeService.GetThemesAsync(); _tenants = await TenantService.GetTenantsAsync(); _urls = PageState.Alias.Name; - _themes = ThemeService.GetThemeTypes(_themeList); + _themeList = await ThemeService.GetThemesAsync(); + _themes = ThemeService.GetThemeControls(_themeList); _siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync(); } @@ -267,13 +267,13 @@ else _themetype = (string)e.Value; if (_themetype != "-") { - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); } else { - _panelayouts = new Dictionary(); - _containers = new Dictionary(); + _layouts = new List(); + _containers = new List(); } _layouttype = "-"; _containertype = "-"; @@ -288,7 +288,7 @@ else private async Task SaveSite() { - if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && (_panelayouts.Count == 0 || _layouttype != "-") && _containertype != "-" && _sitetemplatetype != "-") + if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-" && _sitetemplatetype != "-") { var duplicates = new List(); var aliases = await AliasService.GetAliasesAsync(); diff --git a/Oqtane.Client/Modules/Admin/Sites/Edit.razor b/Oqtane.Client/Modules/Admin/Sites/Edit.razor index ab5f2112..00e3d9f9 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Edit.razor @@ -40,21 +40,21 @@ - @if (_panelayouts.Count > 0) + @if (_layouts.Count > 0) { @@ -63,9 +63,9 @@ @@ -78,9 +78,9 @@ @@ -106,11 +106,11 @@ } @code { - private Dictionary _themes = new Dictionary(); - private Dictionary _panelayouts = new Dictionary(); - private Dictionary _containers = new Dictionary(); - private Alias _alias; private List _themeList; + private List _themes = new List(); + private List _layouts = new List(); + private List _containers = new List(); + private Alias _alias; private string _name = string.Empty; private List _tenantList; private string _tenant = string.Empty; @@ -150,11 +150,11 @@ _urls += alias.Name + "\n"; } - _themes = ThemeService.GetThemeTypes(_themeList); + _themes = ThemeService.GetThemeControls(_themeList); _themetype = site.DefaultThemeType; - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); _layouttype = site.DefaultLayoutType; - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); _containertype = site.DefaultContainerType; _createdby = site.CreatedBy; _createdon = site.CreatedOn; @@ -179,13 +179,13 @@ _themetype = (string)e.Value; if (_themetype != "-") { - _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); - _containers = ThemeService.GetContainerTypes(_themeList, _themetype); + _layouts = ThemeService.GetLayoutControls(_themeList, _themetype); + _containers = ThemeService.GetContainerControls(_themeList, _themetype); } else { - _panelayouts = new Dictionary(); - _containers = new Dictionary(); + _layouts = new List(); + _containers = new List(); } _layouttype = "-"; _containertype = "-"; @@ -202,7 +202,7 @@ { try { - if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_panelayouts.Count == 0 || _layouttype != "-") && _containertype != "-") + if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-") { var unique = true; foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) diff --git a/Oqtane.Client/Services/Interfaces/IThemeService.cs b/Oqtane.Client/Services/Interfaces/IThemeService.cs index 32bb01ad..b75a2988 100644 --- a/Oqtane.Client/Services/Interfaces/IThemeService.cs +++ b/Oqtane.Client/Services/Interfaces/IThemeService.cs @@ -7,9 +7,9 @@ namespace Oqtane.Services public interface IThemeService { Task> GetThemesAsync(); - Dictionary GetThemeTypes(List themes); - Dictionary GetPaneLayoutTypes(List themes, string themeName); - Dictionary GetContainerTypes(List themes, string themeName); + List GetThemeControls(List themes); + List GetLayoutControls(List themes, string themeName); + List GetContainerControls(List themes, string themeName); Task InstallThemesAsync(); Task DeleteThemeAsync(string themeName); } diff --git a/Oqtane.Client/Services/ThemeService.cs b/Oqtane.Client/Services/ThemeService.cs index a2250d95..3e6a3690 100644 --- a/Oqtane.Client/Services/ThemeService.cs +++ b/Oqtane.Client/Services/ThemeService.cs @@ -26,49 +26,21 @@ namespace Oqtane.Services return themes.OrderBy(item => item.Name).ToList(); } - public Dictionary GetThemeTypes(List themes) + public List GetThemeControls(List themes) { - var selectableThemes = new Dictionary(); - foreach (Theme theme in themes) - { - foreach (string themecontrol in theme.ThemeControls.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - selectableThemes.Add(themecontrol, theme.Name + " - " + Utilities.GetTypeNameLastSegment(themecontrol, 0)); - } - } - return selectableThemes; + return themes.SelectMany(item => item.Themes).ToList(); } - public Dictionary GetPaneLayoutTypes(List themes, string themeName) + public List GetLayoutControls(List themes, string themeName) { - var selectablePaneLayouts = new Dictionary(); - foreach (Theme theme in themes) - { - if (Utilities.GetTypeName(themeName).StartsWith(Utilities.GetTypeName(theme.ThemeName))) - { - foreach (string panelayout in theme.PaneLayouts.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - selectablePaneLayouts.Add(panelayout, theme.Name + " - " + @Utilities.GetTypeNameLastSegment(panelayout, 0)); - } - } - } - return selectablePaneLayouts; + return themes.Where(item => Utilities.GetTypeName(themeName).StartsWith(Utilities.GetTypeName(item.ThemeName))) + .SelectMany(item => item.Layouts).ToList(); } - public Dictionary GetContainerTypes(List themes, string themeName) + public List GetContainerControls(List themes, string themeName) { - var selectableContainers = new Dictionary(); - foreach (Theme theme in themes) - { - if (Utilities.GetTypeName(themeName).StartsWith(Utilities.GetTypeName(theme.ThemeName))) - { - foreach (string container in theme.ContainerControls.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - selectableContainers.Add(container, theme.Name + " - " + @Utilities.GetTypeNameLastSegment(container, 0)); - } - } - } - return selectableContainers; + return themes.Where(item => Utilities.GetTypeName(themeName).StartsWith(Utilities.GetTypeName(item.ThemeName))) + .SelectMany(item => item.Containers).ToList(); } public async Task InstallThemesAsync() diff --git a/Oqtane.Client/Themes/ContainerBase.cs b/Oqtane.Client/Themes/ContainerBase.cs index af4ff355..5b1491ae 100644 --- a/Oqtane.Client/Themes/ContainerBase.cs +++ b/Oqtane.Client/Themes/ContainerBase.cs @@ -17,6 +17,8 @@ namespace Oqtane.Themes [CascadingParameter] protected Module ModuleState { get; set; } + public virtual string Name { get; set; } + public virtual string Thumbnail { get; set; } public string ThemePath() { diff --git a/Oqtane.Client/Themes/Controls/ControlPanel.razor b/Oqtane.Client/Themes/Controls/ControlPanel.razor index 8fa031d5..24e8ac48 100644 --- a/Oqtane.Client/Themes/Controls/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/ControlPanel.razor @@ -161,9 +161,9 @@
@@ -218,7 +218,7 @@ private List _moduleDefinitions; private List _pages = new List(); private List _modules = new List(); - private Dictionary _containers = new Dictionary(); + private List _containers = new List(); private string _display = "display: none;"; private string _category = "Common"; @@ -301,7 +301,7 @@ var panes = PageState.Page.Panes; Pane = panes.Count() == 1 ? panes.SingleOrDefault() : ""; var themes = await ThemeService.GetThemesAsync(); - _containers = ThemeService.GetContainerTypes(themes, PageState.Page.ThemeType); + _containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType); ContainerType = PageState.Site.DefaultContainerType; _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); diff --git a/Oqtane.Client/Themes/IContainerControl.cs b/Oqtane.Client/Themes/IContainerControl.cs index a76959ff..bfd77a9c 100644 --- a/Oqtane.Client/Themes/IContainerControl.cs +++ b/Oqtane.Client/Themes/IContainerControl.cs @@ -2,5 +2,7 @@ { public interface IContainerControl { + string Name { get; } // friendly name for a container + string Thumbnail { get; } // screen shot of a container - assumed to be in the ThemePath() folder } } diff --git a/Oqtane.Client/Themes/ILayoutControl.cs b/Oqtane.Client/Themes/ILayoutControl.cs index 59123ce4..69f9cfd1 100644 --- a/Oqtane.Client/Themes/ILayoutControl.cs +++ b/Oqtane.Client/Themes/ILayoutControl.cs @@ -2,7 +2,9 @@ { public interface ILayoutControl { - string Panes { get; } // identifies all panes in a theme ( delimited by ";" ) + string Name { get; } // friendly name for a layout + string Thumbnail { get; } // screen shot of a layout - assumed to be in the ThemePath() folder + string Panes { get; } // identifies all panes in a theme ( delimited by "," or ";" ) } } diff --git a/Oqtane.Client/Themes/LayoutBase.cs b/Oqtane.Client/Themes/LayoutBase.cs index cd8d92e4..f8a83b14 100644 --- a/Oqtane.Client/Themes/LayoutBase.cs +++ b/Oqtane.Client/Themes/LayoutBase.cs @@ -8,6 +8,8 @@ namespace Oqtane.Themes { [CascadingParameter] protected PageState PageState { get; set; } + public virtual string Name { get; set; } + public virtual string Thumbnail { get; set; } public virtual string Panes { get; set; } public string LayoutPath() diff --git a/Oqtane.Client/Themes/OqtaneTheme/Container.razor b/Oqtane.Client/Themes/OqtaneTheme/Container.razor index b7ea2559..6d0148fa 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Container.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Container.razor @@ -12,4 +12,8 @@
-
\ No newline at end of file + + +@code { + public override string Name => "Standard Header"; +} \ No newline at end of file diff --git a/Oqtane.Client/Themes/OqtaneTheme/Default.razor b/Oqtane.Client/Themes/OqtaneTheme/Default.razor index ae0ce8ec..7d8fa135 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Default.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Default.razor @@ -17,6 +17,8 @@ @code { + public override string Name => "Default"; + public override string Panes => string.Empty; public override List Resources => new List() diff --git a/Oqtane.Client/Themes/OqtaneTheme/MultiPane.razor b/Oqtane.Client/Themes/OqtaneTheme/MultiPane.razor index 24ba1146..b40d1989 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/MultiPane.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/MultiPane.razor @@ -14,5 +14,7 @@ @code { - public override string Panes => "Top;Left;Content;Right;Bottom"; + public override string Name => "Multiple Panes"; + + public override string Panes => "Top,Left,Content,Right,Bottom"; } \ No newline at end of file diff --git a/Oqtane.Client/Themes/OqtaneTheme/NoTitle.razor b/Oqtane.Client/Themes/OqtaneTheme/NoTitle.razor index 0d48bc64..082bbe5a 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/NoTitle.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/NoTitle.razor @@ -6,4 +6,8 @@ } - \ No newline at end of file + + +@code { + public override string Name => "No Header"; +} \ No newline at end of file diff --git a/Oqtane.Client/Themes/OqtaneTheme/SinglePane.razor b/Oqtane.Client/Themes/OqtaneTheme/SinglePane.razor index c89c6318..864209e1 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/SinglePane.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/SinglePane.razor @@ -6,5 +6,7 @@ @code { + public override string Name => "Single Pane"; + public override string Panes => "Content"; } \ No newline at end of file diff --git a/Oqtane.Client/Themes/ThemeBase.cs b/Oqtane.Client/Themes/ThemeBase.cs index af05f94a..a2eacbeb 100644 --- a/Oqtane.Client/Themes/ThemeBase.cs +++ b/Oqtane.Client/Themes/ThemeBase.cs @@ -17,6 +17,8 @@ namespace Oqtane.Themes [CascadingParameter] protected PageState PageState { get; set; } + public virtual string Name { get; set; } + public virtual string Thumbnail { get; set; } public virtual string Panes { get; set; } public virtual List Resources { get; set; } diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 488b48c4..1273f784 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -27,18 +27,13 @@ DynamicComponent = builder => { Type containerType = Type.GetType(container); - if (containerType != null) + if (containerType == null) { - builder.OpenComponent(0, containerType); - builder.CloseComponent(); - } - else - { - // container does not exist with type specified - builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageComponent)); - builder.AddAttribute(1, "Message", "Error Loading Module Container " + container); - builder.CloseComponent(); + // fallback + containerType = Type.GetType(Constants.DefaultContainer); } + builder.OpenComponent(0, containerType); + builder.CloseComponent(); }; } } diff --git a/Oqtane.Client/UI/PaneLayout.razor b/Oqtane.Client/UI/PaneLayout.razor index 2226c8c0..95e7a776 100644 --- a/Oqtane.Client/UI/PaneLayout.razor +++ b/Oqtane.Client/UI/PaneLayout.razor @@ -13,15 +13,13 @@ DynamicComponent = builder => { var layoutType = Type.GetType(PageState.Page.LayoutType); - if (layoutType != null) + if (layoutType == null) { - builder.OpenComponent(0, layoutType); - builder.CloseComponent(); - } - else - { - // layout does not exist with type specified + // fallback + layoutType = Type.GetType(Constants.DefaultLayout); } + builder.OpenComponent(0, layoutType); + builder.CloseComponent(); }; } } \ No newline at end of file diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 8857bad9..30052342 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -66,18 +66,13 @@ DynamicComponent = builder => { var themeType = Type.GetType(PageState.Page.ThemeType); - if (themeType != null) + if (themeType == null) { - builder.OpenComponent(0, themeType); - builder.CloseComponent(); - } - else - { - // theme does not exist with type specified - builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageComponent)); - builder.AddAttribute(1, "Message", "Error Loading Page Theme " + PageState.Page.ThemeType); - builder.CloseComponent(); + // fallback + themeType = Type.GetType(Constants.DefaultTheme); } + builder.OpenComponent(0, themeType); + builder.CloseComponent(); }; } diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs index bc14de74..41ceef26 100644 --- a/Oqtane.Server/Repository/ThemeRepository.cs +++ b/Oqtane.Server/Repository/ThemeRepository.cs @@ -87,26 +87,41 @@ namespace Oqtane.Repository } // set internal properties theme.ThemeName = qualifiedThemeType; - theme.ThemeControls = ""; - theme.PaneLayouts = ""; - theme.ContainerControls = ""; + theme.Themes = new List(); + theme.Layouts = new List(); + theme.Containers = new List(); theme.AssemblyName = assembly.FullName.Split(",")[0]; themes.Add(theme); index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType); } theme = themes[index]; - theme.ThemeControls += (themeControlType.FullName + ", " + themeControlType.Assembly.GetName().Name + ";"); + + var themecontrolobject = Activator.CreateInstance(themeControlType) as IThemeControl; + theme.Themes.Add( + new ThemeControl + { + TypeName = themeControlType.FullName + ", " + themeControlType.Assembly.GetName().Name, + Name = theme.Name + " - " + ((string.IsNullOrEmpty(themecontrolobject.Name)) ? Utilities.GetTypeNameLastSegment(themeControlType.FullName, 0) : themecontrolobject.Name), + Thumbnail = themecontrolobject.Thumbnail, + Panes = themecontrolobject.Panes + } + ); // layouts Type[] layouttypes = themeTypes .Where(item => item.GetInterfaces().Contains(typeof(ILayoutControl))).ToArray(); foreach (Type layouttype in layouttypes) { - string panelayout = layouttype.FullName + ", " + themeControlType.Assembly.GetName().Name + ";"; - if (!theme.PaneLayouts.Contains(panelayout)) - { - theme.PaneLayouts += panelayout; - } + var layoutobject = Activator.CreateInstance(layouttype) as ILayoutControl; + theme.Layouts.Add( + new ThemeControl + { + TypeName = layouttype.FullName + ", " + themeControlType.Assembly.GetName().Name, + Name = (string.IsNullOrEmpty(layoutobject.Name)) ? Utilities.GetTypeNameLastSegment(layouttype.FullName, 0) : layoutobject.Name, + Thumbnail = layoutobject.Thumbnail, + Panes = layoutobject.Panes + } + ); } // containers @@ -114,11 +129,16 @@ namespace Oqtane.Repository .Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray(); foreach (Type containertype in containertypes) { - string container = containertype.FullName + ", " + themeControlType.Assembly.GetName().Name + ";"; - if (!theme.ContainerControls.Contains(container)) - { - theme.ContainerControls += container; - } + var containerobject = Activator.CreateInstance(containertype) as IContainerControl; + theme.Containers.Add( + new ThemeControl + { + TypeName = containertype.FullName + ", " + themeControlType.Assembly.GetName().Name, + Name = (string.IsNullOrEmpty(containerobject.Name)) ? Utilities.GetTypeNameLastSegment(containertype.FullName, 0) : containerobject.Name, + Thumbnail = containerobject.Thumbnail, + Panes = "" + } + ); } themes[index] = theme; diff --git a/Oqtane.Shared/Interfaces/IThemeControl.cs b/Oqtane.Shared/Interfaces/IThemeControl.cs index 0f6ad00a..f147afba 100644 --- a/Oqtane.Shared/Interfaces/IThemeControl.cs +++ b/Oqtane.Shared/Interfaces/IThemeControl.cs @@ -5,7 +5,9 @@ namespace Oqtane.Themes { public interface IThemeControl { - string Panes { get; } // identifies all panes in a theme ( delimited by ";" ) - assumed to be a layout if no panes specified + string Name { get; } // friendly name for a theme + string Thumbnail { get; } // screen shot of a theme - assumed to be in the ThemePath() folder + string Panes { get; } // identifies all panes in a theme ( delimited by "," or ";") - assumed to be a layout if no panes specified List Resources { get; } // identifies all resources in a theme } } diff --git a/Oqtane.Shared/Models/Theme.cs b/Oqtane.Shared/Models/Theme.cs index d5a29552..ee420dd9 100644 --- a/Oqtane.Shared/Models/Theme.cs +++ b/Oqtane.Shared/Models/Theme.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Oqtane.Models { @@ -23,9 +24,16 @@ namespace Oqtane.Models public string Contact { get; set; } public string License { get; set; } public string Dependencies { get; set; } - public string ThemeControls { get; set; } - public string PaneLayouts { get; set; } - public string ContainerControls { get; set; } public string AssemblyName { get; set; } + public List Themes { get; set; } + public List Layouts { get; set; } + public List Containers { get; set; } + + //[Obsolete("This property is obsolete. Use Themes instead.", false)] + public string ThemeControls { get; set; } + //[Obsolete("This property is obsolete. Use Layouts instead.", false)] + public string PaneLayouts { get; set; } + //[Obsolete("This property is obsolete. Use Containers instead.", false)] + public string ContainerControls { get; set; } } } diff --git a/Oqtane.Shared/Models/ThemeControl.cs b/Oqtane.Shared/Models/ThemeControl.cs new file mode 100644 index 00000000..d6bb67eb --- /dev/null +++ b/Oqtane.Shared/Models/ThemeControl.cs @@ -0,0 +1,10 @@ +namespace Oqtane.Models +{ + public class ThemeControl + { + public string TypeName { get; set; } + public string Name { get; set; } + public string Thumbnail { get; set; } + public string Panes { get; set; } + } +} From c4f1d3742121800804b81d358dc4026dc2c98417 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 2 Jun 2020 14:21:57 -0400 Subject: [PATCH 08/16] improve user experience after app restarts --- .../Modules/Admin/ModuleDefinitions/Add.razor | 39 ++++----- .../Admin/ModuleDefinitions/Index.razor | 20 +++-- Oqtane.Client/Modules/Admin/Themes/Add.razor | 79 ++++++++++--------- .../Modules/Admin/Themes/Index.razor | 12 ++- .../Modules/Admin/Upgrade/Index.razor | 63 ++++++++------- Oqtane.Client/UI/Interop.cs | 30 +++++++ Oqtane.Server/wwwroot/js/interop.js | 10 +++ 7 files changed, 156 insertions(+), 97 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor index db9186bd..49ea702d 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor @@ -4,29 +4,30 @@ @inject IFileService FileService @inject IModuleDefinitionService ModuleDefinitionService @inject IPackageService PackageService +@inject IJSRuntime JsRuntime @if (_packages != null) { @if (_packages.Count > 0) { - - - -
- Name - Version - -
- - @context.Name - @context.Version - - - - -
-
+ + + +
+ Name + Version + +
+ + @context.Name + @context.Version + + + + +
+
} @@ -77,8 +78,10 @@ { try { + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); await ModuleDefinitionService.InstallModuleDefinitionsAsync(); - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor index acd19670..3354ce5a 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor @@ -3,6 +3,7 @@ @inject NavigationManager NavigationManager @inject IModuleDefinitionService ModuleDefinitionService @inject IPackageService PackageService +@inject IJSRuntime JsRuntime @if (_moduleDefinitions == null) { @@ -24,17 +25,17 @@ else @@ -83,9 +84,11 @@ else try { await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules"); - await ModuleDefinitionService.InstallModuleDefinitionsAsync(); await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", moduledefinitionname, version); - NavigationManager.NavigateTo(NavigateUrl()); + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); + await ModuleDefinitionService.InstallModuleDefinitionsAsync(); } catch (Exception ex) { @@ -98,9 +101,10 @@ else { try { + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId); - await logger.LogInformation("Module Deleted {ModuleDefinition}", moduleDefinition); - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { diff --git a/Oqtane.Client/Modules/Admin/Themes/Add.razor b/Oqtane.Client/Modules/Admin/Themes/Add.razor index da47d8a9..4fc6b155 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Add.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Add.razor @@ -4,46 +4,47 @@ @inject IFileService FileService @inject IThemeService ThemeService @inject IPackageService PackageService +@inject IJSRuntime JsRuntime @if (_packages != null) { - - @if (_packages.Count > 0) - { - - - -
-
- - - - - - - - - - - } - -
@if (context.AssemblyName != "Oqtane.Client") - { + { - } + } @context.Name @context.Version @if (UpgradeAvailable(context.ModuleDefinitionName, context.Version)) - { + { - } + } NameVersion@context.Name@context.Version - -
- - - - -
- - - -
-
-
+ + @if (_packages.Count > 0) + { + + + +
+ Name + Version + +
+ + @context.Name + @context.Version + + + + +
+
+ } + + + + + + +
+ + + +
+
+
- -Cancel + + Cancel } @code { @@ -77,8 +78,10 @@ { try { + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); await ThemeService.InstallThemesAsync(); - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { @@ -101,4 +104,4 @@ AddModuleMessage("Error Downloading Theme", MessageType.Error); } } - } +} diff --git a/Oqtane.Client/Modules/Admin/Themes/Index.razor b/Oqtane.Client/Modules/Admin/Themes/Index.razor index 9f5a76e2..fcb8b779 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Index.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Index.razor @@ -4,6 +4,7 @@ @inject NavigationManager NavigationManager @inject IThemeService ThemeService @inject IPackageService PackageService +@inject IJSRuntime JsRuntime @if (_themes == null) { @@ -83,9 +84,11 @@ else try { await PackageService.DownloadPackageAsync(themename, version, "Themes"); - await ThemeService.InstallThemesAsync(); await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", themename, version); - NavigationManager.NavigateTo(NavigateUrl()); + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); + await ThemeService.InstallThemesAsync(); } catch (Exception ex) { @@ -98,9 +101,10 @@ else { try { + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); await ThemeService.DeleteThemeAsync(Theme.ThemeName); - await logger.LogInformation("Theme Deleted {Theme}", Theme); - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { diff --git a/Oqtane.Client/Modules/Admin/Upgrade/Index.razor b/Oqtane.Client/Modules/Admin/Upgrade/Index.razor index cf446d82..f26d21d7 100644 --- a/Oqtane.Client/Modules/Admin/Upgrade/Index.razor +++ b/Oqtane.Client/Modules/Admin/Upgrade/Index.razor @@ -4,35 +4,36 @@ @inject IFileService FileService @inject IPackageService PackageService @inject IInstallationService InstallationService +@inject IJSRuntime JsRuntime @if (_package != null) { - - - @if (_upgradeavailable) - { - - @("Framework") @_package.Version - } - else - { - - } - - - - - - - -
- - - -
- -
-
+ + + @if (_upgradeavailable) + { + + @("Framework") @_package.Version + } + else + { + + } + + + + + + + +
+ + + +
+ +
+
} @code { @@ -59,7 +60,7 @@ } } } - catch + catch { // can be caused by no network connection } @@ -69,8 +70,10 @@ { try { + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); await InstallationService.Upgrade(); - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { @@ -84,8 +87,10 @@ try { await PackageService.DownloadPackageAsync(packageid, version, "Framework"); + ShowProgressIndicator(); + var interop = new Interop(JsRuntime); + await interop.RedirectBrowser(NavigateUrl(), 3); await InstallationService.Upgrade(); - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { diff --git a/Oqtane.Client/UI/Interop.cs b/Oqtane.Client/UI/Interop.cs index 1c05fe41..3bdbe0bb 100644 --- a/Oqtane.Client/UI/Interop.cs +++ b/Oqtane.Client/UI/Interop.cs @@ -204,5 +204,35 @@ namespace Oqtane.UI return Task.CompletedTask; } } + + public Task RefreshBrowser(bool force, int wait) + { + try + { + _jsRuntime.InvokeAsync( + "Oqtane.Interop.refreshBrowser", + force, wait); + return Task.CompletedTask; + } + catch + { + return Task.CompletedTask; + } + } + + public Task RedirectBrowser(string url, int wait) + { + try + { + _jsRuntime.InvokeAsync( + "Oqtane.Interop.redirectBrowser", + url, wait); + return Task.CompletedTask; + } + catch + { + return Task.CompletedTask; + } + } } } diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index 90668589..f439d62d 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -311,5 +311,15 @@ Oqtane.Interop = { request.send(data); } } + }, + refreshBrowser: function (reload, wait) { + setInterval(function () { + window.location.reload(reload); + }, wait * 1000); + }, + redirectBrowser: function (url, wait) { + setInterval(function () { + window.location.href = url; + }, wait * 1000); } }; From 5544d2bed30f590f846ece2c607e4eb8f196c97e Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 2 Jun 2020 16:10:02 -0400 Subject: [PATCH 09/16] fix dynamic creation of remote script tags --- Oqtane.Server/wwwroot/js/interop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index f439d62d..5b516f99 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -138,7 +138,7 @@ Oqtane.Interop = { script.integrity = integrity; } if (crossorigin !== "") { - script.crossorigin = crossorigin; + script.crossOrigin = crossorigin; } } else { From cdc4de432a911e9adca1fa9d92dcd9c96a310a0a Mon Sep 17 00:00:00 2001 From: Pavel Vesely Date: Wed, 3 Jun 2020 20:10:52 +0200 Subject: [PATCH 10/16] User manager search persistence --- Oqtane.Client/Modules/Admin/Users/Index.razor | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Users/Index.razor b/Oqtane.Client/Modules/Admin/Users/Index.razor index cf180d73..4abc278a 100644 --- a/Oqtane.Client/Modules/Admin/Users/Index.razor +++ b/Oqtane.Client/Modules/Admin/Users/Index.razor @@ -2,17 +2,20 @@ @inherits ModuleBase @inject IUserRoleService UserRoleService @inject IUserService UserService +@inject ISettingService SettingService @if (userroles == null) { -

Loading...

+

+ Loading... +

} else {
- +
@@ -23,9 +26,15 @@ else Name - - - + + + + + + + + + @context.User.DisplayName @@ -34,19 +43,24 @@ else @code { private List allroles; private List userroles; - private string search; + private string _search; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; protected override async Task OnInitializedAsync() { allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - userroles = allroles.Where(item => item.Role.Name == Constants.RegisteredRole).ToList(); + await LoadSettingsAsync(); + userroles = Search(_search); } - private void OnSearch() + private List Search(string search) { - userroles = allroles + if (string.IsNullOrEmpty(_search)) + { + return allroles.Where(item => item.Role.Name == Constants.RegisteredRole).ToList(); + } + return allroles .Where(item => item.Role.Name == Constants.RegisteredRole && ( item.User.Username.Contains(search, StringComparison.OrdinalIgnoreCase) || @@ -57,6 +71,11 @@ else .ToList(); } + private async Task OnSearch() + { + userroles = Search(_search); + await UpdateSettingsAsync(); + } private async Task DeleteUser(UserRole UserRole) { @@ -76,4 +95,20 @@ else AddModuleMessage(ex.Message, MessageType.Error); } } + + private string settingSearch = "AU-search"; + + private async Task LoadSettingsAsync() + { + Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + _search = SettingService.GetSetting(settings, settingSearch, ""); + } + + private async Task UpdateSettingsAsync() + { + Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + SettingService.SetSetting(settings, settingSearch, _search); + await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); + } + } From e24c6fc235bfdd74a4f7777009797ef0af58f818 Mon Sep 17 00:00:00 2001 From: Pavel Vesely Date: Wed, 3 Jun 2020 20:13:48 +0200 Subject: [PATCH 11/16] Move module startup install up to allow install middleware --- Oqtane.Server/Startup.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index b47cdd4f..183547d2 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -222,6 +222,8 @@ namespace Oqtane // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } + // to allow install middleware it should be moved up + app.ConfigureOqtaneAssemblies(env); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseBlazorFrameworkFiles(); @@ -240,7 +242,7 @@ namespace Oqtane endpoints.MapControllers(); endpoints.MapFallbackToPage("/_Host"); }); - app.ConfigureOqtaneAssemblies(env); + } } } From 99cad13890423ff3a38684bc439ca01b558d50ae Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 3 Jun 2020 19:46:47 -0400 Subject: [PATCH 12/16] restrict user data leakage --- .../Modules/Admin/Modules/Settings.razor | 4 +- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 19 +++-- .../Modules/Admin/UserProfile/Add.razor | 72 +++++++--------- .../Modules/Admin/UserProfile/Index.razor | 4 +- .../Modules/Admin/UserProfile/View.razor | 77 +++++++++-------- .../Themes/Controls/ControlPanel.razor | 82 +++++++++++++++++-- .../Themes/Controls/ModuleActionsBase.cs | 49 ++++++++++- Oqtane.Client/UI/SiteRouter.razor | 2 +- Oqtane.Server/Controllers/UserController.cs | 25 +++++- .../Controllers/UserRoleController.cs | 6 +- .../Infrastructure/Jobs/NotificationJob.cs | 6 +- .../Repository/NotificationRepository.cs | 4 - Oqtane.Server/Scripts/Tenant.1.0.1.sql | 6 ++ Oqtane.Shared/Models/Notification.cs | 8 +- 14 files changed, 249 insertions(+), 115 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index 5abb6fdf..31cedb01 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -63,7 +63,7 @@ } - @if (_containers != null) + @if (_permissions != null) { @@ -90,7 +90,7 @@ private string _containerType; private string _allPages = "false"; private string _permissionNames = ""; - private string _permissions; + private string _permissions = null; private string _pageId; private PermissionGrid _permissionGrid; private Type _settingsModuleType; diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 305420d5..7373d36a 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -202,13 +202,16 @@ } -
- - - -
- -
+ @if (_permissions != null) + { + + + + +
+ +
+ }
@@ -237,7 +240,7 @@ private string _layouttype = "-"; private string _containertype = "-"; private string _icon; - private string _permissions; + private string _permissions = null; private string _createdby; private DateTime _createdon; private string _modifiedby; diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor index e6ae6b68..c413ec91 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor @@ -1,7 +1,7 @@ @namespace Oqtane.Modules.Admin.UserProfile @inherits ModuleBase @inject NavigationManager NavigationManager -@inject IUserRoleService UserRoleService +@inject IUserService UserService @inject INotificationService NotificationService @if (PageState.User != null) @@ -9,19 +9,10 @@ @@ -46,8 +37,7 @@ } @code { - private List userroles; - private string userid = "-1"; + private string username = ""; private string subject = ""; private string body = ""; @@ -55,41 +45,35 @@ public override string Title => "Send Notification"; - protected override async Task OnInitializedAsync() - { - try - { - userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - userroles = userroles.Where(item => item.Role.Name == Constants.RegisteredRole || item.Role.Name == Constants.HostRole) - .OrderBy(item => item.User.DisplayName).ToList(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Users {Error}", ex.Message); - AddModuleMessage("Error Loading Users", MessageType.Error); - } - } - private async Task Send() { var notification = new Notification(); try { - notification.SiteId = PageState.Site.SiteId; - notification.FromUserId = PageState.User.UserId; - notification.ToUserId = int.Parse(userid); - notification.ToEmail = ""; - notification.Subject = subject; - notification.Body = body; - notification.ParentId = null; - notification.CreatedOn = DateTime.UtcNow; - notification.IsDelivered = false; - notification.DeliveredOn = null; - - notification = await NotificationService.AddNotificationAsync(notification); - - await logger.LogInformation("Notification Created {Notification}", notification); - NavigationManager.NavigateTo(NavigateUrl()); + var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); + if (user != null) + { + notification.SiteId = PageState.Site.SiteId; + notification.FromUserId = PageState.User.UserId; + notification.FromDisplayName = PageState.User.DisplayName; + notification.FromEmail = PageState.User.Email; + notification.ToUserId = user.UserId; + notification.ToDisplayName = user.DisplayName; + notification.ToEmail = user.Email; + notification.Subject = subject; + notification.Body = body; + notification.ParentId = null; + notification.CreatedOn = DateTime.UtcNow; + notification.IsDelivered = false; + notification.DeliveredOn = null; + notification = await NotificationService.AddNotificationAsync(notification); + await logger.LogInformation("Notification Created {Notification}", notification); + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + AddModuleMessage("User Does Not Exist. Please Verify That The Username Provided Is Correct.", MessageType.Warning); + } } catch (Exception ex) { diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index fec53f62..b47eb3fe 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -120,7 +120,7 @@ else - + @@ -143,7 +143,7 @@ else - + diff --git a/Oqtane.Client/Modules/Admin/UserProfile/View.razor b/Oqtane.Client/Modules/Admin/UserProfile/View.razor index 07140f63..5d5a43f5 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/View.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/View.razor @@ -1,7 +1,7 @@ @namespace Oqtane.Modules.Admin.UserProfile @inherits ModuleBase @inject NavigationManager NavigationManager -@inject IUserRoleService UserRoleService +@inject IUserService UserService @inject INotificationService NotificationService @if (PageState.User != null) @@ -12,16 +12,7 @@ @@ -72,8 +63,7 @@ @code { private int notificationid; private string title = string.Empty; - private List userroles; - private string userid = "-1"; + private string username = ""; private string subject = string.Empty; private string createdon = string.Empty; private string body = string.Empty; @@ -86,20 +76,17 @@ { try { - userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - userroles = userroles.Where(item => item.Role.Name == Constants.RegisteredRole || item.Role.Name == Constants.HostRole) - .OrderBy(item => item.User.DisplayName).ToList(); - notificationid = Int32.Parse(PageState.QueryString["id"]); Notification notification = await NotificationService.GetNotificationAsync(notificationid); if (notification != null) { + int userid = -1; if (notification.ToUserId == PageState.User.UserId) { title = "From"; if (notification.FromUserId != null) { - userid = notification.FromUserId.ToString(); + userid = notification.FromUserId.Value; } } else @@ -107,10 +94,21 @@ title = "To"; if (notification.ToUserId != null) { - userid = notification.ToUserId.ToString(); + userid = notification.ToUserId.Value; } } - + if (userid != -1) + { + var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId); + if (user != null) + { + username = user.Username; + } + } + if (username == "") + { + username = "System"; + } subject = notification.Subject; createdon = notification.CreatedOn.ToString(); body = notification.Body; @@ -134,23 +132,32 @@ private async Task Send() { var notification = new Notification(); - notification.SiteId = PageState.Site.SiteId; - notification.FromUserId = PageState.User.UserId; - notification.ToUserId = int.Parse(userid); - notification.ToEmail = string.Empty; - notification.Subject = subject; - notification.Body = body; - notification.ParentId = notificationid; - notification.CreatedOn = DateTime.UtcNow; - notification.IsDelivered = false; - notification.DeliveredOn = null; - try { - notification = await NotificationService.AddNotificationAsync(notification); - - await logger.LogInformation("Notification Created {Notification}", notification); - NavigationManager.NavigateTo(NavigateUrl()); + var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); + if (user != null) + { + notification.SiteId = PageState.Site.SiteId; + notification.FromUserId = PageState.User.UserId; + notification.FromDisplayName = PageState.User.DisplayName; + notification.FromEmail = PageState.User.Email; + notification.ToUserId = user.UserId; + notification.ToDisplayName = user.DisplayName; + notification.ToEmail = user.Email; + notification.Subject = subject; + notification.Body = body; + notification.ParentId = notificationid; + notification.CreatedOn = DateTime.UtcNow; + notification.IsDelivered = false; + notification.DeliveredOn = null; + notification = await NotificationService.AddNotificationAsync(notification); + await logger.LogInformation("Notification Created {Notification}", notification); + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + AddModuleMessage("User Does Not Exist. Please Verify That The Username Provided Is Correct.", MessageType.Warning); + } } catch (Exception ex) { diff --git a/Oqtane.Client/Themes/Controls/ControlPanel.razor b/Oqtane.Client/Themes/Controls/ControlPanel.razor index cff646ba..5c24be76 100644 --- a/Oqtane.Client/Themes/Controls/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/ControlPanel.razor @@ -32,7 +32,7 @@ -
+
@@ -50,6 +50,21 @@
+
+
+ @if (UserSecurity.GetPermissionStrings(PageState.Page.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(Constants.AllUsersRole)) + { +
+ +
+ } + else + { +
+ +
+ } +
} @if (_deleteConfirmation) @@ -74,7 +89,7 @@ } -
+
@@ -142,7 +157,7 @@
- +
@if (_pane.Length > 1) @@ -171,7 +186,7 @@
-
+
@((MarkupString) Message) @@ -448,7 +463,7 @@ switch (location) { case "Admin": - // get admin dashboard moduleid + // get admin dashboard moduleid module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule); if (module != null) @@ -460,7 +475,7 @@ case "Add": case "Edit": string url = ""; - // get page management moduleid + // get page management moduleid module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule); if (module != null) @@ -485,6 +500,61 @@ } } + private async void Publish(string action) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions)) + { + List permissions; + + if (action == "publish") + { + // publish all modules + foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId)) + { + permissions = UserSecurity.GetPermissionStrings(module.Permissions); + foreach (var permissionstring in permissions) + { + if (permissionstring.PermissionName == PermissionNames.View) + { + List ids = permissionstring.Permissions.Split(';').ToList(); + if (!ids.Contains(Constants.AllUsersRole)) ids.Add(Constants.AllUsersRole); + if (!ids.Contains(Constants.RegisteredRole)) ids.Add(Constants.RegisteredRole); + permissionstring.Permissions = string.Join(";", ids.ToArray()); + } + } + module.Permissions = UserSecurity.SetPermissionStrings(permissions); + await ModuleService.UpdateModuleAsync(module); + } + } + + // publish page + var page = PageState.Page; + permissions = UserSecurity.GetPermissionStrings(page.Permissions); + foreach (var permissionstring in permissions) + { + if (permissionstring.PermissionName == PermissionNames.View) + { + List ids = permissionstring.Permissions.Split(';').ToList(); + switch (action) + { + case "publish": + if (!ids.Contains(Constants.AllUsersRole)) ids.Add(Constants.AllUsersRole); + if (!ids.Contains(Constants.RegisteredRole)) ids.Add(Constants.RegisteredRole); + break; + case "unpublish": + ids.Remove(Constants.AllUsersRole); + ids.Remove(Constants.RegisteredRole); + break; + } + permissionstring.Permissions = string.Join(";", ids.ToArray()); + } + } + page.Permissions = UserSecurity.SetPermissionStrings(permissions); + await PageService.UpdatePageAsync(page); + NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload")); + } + } + private void ConfirmDelete() { _deleteConfirmation = !_deleteConfirmation; diff --git a/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs b/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs index 23b98814..58a7e3c4 100644 --- a/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs +++ b/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using Oqtane.Models; @@ -16,6 +17,7 @@ namespace Oqtane.Themes.Controls { [Inject] public NavigationManager NavigationManager { get; set; } [Inject] public IPageModuleService PageModuleService { get; set; } + [Inject] public IModuleService ModuleService { get; set; } protected List Actions; @@ -30,14 +32,23 @@ namespace Oqtane.Themes.Controls if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions)) { actionList.Add(new ActionViewModel {Name = "Manage Settings", Action = async (u, m) => await Settings(u, m)}); + if (UserSecurity.GetPermissionStrings(ModuleState.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(Constants.AllUsersRole)) + { + actionList.Add(new ActionViewModel { Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) }); + } + else + { + actionList.Add(new ActionViewModel { Name = "Publish Module", Action = async (s, m) => await Publish(s, m) }); + } + actionList.Add(new ActionViewModel { Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) }); if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "") { + actionList.Add(new ActionViewModel { Name = "" }); actionList.Add(new ActionViewModel {Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import")}); actionList.Add(new ActionViewModel {Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export")}); } - actionList.Add(new ActionViewModel {Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m)}); actionList.Add(new ActionViewModel {Name = ""}); if (ModuleState.PaneModuleIndex > 0) @@ -121,6 +132,42 @@ namespace Oqtane.Themes.Controls return url; } + private async Task Publish(string s, PageModule pagemodule) + { + var permissions = UserSecurity.GetPermissionStrings(pagemodule.Module.Permissions); + foreach (var permissionstring in permissions) + { + if (permissionstring.PermissionName == PermissionNames.View) + { + List ids = permissionstring.Permissions.Split(';').ToList(); + if (!ids.Contains(Constants.AllUsersRole)) ids.Add(Constants.AllUsersRole); + if (!ids.Contains(Constants.RegisteredRole)) ids.Add(Constants.RegisteredRole); + permissionstring.Permissions = string.Join(";", ids.ToArray()); + } + } + pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions); + await ModuleService.UpdateModuleAsync(pagemodule.Module); + return NavigateUrl(s, "reload"); + } + + private async Task Unpublish(string s, PageModule pagemodule) + { + var permissions = UserSecurity.GetPermissionStrings(pagemodule.Module.Permissions); + foreach (var permissionstring in permissions) + { + if (permissionstring.PermissionName == PermissionNames.View) + { + List ids = permissionstring.Permissions.Split(';').ToList(); + ids.Remove(Constants.AllUsersRole); + ids.Remove(Constants.RegisteredRole); + permissionstring.Permissions = string.Join(";", ids.ToArray()); + } + } + pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions); + await ModuleService.UpdateModuleAsync(pagemodule.Module); + return NavigateUrl(s, "reload"); + } + private async Task MoveTop(string s, PageModule pagemodule) { pagemodule.Order = 0; diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index f602b83c..429ff29f 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -90,7 +90,7 @@ // parse querystring var querystring = ParseQueryString(uri.Query); - // the reload parameter is used during user login/logout + // the reload parameter is used to reload the PageState if (querystring.ContainsKey("reload")) { reload = Reload.Site; diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index fce08020..b0dc919c 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -57,7 +57,7 @@ namespace Oqtane.Controllers user.SiteId = int.Parse(siteid); user.Roles = GetUserRoles(user.UserId, user.SiteId); } - return user; + return Filter(user); } // GET api//name/x?siteid=x @@ -70,6 +70,29 @@ namespace Oqtane.Controllers user.SiteId = int.Parse(siteid); user.Roles = GetUserRoles(user.UserId, user.SiteId); } + return Filter(user); + } + + private User Filter(User user) + { + if (user != null && !User.IsInRole(Constants.AdminRole) && User.Identity.Name != user.Username) + { + user.DisplayName = ""; + user.Email = ""; + user.PhotoFileId = null; + user.LastLoginOn = DateTime.MinValue; + user.LastIPAddress = ""; + user.Roles = ""; + user.CreatedBy = ""; + user.CreatedOn = DateTime.MinValue; + user.ModifiedBy = ""; + user.ModifiedOn = DateTime.MinValue; + user.DeletedBy = ""; + user.DeletedOn = DateTime.MinValue; + user.IsDeleted = false; + user.Password = ""; + user.IsAuthenticated = false; + } return user; } diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index b4398aa9..50b6d957 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -25,9 +25,9 @@ namespace Oqtane.Controllers _logger = logger; } - // GET: api/?userid=x + // GET: api/?siteid=x [HttpGet] - [Authorize] + [Authorize(Roles = Constants.AdminRole)] public IEnumerable Get(string siteid) { return _userRoles.GetUserRoles(int.Parse(siteid)); @@ -35,7 +35,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize] + [Authorize(Roles = Constants.AdminRole)] public UserRole Get(int id) { return _userRoles.GetUserRole(id); diff --git a/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs b/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs index b3a3e7b2..520533d9 100644 --- a/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs +++ b/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs @@ -69,7 +69,7 @@ namespace Oqtane.Infrastructure mailMessage.Subject = notification.Subject; if (notification.FromUserId != null) { - mailMessage.Body = "From: " + notification.FromUser.DisplayName + "<" + notification.FromUser.Email + ">" + "\n"; + mailMessage.Body = "From: " + notification.FromDisplayName + "<" + notification.FromEmail + ">" + "\n"; } else { @@ -78,8 +78,8 @@ namespace Oqtane.Infrastructure mailMessage.Body += "Sent: " + notification.CreatedOn + "\n"; if (notification.ToUserId != null) { - mailMessage.To.Add(new MailAddress(notification.ToUser.Email, notification.ToUser.DisplayName)); - mailMessage.Body += "To: " + notification.ToUser.DisplayName + "<" + notification.ToUser.Email + ">" + "\n"; + mailMessage.To.Add(new MailAddress(notification.ToEmail, notification.ToDisplayName)); + mailMessage.Body += "To: " + notification.ToDisplayName + "<" + notification.ToEmail + ">" + "\n"; } else { diff --git a/Oqtane.Server/Repository/NotificationRepository.cs b/Oqtane.Server/Repository/NotificationRepository.cs index 8f34ff50..4e6550d2 100644 --- a/Oqtane.Server/Repository/NotificationRepository.cs +++ b/Oqtane.Server/Repository/NotificationRepository.cs @@ -21,8 +21,6 @@ namespace Oqtane.Repository return _db.Notification .Where(item => item.SiteId == siteId) .Where(item => item.IsDelivered == false) - .Include(item => item.FromUser) - .Include(item => item.ToUser) .ToList(); } @@ -30,8 +28,6 @@ namespace Oqtane.Repository .Where(item => item.SiteId == siteId) .Where(item => item.ToUserId == toUserId || toUserId == -1) .Where(item => item.FromUserId == fromUserId || fromUserId == -1) - .Include(item => item.FromUser) - .Include(item => item.ToUser) .ToList(); } diff --git a/Oqtane.Server/Scripts/Tenant.1.0.1.sql b/Oqtane.Server/Scripts/Tenant.1.0.1.sql index 83904a29..5737acf3 100644 --- a/Oqtane.Server/Scripts/Tenant.1.0.1.sql +++ b/Oqtane.Server/Scripts/Tenant.1.0.1.sql @@ -31,3 +31,9 @@ CREATE UNIQUE NONCLUSTERED INDEX IX_File ON [dbo].[File] [Name] ) ON [PRIMARY] GO + +ALTER TABLE [dbo].[Notification] ADD + [FromDisplayName] [nvarchar](50) NULL, + [FromEmail] [nvarchar](256) NULL, + [ToDisplayName] [nvarchar](50) NULL +GO diff --git a/Oqtane.Shared/Models/Notification.cs b/Oqtane.Shared/Models/Notification.cs index 0d804e41..aeb7235d 100644 --- a/Oqtane.Shared/Models/Notification.cs +++ b/Oqtane.Shared/Models/Notification.cs @@ -8,7 +8,10 @@ namespace Oqtane.Models public int NotificationId { get; set; } public int SiteId { get; set; } public int? FromUserId { get; set; } + public string FromDisplayName { get; set; } + public string FromEmail { get; set; } public int? ToUserId { get; set; } + public string ToDisplayName { get; set; } public string ToEmail { get; set; } public int? ParentId { get; set; } public string Subject { get; set; } @@ -19,11 +22,6 @@ namespace Oqtane.Models public string DeletedBy { get; set; } public DateTime? DeletedOn { get; set; } public bool IsDeleted { get; set; } - - [ForeignKey("FromUserId")] - public User FromUser { get; set; } - [ForeignKey("ToUserId")] - public User ToUser { get; set; } } } From 5b0da056b400d89854cf866c0d3c62115c41bb50 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 4 Jun 2020 12:48:29 -0400 Subject: [PATCH 13/16] Restore support for third party assembly dependencies in modules and themes when running om Wasm --- .../Controllers/InstallationController.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index a66d6b21..50b45710 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -9,6 +9,9 @@ using System.IO; using System.Reflection; using System.Linq; using System.IO.Compression; +using Oqtane.Modules; +using Oqtane.Themes; +using System.Diagnostics; namespace Oqtane.Controllers { @@ -70,8 +73,27 @@ namespace Oqtane.Controllers // get list of assemblies which should be downloaded to browser var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies(); var list = assemblies.Select(a => a.GetName().Name).ToList(); - var deps = assemblies.SelectMany(a => a.GetReferencedAssemblies()).Distinct(); - list.AddRange(deps.Where(a => a.Name.EndsWith(".oqtane", StringComparison.OrdinalIgnoreCase)).Select(a => a.Name)); + + // get module and theme dependencies + foreach (var assembly in assemblies) + { + foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule)))) + { + var instance = Activator.CreateInstance(type) as IModule; + foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + { + if (!list.Contains(name)) list.Add(name); + } + } + foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme)))) + { + var instance = Activator.CreateInstance(type) as ITheme; + foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + { + if (!list.Contains(name)) list.Add(name); + } + } + } // create zip file containing assemblies and debug symbols string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); @@ -90,6 +112,7 @@ namespace Oqtane.Controllers filestream.CopyTo(entrystream); } + // include debug symbols ( we may want to consider restricting this to only host users or when running in debug mode for performance ) if (System.IO.File.Exists(Path.Combine(binfolder, file + ".pdb"))) { entry = archive.CreateEntry(file + ".pdb"); From ed2822ac7c89197bf30cc8d21fc151f9001e307f Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 4 Jun 2020 12:53:14 -0400 Subject: [PATCH 14/16] fixed external module template to specify dependencies --- .../wwwroot/Modules/Templates/External/Client/ModuleInfo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/ModuleInfo.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/ModuleInfo.cs index 17af8d41..d6664487 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/ModuleInfo.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/ModuleInfo.cs @@ -11,7 +11,8 @@ namespace [Owner].[Module]s Description = "[Module]", Version = "1.0.0", ServerManagerType = "[ServerManagerType]", - ReleaseVersions = "1.0.0" + ReleaseVersions = "1.0.0", + Dependencies = "[Owner].[Module]s.Shared.Oqtane" }; } } From 3503f20255412aceb1c4d884d1bc010ae79a7d2a Mon Sep 17 00:00:00 2001 From: Sven Reichelt Date: Mon, 8 Jun 2020 11:36:32 +0200 Subject: [PATCH 15/16] Fixed type filtering in assembly extensions --- Oqtane.Shared/Extensions/AssemblyExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Shared/Extensions/AssemblyExtensions.cs b/Oqtane.Shared/Extensions/AssemblyExtensions.cs index 5b68bc76..74ae7070 100644 --- a/Oqtane.Shared/Extensions/AssemblyExtensions.cs +++ b/Oqtane.Shared/Extensions/AssemblyExtensions.cs @@ -35,14 +35,14 @@ namespace System.Reflection return assembly.GetTypes() //.Where(t => t.GetInterfaces().Contains(interfaceType)); - .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); + .Where(x => !x.IsInterface && !x.IsAbstract && interfaceType.IsAssignableFrom(x)); } - + public static IEnumerable GetTypes(this Assembly assembly) { return assembly.GetTypes(typeof(T)); } - + public static IEnumerable GetInstances(this Assembly assembly) where T : class { if (assembly is null) @@ -51,7 +51,7 @@ namespace System.Reflection } var type = typeof(T); var list = assembly.GetTypes() - .Where(x => type.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract && !x.IsGenericType); + .Where(x => !x.IsInterface && !x.IsAbstract && !x.IsGenericType && type.IsAssignableFrom(x)); foreach (var type1 in list) { From 836c4505b9c2a8a0e19452b4591618ad682c6bd1 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 8 Jun 2020 13:48:41 -0400 Subject: [PATCH 16/16] fix bug #589 - Unhandled exception when trying to edit MyPage --- Oqtane.Server/Controllers/PageController.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 6797796a..72e4f352 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -169,8 +169,8 @@ namespace Oqtane.Controllers page.DefaultContainerType = parent.DefaultContainerType; page.Icon = parent.Icon; page.Permissions = new List { - new Permission(PermissionNames.View, userid, true), - new Permission(PermissionNames.Edit, userid, true) + new Permission(PermissionNames.View, int.Parse(userid), true), + new Permission(PermissionNames.Edit, int.Parse(userid), true) }.EncodePermissions(); page.IsPersonalizable = false; page.UserId = int.Parse(userid); @@ -187,8 +187,8 @@ namespace Oqtane.Controllers module.ModuleDefinitionName = pm.Module.ModuleDefinitionName; module.AllPages = false; module.Permissions = new List { - new Permission(PermissionNames.View, userid, true), - new Permission(PermissionNames.Edit, userid, true) + new Permission(PermissionNames.View, int.Parse(userid), true), + new Permission(PermissionNames.Edit, int.Parse(userid), true) }.EncodePermissions(); module = _modules.AddModule(module);
- + - +
@(context.FromUser == null ? "System" : context.FromUser.DisplayName)@context.FromDisplayName @context.Subject @context.CreatedOn @(context.ToUser == null ? context.ToEmail : context.ToUser.DisplayName)@context.ToDisplayName @context.Subject @context.CreatedOn - +