From 38738e08441f7dbbef039ec942ec4e80e58fe026 Mon Sep 17 00:00:00 2001 From: Mike Casas Date: Sun, 16 Aug 2020 22:35:09 -0400 Subject: [PATCH 001/114] Add project reference for dotnet publish to work without errors. --- Oqtane.Server/Oqtane.Server.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 495819fc..26ed3ce3 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -49,6 +49,7 @@ + From e1ec58b2975bc94e8f606c3f6bfc25db420d811e Mon Sep 17 00:00:00 2001 From: Mike Casas Date: Tue, 18 Aug 2020 09:34:26 -0400 Subject: [PATCH 002/114] Rename MenuHorizontal.Razor to MenuHorizontal.razor --- .../Controls/{MenuHorizontal.Razor => MenuHorizontal.razor} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Oqtane.Client/Themes/Controls/{MenuHorizontal.Razor => MenuHorizontal.razor} (100%) diff --git a/Oqtane.Client/Themes/Controls/MenuHorizontal.Razor b/Oqtane.Client/Themes/Controls/MenuHorizontal.razor similarity index 100% rename from Oqtane.Client/Themes/Controls/MenuHorizontal.Razor rename to Oqtane.Client/Themes/Controls/MenuHorizontal.razor From 2f9f823330f023861a737c9610e90586e0828630 Mon Sep 17 00:00:00 2001 From: Mike Casas Date: Tue, 18 Aug 2020 17:02:40 -0400 Subject: [PATCH 003/114] Delete module pluralization in the location display. --- Oqtane.Client/Modules/Admin/ModuleCreator/Index.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Index.razor b/Oqtane.Client/Modules/Admin/ModuleCreator/Index.razor index e42c394f..b3de9742 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Index.razor @@ -105,11 +105,11 @@ string[] path = systeminfo["serverpath"].Split('\\'); if (_template == "internal") { - _location = string.Join("\\", path, 0, path.Length - 1) + "\\Oqtane.Client\\Modules\\" + _owner + "." + _module + "s"; + _location = string.Join("\\", path, 0, path.Length - 1) + "\\Oqtane.Client\\Modules\\" + _owner + "." + _module; } else { - _location = string.Join("\\", path, 0, path.Length - 2) + "\\" + _owner + "." + _module + "s"; + _location = string.Join("\\", path, 0, path.Length - 2) + "\\" + _owner + "." + _module; } } } From e3fe8c591437ee718f876ac2d3a8b01a7cdae22a Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 22 Aug 2020 04:19:11 +0300 Subject: [PATCH 004/114] Fix logo --- Oqtane.Server/wwwroot/oqtane-black.png | Bin 11565 -> 94624 bytes Oqtane.Server/wwwroot/oqtane-white.png | Bin 11567 -> 31678 bytes Oqtane.Server/wwwroot/oqtane.png | Bin 0 -> 94624 bytes oqtane.png | Bin 30049 -> 94624 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Oqtane.Server/wwwroot/oqtane.png diff --git a/Oqtane.Server/wwwroot/oqtane-black.png b/Oqtane.Server/wwwroot/oqtane-black.png index f3c92bf04de6975ed448635d4f34a4d66b703327..942ef8c0c0c0903a02bd40ff139e9a0f8020755c 100644 GIT binary patch literal 94624 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 JT5)jD{{UV$;R^r& diff --git a/Oqtane.Server/wwwroot/oqtane-white.png b/Oqtane.Server/wwwroot/oqtane-white.png index 1d75a0120fb6ebc7c82864fadff224a83c46c5d3..fa7950bc645a767fd3740585d758d16469c136c2 100644 GIT binary patch literal 31678 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

!`rJ<|LoKM@D=PMSkC$E?KI&Bm8dW{p;)Wi zts5cu?f6B=m5CR6x#;e-wtp`zhoLoJesxanMI#oSi7*Xa+x{&P^Q^^%mg*(>PZU!0 z;QeGO=xLIxZx)S|TvfYvu~)HLw-0szATcj;nJkwVL$fW*3o)(;VUOw@irZu)RTKuc&~lJ zG_fB({?MVdD*SlNLTyb`VRVp_O=CssNXNSJxK-dyd*0#>Sa+AlyM6Nd^@G-g_RBI= zevCa_v0q}Vs_6Y9OrN7tQUd%f1hUNo6(3ahcdK{#!THgxY4%@iHBRHPF0I@Rj{H9)*)s;zJvtd!{BlacLlUB*yfbyZdHHIq8y;1F5+d`SR=nWQmDRTyVX^t= z%47!YE1VquUdq+GZZ3}T;ZgzfHp9h!1J7t`7dufO*hO^KgdTrrDz;_)^dYaV9p3GC zZ^@hp?Lq{-vTPs}C?*DGZ9jcUc@6IqbmU>Y>$|ise(Gl}Q+_OO3>E~S(|Atbz1z)5 z1nKk*f08#^^P;wXv!%$M@s*{G{jIYe*}D;SCQ*{~Sbn9_8ADeo307fq`0O>%;opz( z@wp<8%Yr2L7Q$9|Qo&yvtFN6rRm$mgcZ)d>mh?bi5(f~DC|}!%OGQ>;xRLH&O~1pM zg=DlZC8+-IAOBzzCW8HVya(Ob5T-sHQ_wbnTHQ@=7Vm8&;%`nYEVl)zuZx&JUaXASt%C=Esir}hgT<8w*Uj+l!AOdM$- z%v3BI$geW08tQ$j`;V{WV#suDyYg=NaELBEyCzUi`gIjdq&z)CW@mlKp(&-w`sgn; zcPA)R6)UP<$kHx7e`bJfN9?wOqG%e0eX_e0;w-r9mQ>q@Y% zXU>!<*Nu>$e%$;(pl`S-*7VP>Z0aF$CY$L1E`DMeH(t(bu+}UaN;5S}NPh8mCLa_N z5;DS?iIdD8`mVjGI`GEYt{buR)3Zcg6fwb8I>xs=pwckHzdtV;HXyW1XoRZJUpeRD zd{+gt@a*&Is8ZP{TYagt!BXEuM$EH^iS3tviW#)C{Sz$uCxDbj)mH3>Mwhljn=J#(fK{gSA$nH}w%(X4%d&3UiIMD77s1W!X{M^k{^g|b(2fHY zE3LW&+k-Rd&7$cDP5kv{#&G~tP?%U=^wKV*9ceC#S>BYY90`oVczHG*%i~r!h&#zt z6?Y#e>vJBy$uc%HKDTe)9IDL?)byG4PfP&K@hp~iu?KM&tFN~VTsp`rkEwJXqMk#3 zU44hk{`8R}A)T)&c(Odbg{oreFG?M2q0F1FI~m}5nx}W#$!0ntkv+Acu5CkPg3z`z zwz0qT4l%}O2&ri%7_Q;NHKB%yt*?tA4!9<|za9w##Sb~rPzbGb(L_~ztATZ*fH*?6 zfTk7kIJ1ndcTorJ>r z99-&#o+yORoN&OMqHZd#f+Wi40Rmm+p zKNQtwt=mt!V#3Xml14II|AR|Na>9jaj)7%GEjk*$osH`1qNRgM6CjW{fWXWvMJnNP z426;d3#8N+#U73>*IvE9fQ9(2<1B>+3SN! zwm#E4GpfFz&D4en?EJlugr>Eg?BSTaV|vXYoW;Gy2L^rwqV&4q>i2+@s+}vw5BM;2 z6ko>8P7!z><>e%rzK?OV2qT(sV!k28VlsraFg@s472B}73Vs%pZoX!|KL5A!~FjF zqU*Kw-0KOoRi#b4>C&gO{mkJSUKIfISaisnm>e%d`91j;o>5Ks8oXGvcySe|>6ijL z&;Nb)JClZ(witXX@SSv_;FE|8Q)~3^1#+`nCnIxH{D}Yihc`p2nv5ll_3Li_?peE9 Q!hc2&A3N-zw|d3@0f@v*Z~y=R literal 0 HcmV?d00001 diff --git a/oqtane.png b/oqtane.png index 82c098e96f5a988041b564621a3e12e0971cbd02..be8f48c9e6c12c74a1d26667b2499a4dce9570a7 100644 GIT binary patch literal 94624 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

!`rJ<|LoKM@D=PMSkC$E?KI&Bm8dW{p;)Wi zts5cu?f6B=m5CR6x#;e-wtp`zhoLoJesxanMI#oSi7*Xa+x{&P^Q^^%mg*(>PZU!0 z;QeGO=xLIxZx)S|TvfYvu~)HLw-0szATcj;nJkwVL$fW*3o)(;VUOw@irZu)RTKuc&~lJ zG_fB({?MVdD*SlNLTyb`VRVp_O=CssNXNSJxK-dyd*0#>Sa+AlyM6Nd^@G-g_RBI= zevCa_v0q}Vs_6Y9OrN7tQUd%f1hUNo6(3ahcdK{#!THgxY4%@iHBRHPF0I@Rj{H9)*)s;zJvtd!{BlacLlUB*yfbyZdHHIq8y;1F5+d`SR=nWQmDRTyVX^t= z%47!YE1VquUdq+GZZ3}T;ZgzfHp9h!1J7t`7dufO*hO^KgdTrrDz;_)^dYaV9p3GC zZ^@hp?Lq{-vTPs}C?*DGZ9jcUc@6IqbmU>Y>$|ise(Gl}Q+_OO3>E~S(|Atbz1z)5 z1nKk*f08#^^P;wXv!%$M@s*{G{jIYe*}D;SCQ*{~Sbn9_8ADeo307fq`0O>%;opz( z@wp<8%Yr2L7Q$9|Qo&yvtFN6rRm$mgcZ)d>mh?bi5(f~DC|}!%OGQ>;xRLH&O~1pM zg=DlZC8+-IAOBzzCW8HVya(Ob5T-sHQ_wbnTHQ@=7Vm8&;%`nYEVl)zuZx&JUaXASt%C=Esir}hgT<8w*Uj+l!AOdM$- z%v3BI$geW08tQ$j`;V{WV#suDyYg=NaELBEyCzUi`gIjdq&z)CW@mlKp(&-w`sgn; zcPA)R6)UP<$kHx7e`bJfN9?wOqG%e0eX_e0;w-r9mQ>q@Y% zXU>!<*Nu>$e%$;(pl`S-*7VP>Z0aF$CY$L1E`DMeH(t(bu+}UaN;5S}NPh8mCLa_N z5;DS?iIdD8`mVjGI`GEYt{buR)3Zcg6fwb8I>xs=pwckHzdtV;HXyW1XoRZJUpeRD zd{+gt@a*&Is8ZP{TYagt!BXEuM$EH^iS3tviW#)C{Sz$uCxDbj)mH3>Mwhljn=J#(fK{gSA$nH}w%(X4%d&3UiIMD77s1W!X{M^k{^g|b(2fHY zE3LW&+k-Rd&7$cDP5kv{#&G~tP?%U=^wKV*9ceC#S>BYY90`oVczHG*%i~r!h&#zt z6?Y#e>vJBy$uc%HKDTe)9IDL?)byG4PfP&K@hp~iu?KM&tFN~VTsp`rkEwJXqMk#3 zU44hk{`8R}A)T)&c(Odbg{oreFG?M2q0F1FI~m}5nx}W#$!0ntkv+Acu5CkPg3z`z zwz0qT4l%}O2&ri%7_Q;NHKB%yt*?tA4!9<|za9w##Sb~rPzbGb(L_~ztATZ*fH*?6 zfTk7kIJ1ndcTorJ>r z99-&#o+yORoN&OMqHZd#f+Wi40Rmm+p zKNQtwt=mt!V#3Xml14II|AR|Na>9jaj)7%GEjk*$osH`1qNRgM6CjW{fWXWvMJnNP z426;d3#8N+#U73>*IvE9fQ9(2<1B>+3SN! zwm#E4GpfFz&D4en?EJlugr>Eg?BSTaV|vXYoW;Gy2L^rwqV&4q>i2+@s+}vw5BM;2 z6ko>8P7!z><>e%rzK?OV2qT(sV!k28VlsraFg@s472B}73Vs%pZoX!|KL5A!~FjF zqU*Kw-0KOoRi#b4>C&gO{mkJSUKIfISaisnm>e%d`91j;o>5Ks8oXGvcySe|>6ijL z&;Nb)JClZ(witXX@SSv_;FE|8Q)~3^1#+`nCnIxH{D}Yihc`p2nv5ll_3Li_?peE9 Q!hc2&A3N-zw|d3@0f@v*Z~y=R literal 30049 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 Xp0}JU4x?ekDUPP9wo0Xv75e`HTDY>N From fc50a45ecd5e4361981db8643889b7e92d92e1a6 Mon Sep 17 00:00:00 2001 From: Mark Davis <311063+nohorse@users.noreply.github.com> Date: Sat, 22 Aug 2020 14:55:43 -0700 Subject: [PATCH 005/114] Create Tenant.01.00.02.02.sql Proposed fixed for #699 --- Oqtane.Server/Scripts/Tenant.01.00.02.02.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Oqtane.Server/Scripts/Tenant.01.00.02.02.sql diff --git a/Oqtane.Server/Scripts/Tenant.01.00.02.02.sql b/Oqtane.Server/Scripts/Tenant.01.00.02.02.sql new file mode 100644 index 00000000..ba14575a --- /dev/null +++ b/Oqtane.Server/Scripts/Tenant.01.00.02.02.sql @@ -0,0 +1,3 @@ +ALTER TABLE [dbo].[Page] +ALTER COLUMN [Path] [nvarchar](256) NOT NULL +GO From 760fc3b8d492c997ce9ece6259118f8253c37e56 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 26 Aug 2020 15:00:07 -0400 Subject: [PATCH 006/114] Ensure folder does not contain files during deletion and remove directory during deletion, fix validation issue in add page which would allow a user to create a page without selecting a layout, modify action dialog to use its own CSS class name so it can be styled independently from the Admin Modal, rollback "container" CSS class assigment on panes --- Oqtane.Client/Modules/Admin/Files/Edit.razor | 19 ++++++++++---- Oqtane.Client/Modules/Admin/Pages/Add.razor | 4 +-- Oqtane.Client/Modules/Admin/Site/Index.razor | 2 +- Oqtane.Client/Modules/Admin/Sites/Add.razor | 2 +- .../Modules/Controls/ActionDialog.razor | 2 +- Oqtane.Client/UI/Pane.razor | 2 +- Oqtane.Server/Controllers/FolderController.cs | 5 ++++ Oqtane.Server/wwwroot/css/app.css | 25 +++++++++++++++++++ 8 files changed, 50 insertions(+), 11 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index 2c502690..73cac84d 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -1,6 +1,7 @@ @namespace Oqtane.Modules.Admin.Files @inherits ModuleBase @inject IFolderService FolderService +@inject IFileService FileService @inject NavigationManager NavigationManager @if (_folders != null) @@ -45,7 +46,7 @@ Cancel @if (!_isSystem && PageState.QueryString.ContainsKey("id")) { - + }

@@ -193,13 +194,21 @@ } if (!isparent) { - await FolderService.DeleteFolderAsync(_folderId); - await logger.LogInformation("Folder Deleted {Folder}", _folderId); - NavigationManager.NavigateTo(NavigateUrl()); + var files = await FileService.GetFilesAsync(_folderId); + if (files.Count == 0) + { + await FolderService.DeleteFolderAsync(_folderId); + await logger.LogInformation("Folder Deleted {Folder}", _folderId); + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + AddModuleMessage("Folder Has Files And Cannot Be Deleted", MessageType.Warning); + } } else { - AddModuleMessage("Folder Has Child Folders And Cannot Be Deleted", MessageType.Warning); + AddModuleMessage("Folder Has Subfolders And Cannot Be Deleted", MessageType.Warning); } } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index 9e73435b..f666441b 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -299,7 +299,7 @@ Page page = null; try { - if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || !string.IsNullOrEmpty(_layouttype))) + if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || _layouttype != "-")) { page = new Page(); page.SiteId = PageState.Page.SiteId; @@ -389,7 +389,7 @@ } else { - AddModuleMessage("You Must Provide Page Name And Theme", MessageType.Warning); + AddModuleMessage("You Must Provide Page Name And Theme/Layout", MessageType.Warning); } } diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index e483465e..6b5e98ee 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -448,7 +448,7 @@ } else { - AddModuleMessage("You Must Provide A Site Name, Alias, And Default Theme/Container", MessageType.Warning); + AddModuleMessage("You Must Provide A Site Name, Alias, And Default Theme/Layout/Container", MessageType.Warning); } } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index b2b9414d..042e168b 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -402,7 +402,7 @@ else } else { - AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template", MessageType.Warning); + AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, Default Theme/Layout/Container, And Site Template", MessageType.Warning); } } } diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index 0182fe03..fc22605c 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -3,7 +3,7 @@ @if (_visible) { -

+
@if (_image != string.Empty) { @@ -91,9 +91,9 @@ private string _progressbarid = string.Empty; private string _filter = "*"; private bool _haseditpermission = false; - private string _message = string.Empty; private string _image = string.Empty; private string _guid; + private Alert _alert = new Alert(); [Parameter] public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility @@ -205,7 +205,6 @@ private async Task FolderChanged(ChangeEventArgs e) { - _message = string.Empty; try { FolderId = int.Parse((string)e.Value); @@ -217,13 +216,14 @@ catch (Exception ex) { await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); - _message = "
Error Loading Files
"; + + _alert.Type = AlertType.Danger; + _alert.Message = "Error Loading Files"; } } private async Task FileChanged(ChangeEventArgs e) { - _message = string.Empty; FileId = int.Parse((string)e.Value); await SetImage(); @@ -273,7 +273,10 @@ if (result == string.Empty) { await logger.LogInformation("File Upload Succeeded {Files}", upload); - _message = "
File Upload Succeeded
"; + + _alert.Type = AlertType.Success; + _alert.Message = "File Upload Succeeded"; + await GetFiles(); if (upload.Length == 1) @@ -290,30 +293,36 @@ else { await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", ")); - _message = "
File Upload Failed
"; + + _alert.Type = AlertType.Danger; + _alert.Message = "File Upload Failed"; } } catch (Exception ex) { await logger.LogError(ex, "File Upload Failed {Error}", ex.Message); - _message = "
File Upload Failed
"; + + _alert.Type = AlertType.Danger; + _alert.Message = "File Upload Failed"; } } else { - _message = "
You Have Not Selected A File To Upload
"; + _alert.Type = AlertType.Warning; + _alert.Message = "You Have Not Selected A File To Upload"; } } private async Task DeleteFile() { - _message = string.Empty; - try { await FileService.DeleteFileAsync(FileId); await logger.LogInformation("File Deleted {File}", FileId); - _message = "
File Deleted
"; + + _alert.Type = AlertType.Success; + _alert.Message = "File Deleted"; + await GetFiles(); FileId = -1; await SetImage(); @@ -322,7 +331,9 @@ catch (Exception ex) { await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); - _message = "
Error Deleting File
"; + + _alert.Type = AlertType.Danger; + _alert.Message = "Error Deleting File"; } } From ad5f5fbc24f3ae50b9a1dd40c3e4fb158943c75d Mon Sep 17 00:00:00 2001 From: hishamco Date: Sun, 20 Sep 2020 15:10:48 +0300 Subject: [PATCH 027/114] Replace Alert with ModuleMessage component --- Oqtane.Client/Modules/Controls/Alert.razor | 31 ------------------- Oqtane.Client/Modules/Controls/AlertType.cs | 10 ------ .../Modules/Controls/FileManager.razor | 25 ++++++--------- 3 files changed, 9 insertions(+), 57 deletions(-) delete mode 100644 Oqtane.Client/Modules/Controls/Alert.razor delete mode 100644 Oqtane.Client/Modules/Controls/AlertType.cs diff --git a/Oqtane.Client/Modules/Controls/Alert.razor b/Oqtane.Client/Modules/Controls/Alert.razor deleted file mode 100644 index b2d888ca..00000000 --- a/Oqtane.Client/Modules/Controls/Alert.razor +++ /dev/null @@ -1,31 +0,0 @@ -@namespace Oqtane.Modules.Controls -@inherits ModuleControlBase - -@if (!string.IsNullOrEmpty(Message)) -{ - -} - -@code { - [Parameter] - public bool Dismissible { get; set; } = true; - - [Parameter] - public string Message { get; set; } - - [Parameter] - public AlertType Type { get; set; } - - protected override void OnInitialized() - { - base.OnInitialized(); - } -} \ No newline at end of file diff --git a/Oqtane.Client/Modules/Controls/AlertType.cs b/Oqtane.Client/Modules/Controls/AlertType.cs deleted file mode 100644 index a4b0a7aa..00000000 --- a/Oqtane.Client/Modules/Controls/AlertType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Oqtane.Modules.Controls -{ - public enum AlertType - { - Information, - Danger, - Success, - Warning - } -} diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 603ddfb0..34b098b2 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -70,7 +70,7 @@
} - +
@if (_image != string.Empty) { @@ -93,7 +93,7 @@ private bool _haseditpermission = false; private string _image = string.Empty; private string _guid; - private Alert _alert = new Alert(); + private ModuleMessage _message = new ModuleMessage(); [Parameter] public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility @@ -217,8 +217,7 @@ { await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); - _alert.Type = AlertType.Danger; - _alert.Message = "Error Loading Files"; + _message.SetModuleMessage("Error Loading Files", MessageType.Error); } } @@ -274,8 +273,7 @@ { await logger.LogInformation("File Upload Succeeded {Files}", upload); - _alert.Type = AlertType.Success; - _alert.Message = "File Upload Succeeded"; + _message.SetModuleMessage("File Upload Succeeded", MessageType.Success); await GetFiles(); @@ -294,22 +292,19 @@ { await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", ")); - _alert.Type = AlertType.Danger; - _alert.Message = "File Upload Failed"; + _message.SetModuleMessage("File Upload Failed", MessageType.Error); } } catch (Exception ex) { await logger.LogError(ex, "File Upload Failed {Error}", ex.Message); - _alert.Type = AlertType.Danger; - _alert.Message = "File Upload Failed"; + _message.SetModuleMessage("File Upload Failed", MessageType.Error); } } else { - _alert.Type = AlertType.Warning; - _alert.Message = "You Have Not Selected A File To Upload"; + _message.SetModuleMessage("You Have Not Selected A File To Upload", MessageType.Warning); } } @@ -320,8 +315,7 @@ await FileService.DeleteFileAsync(FileId); await logger.LogInformation("File Deleted {File}", FileId); - _alert.Type = AlertType.Success; - _alert.Message = "File Deleted"; + _message.SetModuleMessage("File Deleted", MessageType.Success); await GetFiles(); FileId = -1; @@ -332,8 +326,7 @@ { await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); - _alert.Type = AlertType.Danger; - _alert.Message = "Error Deleting File"; + _message.SetModuleMessage("Error Deleting File", MessageType.Error); } } From 913ad53302c7e87ccdcd138cc8489ca9dc3bd7b1 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sun, 20 Sep 2020 15:43:01 +0300 Subject: [PATCH 028/114] Use ModuleMessage everywhere --- Oqtane.Client/Modules/Controls/RichTextEditor.razor | 9 +++------ Oqtane.Client/UI/Installer.razor | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 5eeb17a2..8b578294 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -8,7 +8,7 @@ @if (_filemanagervisible) { - @((MarkupString)_message) +
}
@@ -85,7 +85,7 @@ private FileManager _fileManager; private string _content = string.Empty; private string _original = string.Empty; - private string _message = string.Empty; + private ModuleMessage _message = new ModuleMessage(); [Parameter] public string Content { get; set; } @@ -144,7 +144,6 @@ public void CloseFileManager() { _filemanagervisible = false; - _message = string.Empty; StateHasChanged(); } @@ -189,17 +188,15 @@ var interop = new RichTextEditorInterop(JSRuntime); await interop.InsertImage(_editorElement, ContentUrl(fileid)); _filemanagervisible = false; - _message = string.Empty; } else { - _message = "
You Must Select An Image To Insert
"; + _message.SetModuleMessage("You Must Select An Image To Insert", MessageType.Warning); } } else { _filemanagervisible = true; - _message = string.Empty; } StateHasChanged(); } diff --git a/Oqtane.Client/UI/Installer.razor b/Oqtane.Client/UI/Installer.razor index 204197f6..a9f29fdc 100644 --- a/Oqtane.Client/UI/Installer.razor +++ b/Oqtane.Client/UI/Installer.razor @@ -119,7 +119,7 @@


- @((MarkupString) _message) +
@@ -135,7 +135,7 @@ private string _hostPassword = ""; private string _confirmPassword = ""; private string _hostEmail = ""; - private string _message = ""; + private ModuleMessage _message = new ModuleMessage(); private string _integratedSecurityDisplay = "display: none;"; private string _loadingDisplay = "display: none;"; @@ -201,13 +201,13 @@ } else { - _message = "
" + installation.Message + "
"; + _message.SetModuleMessage(installation.Message, MessageType.Error); _loadingDisplay = "display: none;"; } } else { - _message = "
Please Enter All Fields And Ensure Passwords Match And Are Greater Than 5 Characters In Length
"; + _message.SetModuleMessage("Please Enter All Fields And Ensure Passwords Match And Are Greater Than 5 Characters In Length", MessageType.Error); } } From 0044f031aaea840cd0dcbdf064fd6f57363679e6 Mon Sep 17 00:00:00 2001 From: hishamco Date: Wed, 23 Sep 2020 11:29:05 +0300 Subject: [PATCH 029/114] Set component params instead of SetModuleMessage --- .../Modules/Controls/FileManager.razor | 21 ++++++++++++------- .../Modules/Controls/RichTextEditor.razor | 3 ++- Oqtane.Client/UI/Installer.razor | 6 ++++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 34b098b2..596de1a6 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -217,7 +217,8 @@ { await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); - _message.SetModuleMessage("Error Loading Files", MessageType.Error); + _message.Message = "Error Loading Files"; + _message.Type = MessageType.Error; } } @@ -273,7 +274,8 @@ { await logger.LogInformation("File Upload Succeeded {Files}", upload); - _message.SetModuleMessage("File Upload Succeeded", MessageType.Success); + _message.Message = "File Upload Succeeded"; + _message.Type = MessageType.Success; await GetFiles(); @@ -292,19 +294,22 @@ { await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", ")); - _message.SetModuleMessage("File Upload Failed", MessageType.Error); + _message.Message = "File Upload Failed"; + _message.Type = MessageType.Error; } } catch (Exception ex) { await logger.LogError(ex, "File Upload Failed {Error}", ex.Message); - _message.SetModuleMessage("File Upload Failed", MessageType.Error); + _message.Message = "File Upload Failed"; + _message.Type = MessageType.Error; } } else { - _message.SetModuleMessage("You Have Not Selected A File To Upload", MessageType.Warning); + _message.Message = "You Have Not Selected A File To Upload"; + _message.Type = MessageType.Warning; } } @@ -315,7 +320,8 @@ await FileService.DeleteFileAsync(FileId); await logger.LogInformation("File Deleted {File}", FileId); - _message.SetModuleMessage("File Deleted", MessageType.Success); + _message.Message = "File Deleted"; + _message.Type = MessageType.Success; await GetFiles(); FileId = -1; @@ -326,7 +332,8 @@ { await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); - _message.SetModuleMessage("Error Deleting File", MessageType.Error); + _message.Message = "Error Deleting File"; + _message.Type = MessageType.Error; } } diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 8b578294..0d6d0a4e 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -191,7 +191,8 @@ } else { - _message.SetModuleMessage("You Must Select An Image To Insert", MessageType.Warning); + _message.Message = "You Must Select An Image To Insert"; + _message.Type = MessageType.Warning; } } else diff --git a/Oqtane.Client/UI/Installer.razor b/Oqtane.Client/UI/Installer.razor index a9f29fdc..11c0eec7 100644 --- a/Oqtane.Client/UI/Installer.razor +++ b/Oqtane.Client/UI/Installer.razor @@ -201,13 +201,15 @@ } else { - _message.SetModuleMessage(installation.Message, MessageType.Error); + _message.Message = installation.Message; + _message.Type = MessageType.Error; _loadingDisplay = "display: none;"; } } else { - _message.SetModuleMessage("Please Enter All Fields And Ensure Passwords Match And Are Greater Than 5 Characters In Length", MessageType.Error); + _message.Message = "Please Enter All Fields And Ensure Passwords Match And Are Greater Than 5 Characters In Length"; + _message.Type = MessageType.Error; } } From 0796ce54a9a04c9cb9a1a73b26c7149dc565b127 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 17:30:56 +0300 Subject: [PATCH 030/114] Add localization settings --- .../Localization/LocalizationSettings.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs diff --git a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs new file mode 100644 index 00000000..80811310 --- /dev/null +++ b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace Oqtane.Infrastructure.Localization +{ + public static class LocalizationSettings + { + private const string EnglishCulture = "en-US"; + + static LocalizationSettings() + { + DefaultCulture = EnglishCulture; + SupportedCultures = new List { DefaultCulture }; + } + + public static string DefaultCulture { get; set; } + + public static IList SupportedCultures { get; set; } + } +} From edecfa10cdc464a5b6007fce74ec3fff749db5c6 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 17:31:54 +0300 Subject: [PATCH 031/114] Load satellite assemblies on startup --- .../OqtaneServiceCollectionExtensions.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index f49d189a..e474ab8f 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.Loader; using Microsoft.Extensions.Hosting; using Oqtane.Infrastructure; +using Oqtane.Infrastructure.Localization; using Oqtane.Modules; using Oqtane.Services; using Oqtane.UI; @@ -14,10 +15,14 @@ namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { + private static readonly string StalliteAssemblyExtension = ".resources.dll"; + public static IServiceCollection AddOqtaneParts(this IServiceCollection services, Runtime runtime) { LoadAssemblies(); + LoadSatelliteAssemblies(); services.AddOqtaneServices(runtime); + return services; } @@ -119,6 +124,46 @@ namespace Microsoft.Extensions.DependencyInjection } } + private static void LoadSatelliteAssemblies() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); + if (assemblyPath == null) + { + return; + } + + AssemblyLoadContext.Default.Resolving += ResolveDependencies; + + foreach (var culture in LocalizationSettings.SupportedCultures) + { + var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(StalliteAssemblyExtension)) + { + AssemblyName assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); + } + catch + { + Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); + continue; + } + + try + { + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); + Console.WriteLine($"Loaded : {assemblyName}"); + } + catch (Exception e) + { + Console.WriteLine($"Failed : {assemblyName}\n{e}"); + } + } + } + } + private static Assembly ResolveDependencies(AssemblyLoadContext context, AssemblyName name) { var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location) + "\\" + name.Name + ".dll"; From 396d584615a46a5eaa06212de4699ded55b106a5 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 18:01:57 +0300 Subject: [PATCH 032/114] Dowanlod satellite assemblies to the browser --- .../Controllers/InstallationController.cs | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 50b45710..f1ef2a8a 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -1,17 +1,17 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using Oqtane.Models; -using Oqtane.Shared; -using Oqtane.Infrastructure; -using System; +using System; using System.IO; using System.Reflection; using System.Linq; using System.IO.Compression; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Oqtane.Infrastructure; +using Oqtane.Infrastructure.Localization; +using Oqtane.Models; using Oqtane.Modules; +using Oqtane.Shared; using Oqtane.Themes; -using System.Diagnostics; namespace Oqtane.Controllers { @@ -73,6 +73,16 @@ 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 binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + + // Get the satellite assemblies + foreach (var cultureFolder in LocalizationSettings.SupportedCultures) + { + foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(Path.GetDirectoryName(binFolder), cultureFolder))) + { + list.Add(Path.Combine(cultureFolder, Path.GetFileNameWithoutExtension(resourceFile))); + } + } // get module and theme dependencies foreach (var assembly in assemblies) @@ -96,7 +106,6 @@ namespace Oqtane.Controllers } // create zip file containing assemblies and debug symbols - string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); byte[] zipfile; using (var memoryStream = new MemoryStream()) { @@ -106,17 +115,17 @@ namespace Oqtane.Controllers foreach (string file in list) { entry = archive.CreateEntry(file + ".dll"); - using (var filestream = new FileStream(Path.Combine(binfolder, file + ".dll"), FileMode.Open, FileAccess.Read)) + using (var filestream = new FileStream(Path.Combine(binFolder, file + ".dll"), FileMode.Open, FileAccess.Read)) using (var entrystream = entry.Open()) { 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"))) + if (System.IO.File.Exists(Path.Combine(binFolder, file + ".pdb"))) { entry = archive.CreateEntry(file + ".pdb"); - using (var filestream = new FileStream(Path.Combine(binfolder, file + ".pdb"), FileMode.Open, FileAccess.Read)) + using (var filestream = new FileStream(Path.Combine(binFolder, file + ".pdb"), FileMode.Open, FileAccess.Read)) using (var entrystream = entry.Open()) { filestream.CopyTo(entrystream); From ec73c958c97b677ae02fcdfd064eb0411224e437 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 18:03:24 +0300 Subject: [PATCH 033/114] AddOqtaneParts -> AddOqtane --- Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs | 2 +- Oqtane.Server/Startup.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index e474ab8f..b274faa5 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -17,7 +17,7 @@ namespace Microsoft.Extensions.DependencyInjection { private static readonly string StalliteAssemblyExtension = ".resources.dll"; - public static IServiceCollection AddOqtaneParts(this IServiceCollection services, Runtime runtime) + public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime) { LoadAssemblies(); LoadSatelliteAssemblies(); diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index ee53f340..f70397bb 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -197,7 +197,7 @@ namespace Oqtane services.AddTransient(); // load the external assemblies into the app domain, install services - services.AddOqtaneParts(_runtime); + services.AddOqtane(_runtime); services.AddMvc() .AddNewtonsoftJson() From accf947afd649516b5cf0e5df5e808ab7ab22c9b Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 18:28:02 +0300 Subject: [PATCH 034/114] LoadClientAssemblies adds satellite assemblies --- Oqtane.Client/Program.cs | 37 +++++++++++-------- .../OqtaneServiceCollectionExtensions.cs | 5 +-- Oqtane.Shared/Shared/Constants.cs | 2 + 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 8a1fd2b8..f0218d64 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -1,19 +1,18 @@ -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -using Microsoft.Extensions.DependencyInjection; -using System.Threading.Tasks; -using Oqtane.Services; -using System.Reflection; -using System; +using System; using System.Collections.Generic; +using System.IO; +using System.IO.Compression; using System.Linq; using System.Net.Http; -using System.Net.Http.Json; -using Oqtane.Modules; -using Oqtane.Shared; -using Oqtane.Providers; +using System.Reflection; +using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Authorization; -using System.IO.Compression; -using System.IO; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Oqtane.Modules; +using Oqtane.Providers; +using Oqtane.Shared; +using Oqtane.Services; namespace Oqtane.Client { @@ -101,8 +100,8 @@ namespace Oqtane.Client // asemblies and debug symbols are packaged in a zip file using (ZipArchive archive = new ZipArchive(new MemoryStream(zip))) { - Dictionary dlls = new Dictionary(); - Dictionary pdbs = new Dictionary(); + var dlls = new Dictionary(); + var pdbs = new Dictionary(); foreach (ZipArchiveEntry entry in archive.Entries) { @@ -115,7 +114,15 @@ namespace Oqtane.Client switch (Path.GetExtension(entry.Name)) { case ".dll": - dlls.Add(entry.Name, file); + // Loads the stallite assemblies early + if (entry.Name.EndsWith(Constants.StalliteAssemblyExtension)) + { + Assembly.Load(entry.Name); + } + else + { + dlls.Add(entry.Name, file); + } break; case ".pdb": pdbs.Add(entry.Name, file); diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index b274faa5..a51595ca 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -8,6 +8,7 @@ using Oqtane.Infrastructure; using Oqtane.Infrastructure.Localization; using Oqtane.Modules; using Oqtane.Services; +using Oqtane.Shared; using Oqtane.UI; // ReSharper disable once CheckNamespace @@ -15,8 +16,6 @@ namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - private static readonly string StalliteAssemblyExtension = ".resources.dll"; - public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime) { LoadAssemblies(); @@ -138,7 +137,7 @@ namespace Microsoft.Extensions.DependencyInjection foreach (var culture in LocalizationSettings.SupportedCultures) { var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); - foreach (var assemblyFile in assembliesFolder.EnumerateFiles(StalliteAssemblyExtension)) + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) { AssemblyName assemblyName; try diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index c237857d..7b9b3a0e 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -57,5 +57,7 @@ namespace Oqtane.Shared (Char) 28, (Char) 29, (Char) 30, (Char) 31, ':', '*', '?', '\\', '/' }; public static readonly string[] InvalidFileNameEndingChars = { ".", " " }; + + public static readonly string StalliteAssemblyExtension = ".resources.dll"; } } From 7f28c5f2ffc58f197c836ab25ec451ec4a06820e Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 18:28:30 +0300 Subject: [PATCH 035/114] Add localization service to Oqtane.Client --- Oqtane.Client/Oqtane.Client.csproj | 1 + Oqtane.Client/Program.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index bff51215..515bf8f5 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -32,6 +32,7 @@ + diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index f0218d64..e7b6f632 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -27,6 +27,9 @@ namespace Oqtane.Client builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); + // Register localization services + builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); + // register auth services builder.Services.AddAuthorizationCore(); builder.Services.AddScoped(); From 468327d59764c62b2e1560ba0a69920cf154dfaf Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 18:29:18 +0300 Subject: [PATCH 036/114] Set localization RootNamespace to make it works --- Oqtane.Client/AssemblyInfo.cs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Oqtane.Client/AssemblyInfo.cs diff --git a/Oqtane.Client/AssemblyInfo.cs b/Oqtane.Client/AssemblyInfo.cs new file mode 100644 index 00000000..d598bfb9 --- /dev/null +++ b/Oqtane.Client/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using Microsoft.Extensions.Localization; + +[assembly: RootNamespace("Oqtane")] From 52d1d5841e70017e915e6b318f5295f7778ebe1c Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 18:50:06 +0300 Subject: [PATCH 037/114] Avoid looking for en-US culture resources --- Oqtane.Server/Controllers/InstallationController.cs | 11 ++++++++--- .../Extensions/OqtaneServiceCollectionExtensions.cs | 5 +++++ .../Localization/LocalizationSettings.cs | 5 ++--- Oqtane.Shared/Shared/Constants.cs | 2 ++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index f1ef2a8a..940ab6a8 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -76,11 +76,16 @@ namespace Oqtane.Controllers var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); // Get the satellite assemblies - foreach (var cultureFolder in LocalizationSettings.SupportedCultures) + foreach (var culture in LocalizationSettings.SupportedCultures) { - foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(Path.GetDirectoryName(binFolder), cultureFolder))) + if (culture == Constants.DefaultCulture) { - list.Add(Path.Combine(cultureFolder, Path.GetFileNameWithoutExtension(resourceFile))); + continue; + } + + foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(Path.GetDirectoryName(binFolder), culture))) + { + list.Add(Path.Combine(culture, Path.GetFileNameWithoutExtension(resourceFile))); } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index a51595ca..09776f45 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -136,6 +136,11 @@ namespace Microsoft.Extensions.DependencyInjection foreach (var culture in LocalizationSettings.SupportedCultures) { + if (culture == Constants.DefaultCulture) + { + continue; + } + var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) { diff --git a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs index 80811310..0e6ff714 100644 --- a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs +++ b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; +using Oqtane.Shared; namespace Oqtane.Infrastructure.Localization { public static class LocalizationSettings { - private const string EnglishCulture = "en-US"; - static LocalizationSettings() { - DefaultCulture = EnglishCulture; + DefaultCulture = Constants.DefaultCulture; SupportedCultures = new List { DefaultCulture }; } diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 7b9b3a0e..a45e2808 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -59,5 +59,7 @@ namespace Oqtane.Shared public static readonly string[] InvalidFileNameEndingChars = { ".", " " }; public static readonly string StalliteAssemblyExtension = ".resources.dll"; + + public static readonly string DefaultCulture = "en-US"; } } From ad9146ead1df7cb04eaacd2eec82821df218bde7 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 19:14:48 +0300 Subject: [PATCH 038/114] Fix stallite assemblies folder path --- Oqtane.Server/Controllers/InstallationController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 940ab6a8..06c3fb48 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -83,7 +83,7 @@ namespace Oqtane.Controllers continue; } - foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(Path.GetDirectoryName(binFolder), culture))) + foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(binFolder, culture))) { list.Add(Path.Combine(culture, Path.GetFileNameWithoutExtension(resourceFile))); } From b52dd571ee7814508c2129432ba7d275db5bc925 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 19:18:56 +0300 Subject: [PATCH 039/114] Fix loading bug --- Oqtane.Client/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index e7b6f632..912720d9 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -120,7 +120,7 @@ namespace Oqtane.Client // Loads the stallite assemblies early if (entry.Name.EndsWith(Constants.StalliteAssemblyExtension)) { - Assembly.Load(entry.Name); + Assembly.Load(file); } else { From 437170671f013a5ee290834ff6148f3ed4fbb9c4 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 20:20:38 +0300 Subject: [PATCH 040/114] Support server-sider localization --- Oqtane.Server/Oqtane.Server.csproj | 1 + Oqtane.Server/Pages/_Host.cshtml | 7 +++++++ Oqtane.Server/Startup.cs | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 44237543..31523442 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -43,6 +43,7 @@ + diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index 0fe00957..e4b6e5a7 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -1,10 +1,17 @@ @page "/" @namespace Oqtane.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@using System.Globalization +@using Microsoft.AspNetCore.Localization @using Microsoft.Extensions.Configuration @inject IConfiguration Configuration @model Oqtane.Pages.HostModel +@{ + // Set localization cookie + var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture)); + HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue); +} diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index f70397bb..7de3eceb 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -16,6 +17,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using Oqtane.Extensions; using Oqtane.Infrastructure; +using Oqtane.Infrastructure.Localization; using Oqtane.Repository; using Oqtane.Security; using Oqtane.Services; @@ -51,6 +53,10 @@ namespace Oqtane // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { + // Register localization services + services.AddLocalization(options => options.ResourcesPath = "Resources"); + CultureInfo.CurrentUICulture = new CultureInfo(LocalizationSettings.DefaultCulture); + services.AddServerSideBlazor(); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) @@ -225,6 +231,10 @@ namespace Oqtane } // to allow install middleware it should be moved up app.ConfigureOqtaneAssemblies(env); + + app.UseRequestLocalization(options => options + .AddSupportedUICultures(LocalizationSettings.SupportedCultures.ToArray())); + app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseBlazorFrameworkFiles(); From 2924e7849fe916484cf0e68e253eb5c06333be6a Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 21:23:22 +0300 Subject: [PATCH 041/114] Read supported cultures from appsettings.json --- .../ApplicationBuilderExtensions.cs | 29 +++++++++++++++++++ .../Localization/LocalizationSettings.cs | 2 +- Oqtane.Server/Startup.cs | 7 ++--- Oqtane.Server/appsettings.json | 4 +++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs index d1c77301..24bd3367 100644 --- a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs @@ -1,14 +1,43 @@ using System; +using System.Globalization; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Oqtane.Infrastructure; +using Oqtane.Infrastructure.Localization; namespace Oqtane.Extensions { public static class ApplicationBuilderExtensions { + private static readonly string DefaultCultureKey = "Localization:DefaultCulture"; + private static readonly string SupportedCulturesKey = "Localization:SupportedCultures"; + + public static IApplicationBuilder UseOqtaneLocalization(this IApplicationBuilder app) + { + var configuration = app.ApplicationServices.GetService(); + var defaultCulture = configuration.GetSection(DefaultCultureKey).Value; + var supportedCultures = configuration.GetSection(SupportedCulturesKey).Get(); + if (supportedCultures.Length > 0) + { + LocalizationSettings.SupportedCultures.AddRange(supportedCultures); + } + + LocalizationSettings.DefaultCulture = defaultCulture; + CultureInfo.CurrentUICulture = new CultureInfo(defaultCulture); + + app.UseRequestLocalization(options => { + options.SetDefaultCulture(defaultCulture) + .AddSupportedUICultures(supportedCultures) + .AddSupportedUICultures(supportedCultures); + }); + + return app; + } + public static IApplicationBuilder ConfigureOqtaneAssemblies(this IApplicationBuilder app, IWebHostEnvironment env) { var startUps = AppDomain.CurrentDomain diff --git a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs index 0e6ff714..38f74295 100644 --- a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs +++ b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs @@ -13,6 +13,6 @@ namespace Oqtane.Infrastructure.Localization public static string DefaultCulture { get; set; } - public static IList SupportedCultures { get; set; } + public static List SupportedCultures { get; } } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 7de3eceb..256d44a3 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -17,7 +16,6 @@ using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using Oqtane.Extensions; using Oqtane.Infrastructure; -using Oqtane.Infrastructure.Localization; using Oqtane.Repository; using Oqtane.Security; using Oqtane.Services; @@ -55,7 +53,6 @@ namespace Oqtane { // Register localization services services.AddLocalization(options => options.ResourcesPath = "Resources"); - CultureInfo.CurrentUICulture = new CultureInfo(LocalizationSettings.DefaultCulture); services.AddServerSideBlazor(); @@ -232,8 +229,8 @@ namespace Oqtane // to allow install middleware it should be moved up app.ConfigureOqtaneAssemblies(env); - app.UseRequestLocalization(options => options - .AddSupportedUICultures(LocalizationSettings.SupportedCultures.ToArray())); + // Allow oqtane localization middleware + app.UseOqtaneLocalization(); app.UseHttpsRedirection(); app.UseStaticFiles(); diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index 0ab499f0..743c6e19 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -11,5 +11,9 @@ "DefaultTheme": "", "DefaultLayout": "", "DefaultContainer": "" + }, + "Localization": { + "DefaultCulture": "en-US", + "SupportedCultures": [] } } \ No newline at end of file From f83c1b17419f34c3307c304739ebd32d1f930c8f Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 29 Sep 2020 22:12:03 +0300 Subject: [PATCH 042/114] Use invariant culture by default --- Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs | 6 +++++- Oqtane.Server/appsettings.json | 2 +- Oqtane.Shared/Shared/Constants.cs | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs index 24bd3367..476d8bee 100644 --- a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs @@ -21,12 +21,16 @@ namespace Oqtane.Extensions var configuration = app.ApplicationServices.GetService(); var defaultCulture = configuration.GetSection(DefaultCultureKey).Value; var supportedCultures = configuration.GetSection(SupportedCulturesKey).Get(); + if (defaultCulture == CultureInfo.InstalledUICulture.Name) + { + LocalizationSettings.DefaultCulture = defaultCulture; + } + if (supportedCultures.Length > 0) { LocalizationSettings.SupportedCultures.AddRange(supportedCultures); } - LocalizationSettings.DefaultCulture = defaultCulture; CultureInfo.CurrentUICulture = new CultureInfo(defaultCulture); app.UseRequestLocalization(options => { diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index 743c6e19..1af87b4c 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -13,7 +13,7 @@ "DefaultContainer": "" }, "Localization": { - "DefaultCulture": "en-US", + "DefaultCulture": "", "SupportedCultures": [] } } \ No newline at end of file diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index a45e2808..db62f416 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; namespace Oqtane.Shared { @@ -60,6 +61,6 @@ namespace Oqtane.Shared public static readonly string StalliteAssemblyExtension = ".resources.dll"; - public static readonly string DefaultCulture = "en-US"; + public static readonly string DefaultCulture = CultureInfo.InstalledUICulture.Name; } } From 2e2d46996ade6991431a1125b597ecb02ac23a33 Mon Sep 17 00:00:00 2001 From: hishamco Date: Wed, 30 Sep 2020 00:07:00 +0300 Subject: [PATCH 043/114] Refactoring --- .../Controllers/InstallationController.cs | 7 +-- .../ApplicationBuilderExtensions.cs | 48 +++++++----------- .../OqtaneServiceCollectionExtensions.cs | 49 ++++++++++--------- .../Interfaces/ILocalizationManager.cs | 9 ++++ .../Localization/LocalizationOptions.cs | 9 ++++ .../Localization/LocalizationSettings.cs | 18 ------- .../Infrastructure/LocalizationManager.cs | 29 +++++++++++ Oqtane.Server/Startup.cs | 6 +++ .../Extensions/EnumerableExtensions.cs | 8 +++ Oqtane.Shared/Shared/ServiceActivator.cs | 22 +++++++++ 10 files changed, 130 insertions(+), 75 deletions(-) create mode 100644 Oqtane.Server/Infrastructure/Interfaces/ILocalizationManager.cs create mode 100644 Oqtane.Server/Infrastructure/Localization/LocalizationOptions.cs delete mode 100644 Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs create mode 100644 Oqtane.Server/Infrastructure/LocalizationManager.cs create mode 100644 Oqtane.Shared/Extensions/EnumerableExtensions.cs create mode 100644 Oqtane.Shared/Shared/ServiceActivator.cs diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 06c3fb48..d3529a98 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Oqtane.Infrastructure; -using Oqtane.Infrastructure.Localization; using Oqtane.Models; using Oqtane.Modules; using Oqtane.Shared; @@ -21,12 +20,14 @@ namespace Oqtane.Controllers private readonly IConfigurationRoot _config; private readonly IInstallationManager _installationManager; private readonly IDatabaseManager _databaseManager; + private readonly ILocalizationManager _localizationManager; - public InstallationController(IConfigurationRoot config, IInstallationManager installationManager, IDatabaseManager databaseManager) + public InstallationController(IConfigurationRoot config, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager) { _config = config; _installationManager = installationManager; _databaseManager = databaseManager; + _localizationManager = localizationManager; } // POST api/ @@ -76,7 +77,7 @@ namespace Oqtane.Controllers var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); // Get the satellite assemblies - foreach (var culture in LocalizationSettings.SupportedCultures) + foreach (var culture in _localizationManager.GetSupportedCultures()) { if (culture == Constants.DefaultCulture) { diff --git a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs index 476d8bee..67676d16 100644 --- a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs @@ -4,44 +4,13 @@ using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Oqtane.Infrastructure; -using Oqtane.Infrastructure.Localization; namespace Oqtane.Extensions { public static class ApplicationBuilderExtensions { - private static readonly string DefaultCultureKey = "Localization:DefaultCulture"; - private static readonly string SupportedCulturesKey = "Localization:SupportedCultures"; - - public static IApplicationBuilder UseOqtaneLocalization(this IApplicationBuilder app) - { - var configuration = app.ApplicationServices.GetService(); - var defaultCulture = configuration.GetSection(DefaultCultureKey).Value; - var supportedCultures = configuration.GetSection(SupportedCulturesKey).Get(); - if (defaultCulture == CultureInfo.InstalledUICulture.Name) - { - LocalizationSettings.DefaultCulture = defaultCulture; - } - - if (supportedCultures.Length > 0) - { - LocalizationSettings.SupportedCultures.AddRange(supportedCultures); - } - - CultureInfo.CurrentUICulture = new CultureInfo(defaultCulture); - - app.UseRequestLocalization(options => { - options.SetDefaultCulture(defaultCulture) - .AddSupportedUICultures(supportedCultures) - .AddSupportedUICultures(supportedCultures); - }); - - return app; - } - public static IApplicationBuilder ConfigureOqtaneAssemblies(this IApplicationBuilder app, IWebHostEnvironment env) { var startUps = AppDomain.CurrentDomain @@ -55,5 +24,22 @@ namespace Oqtane.Extensions return app; } + + public static IApplicationBuilder UseOqtaneLocalization(this IApplicationBuilder app) + { + var localizationManager = app.ApplicationServices.GetService(); + var defaultCulture = localizationManager.GetDefaultCulture(); + var supportedCultures = localizationManager.GetSupportedCultures(); + + CultureInfo.CurrentUICulture = new CultureInfo(defaultCulture); + + app.UseRequestLocalization(options => { + options.SetDefaultCulture(defaultCulture) + .AddSupportedUICultures(supportedCultures) + .AddSupportedUICultures(supportedCultures); + }); + + return app; + } } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 09776f45..4090be8d 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Runtime.Loader; using Microsoft.Extensions.Hosting; using Oqtane.Infrastructure; -using Oqtane.Infrastructure.Localization; using Oqtane.Modules; using Oqtane.Services; using Oqtane.Shared; @@ -134,35 +133,39 @@ namespace Microsoft.Extensions.DependencyInjection AssemblyLoadContext.Default.Resolving += ResolveDependencies; - foreach (var culture in LocalizationSettings.SupportedCultures) + using (var serviceScope = ServiceActivator.GetScope()) { - if (culture == Constants.DefaultCulture) + var localizationManager = serviceScope.ServiceProvider.GetService(); + foreach (var culture in localizationManager.GetSupportedCultures()) { - continue; - } - - var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); - foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) - { - AssemblyName assemblyName; - try + if (culture == Constants.DefaultCulture) { - assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); - } - catch - { - Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); continue; } - try + var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) { - Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); - Console.WriteLine($"Loaded : {assemblyName}"); - } - catch (Exception e) - { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); + AssemblyName assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); + } + catch + { + Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); + continue; + } + + try + { + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); + Console.WriteLine($"Loaded : {assemblyName}"); + } + catch (Exception e) + { + Console.WriteLine($"Failed : {assemblyName}\n{e}"); + } } } } diff --git a/Oqtane.Server/Infrastructure/Interfaces/ILocalizationManager.cs b/Oqtane.Server/Infrastructure/Interfaces/ILocalizationManager.cs new file mode 100644 index 00000000..fa20eef4 --- /dev/null +++ b/Oqtane.Server/Infrastructure/Interfaces/ILocalizationManager.cs @@ -0,0 +1,9 @@ +namespace Oqtane.Infrastructure +{ + public interface ILocalizationManager + { + string GetDefaultCulture(); + + string[] GetSupportedCultures(); + } +} diff --git a/Oqtane.Server/Infrastructure/Localization/LocalizationOptions.cs b/Oqtane.Server/Infrastructure/Localization/LocalizationOptions.cs new file mode 100644 index 00000000..6330130e --- /dev/null +++ b/Oqtane.Server/Infrastructure/Localization/LocalizationOptions.cs @@ -0,0 +1,9 @@ +namespace Oqtane.Infrastructure +{ + public class LocalizationOptions + { + public string DefaultCulture { get; set; } + + public string[] SupportedCultures { get; set; } + } +} diff --git a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs b/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs deleted file mode 100644 index 38f74295..00000000 --- a/Oqtane.Server/Infrastructure/Localization/LocalizationSettings.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using Oqtane.Shared; - -namespace Oqtane.Infrastructure.Localization -{ - public static class LocalizationSettings - { - static LocalizationSettings() - { - DefaultCulture = Constants.DefaultCulture; - SupportedCultures = new List { DefaultCulture }; - } - - public static string DefaultCulture { get; set; } - - public static List SupportedCultures { get; } - } -} diff --git a/Oqtane.Server/Infrastructure/LocalizationManager.cs b/Oqtane.Server/Infrastructure/LocalizationManager.cs new file mode 100644 index 00000000..22b4ca79 --- /dev/null +++ b/Oqtane.Server/Infrastructure/LocalizationManager.cs @@ -0,0 +1,29 @@ +using System.Collections; +using Microsoft.Extensions.Options; +using Oqtane.Shared; + +namespace Oqtane.Infrastructure +{ + public class LocalizationManager : ILocalizationManager + { + private static readonly string DefaultCulture = Constants.DefaultCulture; + private static readonly string[] SupportedCultures = new[] { DefaultCulture }; + + private readonly LocalizationOptions _localizationOptions; + + public LocalizationManager(IOptions localizationOptions) + { + _localizationOptions = localizationOptions.Value; + } + + public string GetDefaultCulture() + => string.IsNullOrEmpty(_localizationOptions.DefaultCulture) + ? DefaultCulture + : _localizationOptions.DefaultCulture; + + public string[] GetSupportedCultures() + => _localizationOptions.SupportedCultures.IsNullOrEmpty() + ? SupportedCultures + : _localizationOptions.SupportedCultures; + } +} diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 256d44a3..98d43bcd 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -128,6 +128,8 @@ namespace Oqtane .AddSignInManager() .AddDefaultTokenProviders(); + services.Configure(Configuration.GetSection("Localization")); + services.Configure(options => { // Password settings @@ -190,6 +192,7 @@ namespace Oqtane services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -199,6 +202,9 @@ namespace Oqtane services.AddTransient(); services.AddTransient(); + // TODO: Check if there's a better way instead of building service provider + ServiceActivator.Configure(services.BuildServiceProvider()); + // load the external assemblies into the app domain, install services services.AddOqtane(_runtime); diff --git a/Oqtane.Shared/Extensions/EnumerableExtensions.cs b/Oqtane.Shared/Extensions/EnumerableExtensions.cs new file mode 100644 index 00000000..a4bdde7c --- /dev/null +++ b/Oqtane.Shared/Extensions/EnumerableExtensions.cs @@ -0,0 +1,8 @@ +namespace System.Collections +{ + public static class EnumerableExtensions + { + public static bool IsNullOrEmpty(this IEnumerable source) + => source == null || source.GetEnumerator().MoveNext() == false; + } +} diff --git a/Oqtane.Shared/Shared/ServiceActivator.cs b/Oqtane.Shared/Shared/ServiceActivator.cs new file mode 100644 index 00000000..5718d174 --- /dev/null +++ b/Oqtane.Shared/Shared/ServiceActivator.cs @@ -0,0 +1,22 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Oqtane.Shared +{ + public static class ServiceActivator + { + private static IServiceProvider _serviceProvider = null; + + public static void Configure(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public static IServiceScope GetScope(IServiceProvider serviceProvider = null) + { + var provider = serviceProvider ?? _serviceProvider; + + return provider?.GetRequiredService().CreateScope(); + } + } +} From f70fed66ae4388028dffbfcfea7c9eb234e17bcb Mon Sep 17 00:00:00 2001 From: Michael Atwood Date: Wed, 30 Sep 2020 16:22:46 -0700 Subject: [PATCH 044/114] add default class 'container' for div in pane to avoid content squishing --- Oqtane.Client/UI/Pane.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 97be40fa..88f677b5 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -13,7 +13,7 @@
@code { - private string _paneadminborder = ""; + private string _paneadminborder = "container"; private string _panetitle = ""; [CascadingParameter] @@ -33,7 +33,7 @@ } else { - _paneadminborder = ""; + _paneadminborder = "container"; _panetitle = ""; } From 6e41cd850e8504a18c5bb1e2526134579ee74f6d Mon Sep 17 00:00:00 2001 From: Michael Atwood Date: Wed, 30 Sep 2020 22:53:41 -0700 Subject: [PATCH 045/114] allows page to find Custom Index page in Module from Actions Property --- Oqtane.Client/UI/SiteRouter.razor | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index c395a868..797f962b 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -76,7 +76,7 @@ User user = null; List modules; var moduleid = -1; - var action = string.Empty; + var action = Constants.DefaultAction; var urlparameters = string.Empty; var editmode = false; var reload = Reload.None; @@ -459,25 +459,18 @@ typename = Constants.ErrorModule; } - if (module.ModuleId == moduleid && action != "") + // check if the module defines custom routes*@ + if (module.ModuleDefinition.ControlTypeRoutes != "") { - // check if the module defines custom routes - if (module.ModuleDefinition.ControlTypeRoutes != "") + foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { - foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) + if (route.StartsWith(action + "=")) { - if (route.StartsWith(action + "=")) - { - typename = route.Replace(action + "=", ""); - } + typename = route.Replace(action + "=", ""); } } - module.ModuleType = typename.Replace(Constants.ActionToken, action); - } - else - { - module.ModuleType = typename.Replace(Constants.ActionToken, Constants.DefaultAction); } + module.ModuleType = typename.Replace(Constants.ActionToken, action); // get additional metadata from IModuleControl interface typename = module.ModuleType; From 2a402497cf12196ff7c938b834382719df307152 Mon Sep 17 00:00:00 2001 From: Michael Atwood Date: Thu, 1 Oct 2020 16:02:14 -0700 Subject: [PATCH 046/114] only add div on admin border --- Oqtane.Client/UI/Pane.razor | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 88f677b5..a3429cca 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -1,18 +1,23 @@ -@using Microsoft.AspNetCore.Components.Rendering +@using Microsoft.AspNetCore.Components.Rendering @namespace Oqtane.UI @inject IUserService UserService @inject IModuleService ModuleService @inject IModuleDefinitionService ModuleDefinitionService -
- @if (_panetitle != "") - { +@if (_useadminborder) +{ +
@((MarkupString)_panetitle) - } + @DynamicComponent +
+} +else +{ @DynamicComponent -
+} @code { + private bool _useadminborder = false; private string _paneadminborder = "container"; private string _panetitle = ""; @@ -26,8 +31,9 @@ protected override void OnParametersSet() { - if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions) && Name != Constants.AdminPane) + if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && Name != Constants.AdminPane) { + _useadminborder = true; _paneadminborder = "app-pane-admin-border"; _panetitle = "
" + Name + " Pane
"; } @@ -47,8 +53,8 @@ if (module != null && !module.IsDeleted) { var typename = module.ModuleType; - // check for core module actions component - if (Constants.DefaultModuleActions.Contains(PageState.Action)) + // check for core module actions component + if (Constants.DefaultModuleActions.Contains(PageState.Action)) { typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, PageState.Action); } @@ -94,8 +100,8 @@ } else { - // module control does not exist with name specified - } + // module control does not exist with name specified + } } } } @@ -106,8 +112,8 @@ Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId); if (module != null && module.Pane.ToLower() == Name.ToLower() && !module.IsDeleted) { - // check if user is authorized to view module - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) + // check if user is authorized to view module + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) { CreateComponent(builder, module); } @@ -117,8 +123,8 @@ { foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower() && !item.IsDeleted).OrderBy(x => x.Order).ToArray()) { - // check if user is authorized to view module - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) + // check if user is authorized to view module + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) { CreateComponent(builder, module); } @@ -135,4 +141,4 @@ builder.SetKey(module.PageModuleId); builder.CloseComponent(); } -} +} \ No newline at end of file From c2ca55627e9590484651fb85e1a45ad0283c98bd Mon Sep 17 00:00:00 2001 From: Michael Atwood Date: Sat, 3 Oct 2020 12:12:23 -0700 Subject: [PATCH 047/114] comment where index page is specifed if no action --- Oqtane.Client/UI/SiteRouter.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 797f962b..a93661b7 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -202,6 +202,7 @@ { modIdPos = i + 1; actionPos = modIdPos + 1; + // Route to index page if no action is specifed if (actionPos > segments.Length - 1) { action = Constants.DefaultAction; From bcb6c81e439900a9ffa68539af8141d4ff5afda8 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 3 Oct 2020 22:41:48 +0300 Subject: [PATCH 048/114] Avoid Building ServiceProvider in ConfigureServices --- .../OqtaneServiceCollectionExtensions.cs | 54 +++++++++---------- Oqtane.Server/Startup.cs | 19 ++++--- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 4090be8d..0b94b088 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -15,10 +15,10 @@ namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime) + public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime, string[] supportedCultures) { LoadAssemblies(); - LoadSatelliteAssemblies(); + LoadSatelliteAssemblies(supportedCultures); services.AddOqtaneServices(runtime); return services; @@ -122,7 +122,7 @@ namespace Microsoft.Extensions.DependencyInjection } } - private static void LoadSatelliteAssemblies() + private static void LoadSatelliteAssemblies(string[] supportedCultures) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); @@ -133,39 +133,35 @@ namespace Microsoft.Extensions.DependencyInjection AssemblyLoadContext.Default.Resolving += ResolveDependencies; - using (var serviceScope = ServiceActivator.GetScope()) + foreach (var culture in supportedCultures) { - var localizationManager = serviceScope.ServiceProvider.GetService(); - foreach (var culture in localizationManager.GetSupportedCultures()) + if (culture == Constants.DefaultCulture) { - if (culture == Constants.DefaultCulture) + continue; + } + + var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) + { + AssemblyName assemblyName; + try { + assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); + } + catch + { + Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); continue; } - var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); - foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) + try { - AssemblyName assemblyName; - try - { - assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); - } - catch - { - Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); - continue; - } - - try - { - Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); - Console.WriteLine($"Loaded : {assemblyName}"); - } - catch (Exception e) - { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); - } + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); + Console.WriteLine($"Loaded : {assemblyName}"); + } + catch (Exception e) + { + Console.WriteLine($"Failed : {assemblyName}\n{e}"); } } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 98d43bcd..396e6602 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.IO; using System.Linq; using System.Net.Http; @@ -26,11 +27,14 @@ namespace Oqtane { public class Startup { - public IConfigurationRoot Configuration { get; } + private static readonly string[] DefaultSupportedCultures = new[] { Constants.DefaultCulture }; + private string _webRoot; private Runtime _runtime; private bool _useSwagger; + public IConfigurationRoot Configuration { get; } + public Startup(IWebHostEnvironment env) { var builder = new ConfigurationBuilder() @@ -128,7 +132,10 @@ namespace Oqtane .AddSignInManager() .AddDefaultTokenProviders(); - services.Configure(Configuration.GetSection("Localization")); + var localizationSection = Configuration.GetSection("Localization"); + var localizationOptions = localizationSection.Get(); + + services.Configure(localizationSection); services.Configure(options => { @@ -202,11 +209,11 @@ namespace Oqtane services.AddTransient(); services.AddTransient(); - // TODO: Check if there's a better way instead of building service provider - ServiceActivator.Configure(services.BuildServiceProvider()); - // load the external assemblies into the app domain, install services - services.AddOqtane(_runtime); + services.AddOqtane(_runtime, + localizationOptions.SupportedCultures.IsNullOrEmpty() + ? DefaultSupportedCultures + : localizationOptions.SupportedCultures); services.AddMvc() .AddNewtonsoftJson() From 6a7be12758204715d4dc0d3642223e72aa569585 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Sat, 3 Oct 2020 15:50:15 -0400 Subject: [PATCH 049/114] added DefaultAction property to IModule (#765) --- Oqtane.Client/UI/Pane.razor | 8 ++++---- Oqtane.Client/UI/SiteRouter.razor | 18 +++++++++--------- Oqtane.Server/appsettings.release.json | 6 +++++- Oqtane.Shared/Models/ModuleDefinition.cs | 3 +++ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index a3429cca..0c2c0f69 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -112,8 +112,8 @@ else Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId); if (module != null && module.Pane.ToLower() == Name.ToLower() && !module.IsDeleted) { - // check if user is authorized to view module - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) + // check if user is authorized to view module + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) { CreateComponent(builder, module); } @@ -123,8 +123,8 @@ else { foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower() && !item.IsDeleted).OrderBy(x => x.Order).ToArray()) { - // check if user is authorized to view module - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) + // check if user is authorized to view module + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) { CreateComponent(builder, module); } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index a93661b7..b79ea29d 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -202,21 +202,15 @@ { modIdPos = i + 1; actionPos = modIdPos + 1; - // Route to index page if no action is specifed - if (actionPos > segments.Length - 1) - { - action = Constants.DefaultAction; - } - else + if (actionPos <= segments.Length - 1) { action = segments[actionPos]; - } } } - // check if path has moduleid and action specification ie. pagename/moduleid/action/ + // check if path has moduleid and action specification ie. pagename/*/moduleid/action/ if (modIdPos > 0) { int.TryParse(segments[modIdPos], out result); @@ -460,7 +454,13 @@ typename = Constants.ErrorModule; } - // check if the module defines custom routes*@ + // handle default action + if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction)) + { + action = module.ModuleDefinition.DefaultAction; + } + + // check if the module defines custom action routes if (module.ModuleDefinition.ControlTypeRoutes != "") { foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) diff --git a/Oqtane.Server/appsettings.release.json b/Oqtane.Server/appsettings.release.json index 4fe3a03a..1af87b4c 100644 --- a/Oqtane.Server/appsettings.release.json +++ b/Oqtane.Server/appsettings.release.json @@ -1,8 +1,8 @@ { - "Runtime": "Server", "ConnectionStrings": { "DefaultConnection": "" }, + "Runtime": "Server", "Installation": { "DefaultAlias": "", "HostPassword": "", @@ -11,5 +11,9 @@ "DefaultTheme": "", "DefaultLayout": "", "DefaultContainer": "" + }, + "Localization": { + "DefaultCulture": "", + "SupportedCultures": [] } } \ No newline at end of file diff --git a/Oqtane.Shared/Models/ModuleDefinition.cs b/Oqtane.Shared/Models/ModuleDefinition.cs index 1e66735f..0fd8b892 100644 --- a/Oqtane.Shared/Models/ModuleDefinition.cs +++ b/Oqtane.Shared/Models/ModuleDefinition.cs @@ -20,6 +20,7 @@ namespace Oqtane.Models ServerManagerType = ""; ControlTypeRoutes = ""; ReleaseVersions = ""; + DefaultAction = ""; Runtimes = ""; Template = ""; } @@ -57,6 +58,8 @@ namespace Oqtane.Models public string ControlTypeRoutes { get; set; } [NotMapped] public string ReleaseVersions { get; set; } + [NotMapped] + public string DefaultAction { get; set; } // internal properties [NotMapped] From ce37d2f2d294c25c5e5bca927d3d1f9a4a70cbe8 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 3 Oct 2020 23:26:44 +0300 Subject: [PATCH 050/114] Skip missed satellite assemblies forlders --- .../Controllers/InstallationController.cs | 12 +++++- .../OqtaneServiceCollectionExtensions.cs | 43 +++++++++++-------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index d3529a98..29583e8a 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -79,14 +79,22 @@ namespace Oqtane.Controllers // Get the satellite assemblies foreach (var culture in _localizationManager.GetSupportedCultures()) { + var assembliesFolderPath = Path.Combine(binFolder, culture); if (culture == Constants.DefaultCulture) { continue; } - foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(binFolder, culture))) + if(Directory.Exists(assembliesFolderPath)) { - list.Add(Path.Combine(culture, Path.GetFileNameWithoutExtension(resourceFile))); + foreach (var resourceFile in Directory.EnumerateFiles(assembliesFolderPath)) + { + list.Add(Path.Combine(culture, Path.GetFileNameWithoutExtension(resourceFile))); + } + } + else + { + Console.WriteLine($"The satellite assemblies folder named '{culture}' is not found."); } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 0b94b088..540f399c 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -141,29 +141,36 @@ namespace Microsoft.Extensions.DependencyInjection } var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); - foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) + if (assembliesFolder.Exists) { - AssemblyName assemblyName; - try + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) { - assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); - } - catch - { - Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); - continue; - } + AssemblyName assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); + } + catch + { + Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); + continue; + } - try - { - Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); - Console.WriteLine($"Loaded : {assemblyName}"); - } - catch (Exception e) - { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); + try + { + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); + Console.WriteLine($"Loaded : {assemblyName}"); + } + catch (Exception e) + { + Console.WriteLine($"Failed : {assemblyName}\n{e}"); + } } } + else + { + Console.WriteLine($"The satellite assemblies folder named '{culture}' is not found."); + } } } From 3d7630d3d4521566580009d5632331915651b382 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Sun, 4 Oct 2020 10:43:09 -0400 Subject: [PATCH 051/114] Update README.md --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5b3af4e2..24ec4eea 100644 --- a/README.md +++ b/README.md @@ -38,15 +38,10 @@ Please note that this project is owned by the .NET Foundation and is governed by # Roadmap This project is a work in progress and the schedule for implementing enhancements is dependent upon the availability of community members who are willing/able to assist. -V.Next ( still in the process of being prioritized ) -- [ ] Admin UI markup optimization -- [ ] DB Migrations for framework installation/upgrade -- [ ] Support for SQLite +V.2.0.0 ( estimated release date Nov 10, 2020 ) +- [ ] Migrate to .NET 5 - [ ] Static Localization ( ie. labels, help text, etc.. ) -- [ ] Migrate to Code-Behind Pattern ( *.razor.cs ) -- [ ] Generic Repository Pattern -- [ ] JwT token authentication ( possibly using IdentityServer ) -- [ ] Optional Encryption for Settings Values +- [ ] Admin UI markup optimization V1.0.0 (MVP) - Released in conjunction with .NET Core 3.2 ( May 2020 ) - [x] Multi-Tenant ( Shared Database & Isolated Database ) @@ -66,6 +61,13 @@ V1.0.0 (MVP) - Released in conjunction with .NET Core 3.2 ( May 2020 ) - [x] Auto-Upgrade Framework - [x] Progressive Web Application Support +Future Consideration +- [ ] DB Migrations for framework installation/upgrade +- [ ] Support for SQLite +- [ ] Generic Repository Pattern +- [ ] JwT token authentication ( possibly using IdentityServer ) +- [ ] Optional Encryption for Settings Values + # Background Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and is inspired by the DotNetNuke web application framework. Initially created as a proof of concept, Oqtane is a native Blazor application written from the ground up using modern .NET Core technology. It is a modular application framework offering a fully dynamic page compositing model, multi-site support, designer friendly templates (skins), and extensibility via third party modules. From 0c0916c6ab2a4f41a4c1c48c20fde30da5992afb Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 5 Oct 2020 09:11:47 -0400 Subject: [PATCH 052/114] Fixed build warnings related to ModuleMessage component changes --- .../Modules/Controls/FileManager.razor | 37 +++++++++++-------- .../Modules/Controls/ModuleMessage.razor | 15 ++------ .../Modules/Controls/RichTextEditor.razor | 11 +++--- Oqtane.Client/Modules/MessageType.cs | 3 +- Oqtane.Client/UI/Installer.razor | 20 +++++----- Oqtane.Client/UI/ModuleInstance.razor | 9 +++-- Oqtane.Shared/Shared/Utilities.cs | 3 +- 7 files changed, 50 insertions(+), 48 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 596de1a6..7872aba0 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -70,7 +70,7 @@ } - + @if (_image != string.Empty) { @@ -93,7 +93,8 @@ private bool _haseditpermission = false; private string _image = string.Empty; private string _guid; - private ModuleMessage _message = new ModuleMessage(); + private string _message = string.Empty; + private MessageType _messagetype; [Parameter] public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility @@ -205,6 +206,7 @@ private async Task FolderChanged(ChangeEventArgs e) { + _message = string.Empty; try { FolderId = int.Parse((string)e.Value); @@ -217,13 +219,14 @@ { await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); - _message.Message = "Error Loading Files"; - _message.Type = MessageType.Error; + _message = "Error Loading Files"; + _messagetype = MessageType.Error; } } private async Task FileChanged(ChangeEventArgs e) { + _message = string.Empty; FileId = int.Parse((string)e.Value); await SetImage(); @@ -254,6 +257,7 @@ private async Task UploadFile() { + _message = string.Empty; var interop = new Interop(JSRuntime); var upload = await interop.GetFiles(_fileinputid); if (upload.Length > 0) @@ -274,8 +278,8 @@ { await logger.LogInformation("File Upload Succeeded {Files}", upload); - _message.Message = "File Upload Succeeded"; - _message.Type = MessageType.Success; + _message = "File Upload Succeeded"; + _messagetype = MessageType.Success; await GetFiles(); @@ -294,34 +298,35 @@ { await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", ")); - _message.Message = "File Upload Failed"; - _message.Type = MessageType.Error; + _message = "File Upload Failed"; + _messagetype = MessageType.Error; } } catch (Exception ex) { await logger.LogError(ex, "File Upload Failed {Error}", ex.Message); - _message.Message = "File Upload Failed"; - _message.Type = MessageType.Error; + _message = "File Upload Failed"; + _messagetype = MessageType.Error; } } else { - _message.Message = "You Have Not Selected A File To Upload"; - _message.Type = MessageType.Warning; + _message = "You Have Not Selected A File To Upload"; + _messagetype = MessageType.Warning; } } private async Task DeleteFile() { + _message = string.Empty; try { await FileService.DeleteFileAsync(FileId); await logger.LogInformation("File Deleted {File}", FileId); - _message.Message = "File Deleted"; - _message.Type = MessageType.Success; + _message = "File Deleted"; + _messagetype = MessageType.Success; await GetFiles(); FileId = -1; @@ -332,8 +337,8 @@ { await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); - _message.Message = "Error Deleting File"; - _message.Type = MessageType.Error; + _message = "Error Deleting File"; + _messagetype = MessageType.Error; } } diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index ad5957fa..171a8926 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -16,7 +16,7 @@ @code { private string _message = string.Empty; - private string _classname = "alert alert-danger"; + private string _classname = string.Empty; [Parameter] public string Message { get; set; } @@ -26,23 +26,16 @@ protected override void OnParametersSet() { - if (!string.IsNullOrEmpty(Message)) + _message = Message; + if (!string.IsNullOrEmpty(_message)) { - _message = Message; _classname = GetMessageType(Type); } } - public void SetModuleMessage(string message, MessageType type) - { - _message = message; - _classname = GetMessageType(type); - StateHasChanged(); - } - private string GetMessageType(MessageType type) { - var classname = string.Empty; + string classname = string.Empty; switch (type) { case MessageType.Success: diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 0d6d0a4e..3d7d2327 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -8,7 +8,7 @@ @if (_filemanagervisible) { - +
}
@@ -85,7 +85,7 @@ private FileManager _fileManager; private string _content = string.Empty; private string _original = string.Empty; - private ModuleMessage _message = new ModuleMessage(); + private string _message = string.Empty; [Parameter] public string Content { get; set; } @@ -107,7 +107,7 @@ public string DebugLevel { get; set; } = "info"; public override List Resources => new List() -{ + { new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.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" } @@ -144,6 +144,7 @@ public void CloseFileManager() { _filemanagervisible = false; + _message = string.Empty; StateHasChanged(); } @@ -180,6 +181,7 @@ public async Task InsertImage() { + _message = string.Empty; if (_filemanagervisible) { var fileid = _fileManager.GetFileId(); @@ -191,8 +193,7 @@ } else { - _message.Message = "You Must Select An Image To Insert"; - _message.Type = MessageType.Warning; + _message = "You Must Select An Image To Insert"; } } else diff --git a/Oqtane.Client/Modules/MessageType.cs b/Oqtane.Client/Modules/MessageType.cs index a78f95f9..561579b4 100644 --- a/Oqtane.Client/Modules/MessageType.cs +++ b/Oqtane.Client/Modules/MessageType.cs @@ -5,6 +5,7 @@ Success, Info, Warning, - Error + Error, + Undefined } } diff --git a/Oqtane.Client/UI/Installer.razor b/Oqtane.Client/UI/Installer.razor index 11c0eec7..8b915b5f 100644 --- a/Oqtane.Client/UI/Installer.razor +++ b/Oqtane.Client/UI/Installer.razor @@ -119,7 +119,7 @@


- +
@@ -129,13 +129,13 @@ private string _databaseType = "LocalDB"; private string _serverName = "(LocalDb)\\MSSQLLocalDB"; private string _databaseName = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm"); - private string _username = ""; - private string _password = ""; + private string _username = string.Empty; + private string _password = string.Empty; private string _hostUsername = Constants.HostUser; - private string _hostPassword = ""; - private string _confirmPassword = ""; - private string _hostEmail = ""; - private ModuleMessage _message = new ModuleMessage(); + private string _hostPassword = string.Empty; + private string _confirmPassword = string.Empty; + private string _hostEmail = string.Empty; + private string _message = string.Empty; private string _integratedSecurityDisplay = "display: none;"; private string _loadingDisplay = "display: none;"; @@ -201,15 +201,13 @@ } else { - _message.Message = installation.Message; - _message.Type = MessageType.Error; + _message = installation.Message; _loadingDisplay = "display: none;"; } } else { - _message.Message = "Please Enter All Fields And Ensure Passwords Match And Are Greater Than 5 Characters In Length"; - _message.Type = MessageType.Error; + _message = "Please Enter All Fields And Ensure Passwords Match And Are Greater Than 5 Characters In Length"; } } diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 8dfe2e03..80af124d 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,8 +1,7 @@ @namespace Oqtane.UI - + - @DynamicComponent @if (_progressindicator) @@ -12,6 +11,7 @@ @code { private string _message; + private MessageType _messagetype; private bool _progressindicator = false; [CascadingParameter] @@ -49,11 +49,13 @@ { // module does not exist with typename specified _message = "Module Does Not Have A Component Named " + Utilities.GetTypeNameLastSegment(typename, 0) + ".razor"; + _messagetype = MessageType.Error; } } else { _message = "Something is wrong with moduletype"; + _messagetype = MessageType.Error; } }; @@ -61,9 +63,10 @@ public void AddModuleMessage(string message, MessageType type) { + _message = message; + _messagetype = type; _progressindicator = false; StateHasChanged(); - ModuleMessage.SetModuleMessage(message, type); } public void ShowProgressIndicator() diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index ea36861b..c2cfc90f 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -326,7 +326,8 @@ namespace Oqtane.Shared public static bool IsPathOrFileValid(this string name) { - return (name.IndexOfAny(Constants.InvalidFileNameChars) == -1 && + return (name != null && + name.IndexOfAny(Constants.InvalidFileNameChars) == -1 && !Constants.InvalidFileNameEndingChars.Any(name.EndsWith) && !Constants.ReservedDevices.Split(',').Contains(name.ToUpper().Split('.')[0])); } From 7b3dfc49b25b5322fd4b493ef8c8ea8cdc36ab04 Mon Sep 17 00:00:00 2001 From: Mike Casas Date: Tue, 6 Oct 2020 08:11:00 -0400 Subject: [PATCH 053/114] Refactor to eliminate repetitive code. --- Oqtane.Client/Services/ServiceBase.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs index 2e891ca3..71e1ad78 100644 --- a/Oqtane.Client/Services/ServiceBase.cs +++ b/Oqtane.Client/Services/ServiceBase.cs @@ -173,13 +173,15 @@ namespace Oqtane.Services // add entityid parameter to url for custom authorization policy public string CreateAuthorizationPolicyUrl(string url, int entityId) { + string qs = "entityid=" + entityId.ToString(); + if (url.Contains("?")) { - return url + "&entityid=" + entityId.ToString(); + return url + "&" + qs; } else { - return url + "?entityid=" + entityId.ToString(); + return url + "?" + qs; } } From 3ab9510e2a6b2a5a2efa0d7c20b74f21ad1e4a98 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 8 Oct 2020 09:59:05 -0400 Subject: [PATCH 054/114] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24ec4eea..e9e2a140 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Future Consideration - [ ] DB Migrations for framework installation/upgrade - [ ] Support for SQLite - [ ] Generic Repository Pattern -- [ ] JwT token authentication ( possibly using IdentityServer ) +- [ ] Support for other Auth providers - [ ] Optional Encryption for Settings Values # Background From aad10ab1c4933da802c5d1fbe7a4242bad3afbfb Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 8 Oct 2020 11:20:43 -0400 Subject: [PATCH 055/114] Changes for .NET 5 --- Oqtane.Client/Oqtane.Client.csproj | 15 +++++++-------- Oqtane.Server/Controllers/PackageController.cs | 10 ++++------ Oqtane.Server/Oqtane.Server.csproj | 18 +++++++++--------- Oqtane.Shared/Oqtane.Shared.csproj | 8 ++++---- Oqtane.Test/Oqtane.Test.csproj | 16 +++++++--------- Oqtane.Upgrade/Oqtane.Upgrade.csproj | 2 +- 6 files changed, 32 insertions(+), 37 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 515bf8f5..e6dc8056 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -1,7 +1,7 @@ - + - netstandard2.1 + net5.0 Exe 7.3 3.0 @@ -28,12 +28,11 @@ - - - - - - + + + + + diff --git a/Oqtane.Server/Controllers/PackageController.cs b/Oqtane.Server/Controllers/PackageController.cs index 51194245..1c1752f1 100644 --- a/Oqtane.Server/Controllers/PackageController.cs +++ b/Oqtane.Server/Controllers/PackageController.cs @@ -34,8 +34,7 @@ namespace Oqtane.Controllers using (var httpClient = new HttpClient()) { - CancellationToken token; - var searchResult = await GetJson(httpClient, "https://azuresearch-usnc.nuget.org/query?q=tags:oqtane", token); + var searchResult = await GetJson(httpClient, "https://azuresearch-usnc.nuget.org/query?q=tags:oqtane"); foreach(Data data in searchResult.Data) { if (data.Tags.Contains(tag)) @@ -61,9 +60,8 @@ namespace Oqtane.Controllers { using (var httpClient = new HttpClient()) { - CancellationToken token; folder = Path.Combine(_environment.WebRootPath, folder); - var response = await httpClient.GetAsync("https://www.nuget.org/api/v2/package/" + packageid.ToLower() + "/" + version, token).ConfigureAwait(false); + var response = await httpClient.GetAsync("https://www.nuget.org/api/v2/package/" + packageid.ToLower() + "/" + version).ConfigureAwait(false); response.EnsureSuccessStatusCode(); string filename = packageid + "." + version + ".nupkg"; using (var fileStream = new FileStream(Path.Combine(folder, filename), FileMode.Create, FileAccess.Write, FileShare.None)) @@ -73,10 +71,10 @@ namespace Oqtane.Controllers } } - private async Task GetJson(HttpClient httpClient, string url, CancellationToken token) + private async Task GetJson(HttpClient httpClient, string url) { Uri uri = new Uri(url); - var response = await httpClient.GetAsync(uri, token).ConfigureAwait(false); + var response = await httpClient.GetAsync(uri).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var stream = await response.Content.ReadAsStreamAsync(); using (var streamReader = new StreamReader(stream)) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 31523442..795b546e 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0 7.3 Debug;Release 1.0.4 @@ -37,15 +37,15 @@ - - + + - - - - - - + + + + + + diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index 3ebd6b9b..0e80493c 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 7.3 Debug;Release 1.0.4 @@ -19,9 +19,9 @@ - - - + + + diff --git a/Oqtane.Test/Oqtane.Test.csproj b/Oqtane.Test/Oqtane.Test.csproj index 672b16e3..5fb17674 100644 --- a/Oqtane.Test/Oqtane.Test.csproj +++ b/Oqtane.Test/Oqtane.Test.csproj @@ -1,7 +1,7 @@ - + - netcoreapp3.1 + net5.0 7.3 Debug;Release 1.0.4 @@ -18,14 +18,12 @@ false - - - - - - + + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Oqtane.Upgrade/Oqtane.Upgrade.csproj b/Oqtane.Upgrade/Oqtane.Upgrade.csproj index 131934b5..73f4bad0 100644 --- a/Oqtane.Upgrade/Oqtane.Upgrade.csproj +++ b/Oqtane.Upgrade/Oqtane.Upgrade.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 7.3 Exe 1.0.4 From b3db92ee957ab7454bb96f934d4db9b8e84b7b93 Mon Sep 17 00:00:00 2001 From: hishamco Date: Fri, 9 Oct 2020 19:17:42 +0300 Subject: [PATCH 056/114] Add blazor error details on DEV environment --- Oqtane.Server/Startup.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 396e6602..976556b7 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -32,6 +32,7 @@ namespace Oqtane private string _webRoot; private Runtime _runtime; private bool _useSwagger; + private IWebHostEnvironment _env; public IConfigurationRoot Configuration { get; } @@ -49,6 +50,8 @@ namespace Oqtane _webRoot = env.WebRootPath; AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data")); + + _env = env; } // This method gets called by the runtime. Use this method to add services to the container. @@ -58,7 +61,13 @@ namespace Oqtane // Register localization services services.AddLocalization(options => options.ResourcesPath = "Resources"); - services.AddServerSideBlazor(); + services.AddServerSideBlazor().AddCircuitOptions(options => + { + if (_env.IsDevelopment()) + { + options.DetailedErrors = true; + } + }); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) if (!services.Any(x => x.ServiceType == typeof(HttpClient))) From 86bb6d1ea8fd4bb0c9efbc8a1561bc0b0223d8c4 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 10 Oct 2020 22:19:21 +0300 Subject: [PATCH 057/114] Simplify localization settings configurations --- .../Extensions/WebHostBuilderExtensions.cs | 21 +++++++++++++++++++ Oqtane.Server/Program.cs | 1 + Oqtane.Server/Startup.cs | 17 +++++---------- 3 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 Oqtane.Server/Extensions/WebHostBuilderExtensions.cs diff --git a/Oqtane.Server/Extensions/WebHostBuilderExtensions.cs b/Oqtane.Server/Extensions/WebHostBuilderExtensions.cs new file mode 100644 index 00000000..3e9b8fc7 --- /dev/null +++ b/Oqtane.Server/Extensions/WebHostBuilderExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Oqtane.Infrastructure; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class WebHostBuilderExtensions + { + public static IWebHostBuilder ConfigureLocalizationSettings(this IWebHostBuilder builder) + { + return builder.ConfigureServices((context, services) => + { + var config = context.Configuration; + + services.Configure(config.GetSection("Localization")); + services.AddSingleton(ctx => ctx.GetService>().Value); + services.AddTransient(); + }); + } + } +} diff --git a/Oqtane.Server/Program.cs b/Oqtane.Server/Program.cs index c4b5492f..1ac0797e 100644 --- a/Oqtane.Server/Program.cs +++ b/Oqtane.Server/Program.cs @@ -26,6 +26,7 @@ namespace Oqtane.Server .AddCommandLine(args) .Build()) .UseStartup() + .ConfigureLocalizationSettings() .Build(); } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 976556b7..f5c5e07b 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -27,22 +27,23 @@ namespace Oqtane { public class Startup { - private static readonly string[] DefaultSupportedCultures = new[] { Constants.DefaultCulture }; - private string _webRoot; private Runtime _runtime; private bool _useSwagger; private IWebHostEnvironment _env; + private string[] _supportedCultures; public IConfigurationRoot Configuration { get; } - public Startup(IWebHostEnvironment env) + public Startup(IWebHostEnvironment env, ILocalizationManager localizationManager) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); Configuration = builder.Build(); + _supportedCultures = localizationManager.GetSupportedCultures(); + _runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server; //add possibility to switch off swagger on production. @@ -141,11 +142,6 @@ namespace Oqtane .AddSignInManager() .AddDefaultTokenProviders(); - var localizationSection = Configuration.GetSection("Localization"); - var localizationOptions = localizationSection.Get(); - - services.Configure(localizationSection); - services.Configure(options => { // Password settings @@ -219,10 +215,7 @@ namespace Oqtane services.AddTransient(); // load the external assemblies into the app domain, install services - services.AddOqtane(_runtime, - localizationOptions.SupportedCultures.IsNullOrEmpty() - ? DefaultSupportedCultures - : localizationOptions.SupportedCultures); + services.AddOqtane(_runtime, _supportedCultures); services.AddMvc() .AddNewtonsoftJson() From 4b11bdc4be2bd32231e419d33d07531a99e26c00 Mon Sep 17 00:00:00 2001 From: hishamco Date: Mon, 12 Oct 2020 18:15:08 +0300 Subject: [PATCH 058/114] Support label localization --- Oqtane.Client/Modules/Controls/Label.razor | 20 ++++++++++++++++++++ Oqtane.Client/Oqtane.Client.csproj | 2 ++ Oqtane.Client/Program.cs | 2 ++ 3 files changed, 24 insertions(+) diff --git a/Oqtane.Client/Modules/Controls/Label.razor b/Oqtane.Client/Modules/Controls/Label.razor index 751b222a..edccb9de 100644 --- a/Oqtane.Client/Modules/Controls/Label.razor +++ b/Oqtane.Client/Modules/Controls/Label.razor @@ -1,5 +1,8 @@ @namespace Oqtane.Modules.Controls @inherits ModuleControlBase +@using Microsoft.AspNetCore.Http +@using Microsoft.Extensions.Localization +@inject IHttpContextAccessor HttpContextAccessor @if (!string.IsNullOrEmpty(HelpText)) { @@ -26,6 +29,9 @@ else [Parameter] public string HelpText { get; set; } // optional - tooltip for this label + [Parameter] + public string ResourceKey { get; set; } + protected override void OnParametersSet() { _openLabel = "@localizer[$"{ResourceKey}.Text"]; + HelpText = localizer[$"{ResourceKey}.{nameof(HelpText)}"]; + } + } } } diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 515bf8f5..e85799c8 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -32,6 +32,8 @@ + + diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 912720d9..9b29f544 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Oqtane.Modules; using Oqtane.Providers; @@ -26,6 +27,7 @@ namespace Oqtane.Client builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); + builder.Services.AddSingleton(); // Register localization services builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); From edc65e66c9b4449ad003b61ccc0ad6b366970b5b Mon Sep 17 00:00:00 2001 From: hishamco Date: Mon, 12 Oct 2020 18:26:04 +0300 Subject: [PATCH 059/114] Use AddHttpContextAccessor() --- Oqtane.Client/Oqtane.Client.csproj | 1 - Oqtane.Client/Program.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index e85799c8..eaff964a 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -33,7 +33,6 @@ - diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 9b29f544..7d3ea0a7 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -8,7 +8,6 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Oqtane.Modules; using Oqtane.Providers; @@ -27,7 +26,7 @@ namespace Oqtane.Client builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); - builder.Services.AddSingleton(); + builder.Services.AddHttpContextAccessor(); // Register localization services builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); From 4a90e6e64fc705de3566651ac2d3771bb269fcb6 Mon Sep 17 00:00:00 2001 From: hishamco Date: Thu, 15 Oct 2020 06:07:11 +0300 Subject: [PATCH 060/114] Use ServiceActivator instead of IHttpContextAccessor --- Oqtane.Client/Modules/Controls/Label.razor | 15 +++++++++------ Oqtane.Client/Oqtane.Client.csproj | 1 - Oqtane.Client/Program.cs | 6 ++++-- Oqtane.Server/Startup.cs | 2 ++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/Label.razor b/Oqtane.Client/Modules/Controls/Label.razor index edccb9de..0d32a14b 100644 --- a/Oqtane.Client/Modules/Controls/Label.razor +++ b/Oqtane.Client/Modules/Controls/Label.razor @@ -1,8 +1,6 @@ @namespace Oqtane.Modules.Controls @inherits ModuleControlBase -@using Microsoft.AspNetCore.Http @using Microsoft.Extensions.Localization -@inject IHttpContextAccessor HttpContextAccessor @if (!string.IsNullOrEmpty(HelpText)) { @@ -54,10 +52,15 @@ else var moduleType = Type.GetType(ModuleState.ModuleType); var localizerTypeName = $"Microsoft.Extensions.Localization.IStringLocalizer`1[[{moduleType.AssemblyQualifiedName}]], Microsoft.Extensions.Localization.Abstractions"; var localizerType = Type.GetType(localizerTypeName); - var localizer = (IStringLocalizer)HttpContextAccessor.HttpContext.RequestServices.GetService(localizerType); - - ChildContent = @@localizer[$"{ResourceKey}.Text"]; - HelpText = localizer[$"{ResourceKey}.{nameof(HelpText)}"]; + + // HACK: Use ServiceActivator instead of injecting IHttpContextAccessor, because HttpContext throws NRE in WebAssembly runtime + using (var scope = ServiceActivator.GetScope()) + { + var localizer = (IStringLocalizer)scope.ServiceProvider.GetService(localizerType); + + ChildContent = @@localizer[$"{ResourceKey}.Text"]; + HelpText = localizer[$"{ResourceKey}.{nameof(HelpText)}"]; + } } } } diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index eaff964a..515bf8f5 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -32,7 +32,6 @@ - diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 7d3ea0a7..d442141d 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -26,7 +26,6 @@ namespace Oqtane.Client builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); - builder.Services.AddHttpContextAccessor(); // Register localization services builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); @@ -89,8 +88,11 @@ namespace Oqtane.Client .ToList() .ForEach(x => x.ConfigureServices(builder.Services)); } + var host = builder.Build(); - await builder.Build().RunAsync(); + ServiceActivator.Configure(host.Services); + + await host.RunAsync(); } private static async Task LoadClientAssemblies(HttpClient http) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index f5c5e07b..2cff1aa0 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -231,6 +231,8 @@ namespace Oqtane // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + ServiceActivator.Configure(app.ApplicationServices); + if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); From 06c041dd4e0df517253431ca84f72967cc457a95 Mon Sep 17 00:00:00 2001 From: ijungleboy Date: Thu, 15 Oct 2020 10:38:25 +0200 Subject: [PATCH 061/114] Add Documentation attributes part of https://github.com/oqtane/oqtane.framework/issues/570 --- Oqtane.Shared/Documentation/InternalApi.cs | 28 +++++++++++++++++++ Oqtane.Shared/Documentation/PrivateApi.cs | 27 ++++++++++++++++++ Oqtane.Shared/Documentation/PublicApi.cs | 27 ++++++++++++++++++ .../Documentation/WorkInProgressApi.cs | 18 ++++++++++++ Oqtane.Shared/Documentation/readme.md | 7 +++++ 5 files changed, 107 insertions(+) create mode 100644 Oqtane.Shared/Documentation/InternalApi.cs create mode 100644 Oqtane.Shared/Documentation/PrivateApi.cs create mode 100644 Oqtane.Shared/Documentation/PublicApi.cs create mode 100644 Oqtane.Shared/Documentation/WorkInProgressApi.cs create mode 100644 Oqtane.Shared/Documentation/readme.md diff --git a/Oqtane.Shared/Documentation/InternalApi.cs b/Oqtane.Shared/Documentation/InternalApi.cs new file mode 100644 index 00000000..be660f77 --- /dev/null +++ b/Oqtane.Shared/Documentation/InternalApi.cs @@ -0,0 +1,28 @@ +using System; + +namespace Oqtane.Documentation +{ + /// + /// This attribute serves as metadata for other things to mark them as internal APIs. + /// Use this on stuff you want to document publicly, but mark as internal so people are warned + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + [PublicApi] + // ReSharper disable once InconsistentNaming + public class InternalApi_DoNotUse_MayChangeWithoutNotice: Attribute + { + /// + /// The `[InternalApi_DoNotUse_MayChangeWithoutNotice]` attribute can be used without additional comment. + /// + // Important note - this constructor looks unnecessary, because comment is optional in the other constructor + // but we need it because of a minor issue in docfx + public InternalApi_DoNotUse_MayChangeWithoutNotice() { } + + /// + /// Constructor with optional comment `[InternalApi_DoNotUse_MayChangeWithoutNotice(some-comment)]`. + /// + /// Reason why it's internal, optional + public InternalApi_DoNotUse_MayChangeWithoutNotice(string comment) { } + + } +} diff --git a/Oqtane.Shared/Documentation/PrivateApi.cs b/Oqtane.Shared/Documentation/PrivateApi.cs new file mode 100644 index 00000000..decd0c24 --- /dev/null +++ b/Oqtane.Shared/Documentation/PrivateApi.cs @@ -0,0 +1,27 @@ +using System; + +namespace Oqtane.Documentation +{ + /// + /// This attribute marks classes, methods, etc. as private APIs + /// So they should _not_ be publicly documented. + /// By default, all APIs are private, so you only need this attribute on children of classes marked with `[PublicApi]`. + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + [PublicApi] + public class PrivateApi: Attribute + { + /// + /// The `[PrivateApi]` attribute can be used without additional comment. + /// + // Important note - this constructor looks unnecessary, because comment could be optional in the other constructor + // but we need it because of a minor issue in docfx + public PrivateApi() { } + + /// + /// Constructor with optional comment `[PrivateApi(some-comment)]`. + /// + /// Reason why it's private, optional + public PrivateApi(string comment) { } + } +} diff --git a/Oqtane.Shared/Documentation/PublicApi.cs b/Oqtane.Shared/Documentation/PublicApi.cs new file mode 100644 index 00000000..0c84a785 --- /dev/null +++ b/Oqtane.Shared/Documentation/PublicApi.cs @@ -0,0 +1,27 @@ +using System; + +namespace Oqtane.Documentation +{ + /// + /// This attribute marks classes, properties etc. as public APIs. + /// Any API / code with this attribute will be published in the docs. + /// You can apply it to anything, but usually you will only need it on classes. + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + [PublicApi] + public class PublicApi: Attribute + { + /// + /// The `[PublicApi]` attribute can usually be used without additional comment. + /// + // Important note - this constructor looks unnecessary, because comment could be optional in the other constructor + // but we need it because of a minor issue in docfx + public PublicApi() { } + + /// + /// Constructor with optional comment `[PublicApi(some-comment)]` + /// + /// Reason why it's public, optional + public PublicApi(string comment) { } + } +} diff --git a/Oqtane.Shared/Documentation/WorkInProgressApi.cs b/Oqtane.Shared/Documentation/WorkInProgressApi.cs new file mode 100644 index 00000000..c4ed0d88 --- /dev/null +++ b/Oqtane.Shared/Documentation/WorkInProgressApi.cs @@ -0,0 +1,18 @@ +using System; + +namespace Oqtane.Documentation +{ + /// + /// This attribute marks APIs to be publicly documented with a clear warning that it's work in progress. + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + [PublicApi] + public class WorkInProgressApi: Attribute + { + /// + /// The `[WorkInProgressApi(some-comment)]` attributes must always have a comment why they are WIP. + /// + /// Reason why it's WIP, required + public WorkInProgressApi(string comment) { } + } +} diff --git a/Oqtane.Shared/Documentation/readme.md b/Oqtane.Shared/Documentation/readme.md new file mode 100644 index 00000000..cd55726a --- /dev/null +++ b/Oqtane.Shared/Documentation/readme.md @@ -0,0 +1,7 @@ +# Oqtane API Decorator Attributes + +This folder contains special attributes for the API Code Generator. + +The idea is that only items marked with special attributes are valide public APIs, and only these will be documented in the public docs + +As of 2020, all APIs are documented, and only these marked as `[PrivateApi]` will be excluded. In future, we may reverse this to only document things marked as `[PublicApi]`. \ No newline at end of file From 955e7a38562003a2d4b17ab31053c7bc4e9c5701 Mon Sep 17 00:00:00 2001 From: Tony Valenti Date: Fri, 16 Oct 2020 06:22:52 -0500 Subject: [PATCH 062/114] Factored out Contants.*** Role into RoleNames.*** Renamed 'AllUsers' to 'Everyone' --- Oqtane.Client/Modules/Admin/Error/Index.razor | 2 +- Oqtane.Client/Modules/Admin/Roles/Users.razor | 2 +- .../Modules/Admin/UserProfile/Index.razor | 4 +- Oqtane.Client/Modules/Admin/Users/Index.razor | 4 +- Oqtane.Client/Modules/Admin/Users/Roles.razor | 2 +- .../Modules/Controls/ActionDialog.razor | 4 +- .../Modules/Controls/ActionLink.razor | 4 +- .../Modules/Controls/FileManager.razor | 2 +- .../Modules/Controls/ModuleMessage.razor | 2 +- .../Modules/Controls/PermissionGrid.razor | 10 +- .../Themes/Controls/ControlPanel.razor | 16 +- .../Themes/Controls/ModuleActionsBase.cs | 10 +- Oqtane.Client/UI/Pane.razor | 4 +- Oqtane.Server/Controllers/AliasController.cs | 10 +- Oqtane.Server/Controllers/FileController.cs | 8 +- Oqtane.Server/Controllers/FolderController.cs | 10 +- .../Controllers/InstallationController.cs | 4 +- Oqtane.Server/Controllers/JobController.cs | 14 +- Oqtane.Server/Controllers/JobLogController.cs | 10 +- Oqtane.Server/Controllers/LogController.cs | 4 +- Oqtane.Server/Controllers/ModuleController.cs | 10 +- .../Controllers/ModuleDefinitionController.cs | 8 +- .../Controllers/NotificationController.cs | 10 +- .../Controllers/PackageController.cs | 4 +- Oqtane.Server/Controllers/PageController.cs | 12 +- .../Controllers/PageModuleController.cs | 8 +- .../Controllers/ProfileController.cs | 6 +- Oqtane.Server/Controllers/RoleController.cs | 10 +- .../Controllers/SettingController.cs | 6 +- Oqtane.Server/Controllers/SiteController.cs | 8 +- .../Controllers/SiteTemplateController.cs | 2 +- Oqtane.Server/Controllers/SqlController.cs | 2 +- Oqtane.Server/Controllers/SystemController.cs | 2 +- Oqtane.Server/Controllers/TenantController.cs | 10 +- Oqtane.Server/Controllers/ThemeController.cs | 6 +- Oqtane.Server/Controllers/UserController.cs | 16 +- .../Controllers/UserRoleController.cs | 10 +- .../Infrastructure/DatabaseManager.cs | 4 +- .../SiteTemplates/DefaultSiteTemplate.cs | 48 ++-- .../SiteTemplates/EmptySiteTemplate.cs | 6 +- .../Infrastructure/UpgradeManager.cs | 12 +- .../Repository/ModuleDefinitionRepository.cs | 6 +- Oqtane.Server/Repository/SiteRepository.cs | 208 +++++++++--------- .../Security/ClaimsPrincipalFactory.cs | 10 +- Oqtane.Shared/Security/UserSecurity.cs | 4 +- Oqtane.Shared/Shared/Constants.cs | 21 +- Oqtane.Shared/Shared/RoleNames.cs | 8 + 47 files changed, 298 insertions(+), 285 deletions(-) create mode 100644 Oqtane.Shared/Shared/RoleNames.cs diff --git a/Oqtane.Client/Modules/Admin/Error/Index.razor b/Oqtane.Client/Modules/Admin/Error/Index.razor index 9e0df574..7ddb0ce3 100644 --- a/Oqtane.Client/Modules/Admin/Error/Index.razor +++ b/Oqtane.Client/Modules/Admin/Error/Index.razor @@ -8,7 +8,7 @@ protected override async Task OnInitializedAsync() { Module module = await ModuleService.GetModuleAsync(ModuleState.ModuleId); - if (UserSecurity.IsAuthorized(PageState.User, Constants.HostRole)) + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { string message = "A Problem Was Encountered Loading Module " + module.ModuleDefinitionName; AddModuleMessage(message, MessageType.Error); diff --git a/Oqtane.Client/Modules/Admin/Roles/Users.razor b/Oqtane.Client/Modules/Admin/Roles/Users.razor index c292d3d5..a583aedc 100644 --- a/Oqtane.Client/Modules/Admin/Roles/Users.razor +++ b/Oqtane.Client/Modules/Admin/Roles/Users.razor @@ -88,7 +88,7 @@ else Role role = await RoleService.GetRoleAsync(roleid); name = role.Name; users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - users = users.Where(item => item.Role.Name == Constants.RegisteredRole).ToList(); + users = users.Where(item => item.Role.Name == RoleNames.Registered).ToList(); await GetUserRoles(); } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 9c718ef1..30e6b075 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -79,7 +79,7 @@ else @foreach (Profile profile in profiles) { var p = profile; - if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole)) + if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { if (p.Category != category) { @@ -299,7 +299,7 @@ else { settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue); } - if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole)) + if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) { diff --git a/Oqtane.Client/Modules/Admin/Users/Index.razor b/Oqtane.Client/Modules/Admin/Users/Index.razor index 682e2d3b..efcd89a2 100644 --- a/Oqtane.Client/Modules/Admin/Users/Index.razor +++ b/Oqtane.Client/Modules/Admin/Users/Index.razor @@ -58,10 +58,10 @@ else { if (string.IsNullOrEmpty(_search)) { - return allroles.Where(item => item.Role.Name == Constants.RegisteredRole).ToList(); + return allroles.Where(item => item.Role.Name == RoleNames.Registered).ToList(); } return allroles - .Where(item => item.Role.Name == Constants.RegisteredRole && + .Where(item => item.Role.Name == RoleNames.Registered && ( item.User.Username.Contains(search, StringComparison.OrdinalIgnoreCase) || item.User.Email.Contains(search, StringComparison.OrdinalIgnoreCase) || diff --git a/Oqtane.Client/Modules/Admin/Users/Roles.razor b/Oqtane.Client/Modules/Admin/Users/Roles.razor index a4e946df..9a056a43 100644 --- a/Oqtane.Client/Modules/Admin/Users/Roles.razor +++ b/Oqtane.Client/Modules/Admin/Users/Roles.razor @@ -63,7 +63,7 @@ else @context.Role.Name - @if (context.Role.Name != Constants.RegisteredRole) + @if (context.Role.Name != RoleNames.Registered) { } diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index fc22605c..94254ab9 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -134,10 +134,10 @@ authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions); break; case SecurityAccessLevel.Admin: - authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole); + authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin); break; case SecurityAccessLevel.Host: - authorized = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole); + authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); break; } } diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index 7de2331a..a4bcba0f 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -135,10 +135,10 @@ authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions); break; case SecurityAccessLevel.Admin: - authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole); + authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin); break; case SecurityAccessLevel.Host: - authorized = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole); + authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); break; } } diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 7872aba0..291b2acb 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -173,7 +173,7 @@ _haseditpermission = false; if (!string.IsNullOrEmpty(Folder)) { - _haseditpermission = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole); + _haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); _files = await FileService.GetFilesAsync(Folder); } else diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index 171a8926..680f45c0 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -6,7 +6,7 @@ {
- @if (UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole)) + @if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) {
@@ -51,7 +51,7 @@

- @if (UserSecurity.GetPermissionStrings(PageState.Page.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(Constants.AllUsersRole)) + @if (UserSecurity.GetPermissionStrings(PageState.Page.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(RoleNames.Everyone)) {
@@ -510,8 +510,8 @@ 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); + if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone); + if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered); permissionstring.Permissions = string.Join(";", ids.ToArray()); } } @@ -531,12 +531,12 @@ switch (action) { case "publish": - if (!ids.Contains(Constants.AllUsersRole)) ids.Add(Constants.AllUsersRole); - if (!ids.Contains(Constants.RegisteredRole)) ids.Add(Constants.RegisteredRole); + if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone); + if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered); break; case "unpublish": - ids.Remove(Constants.AllUsersRole); - ids.Remove(Constants.RegisteredRole); + ids.Remove(RoleNames.Everyone); + ids.Remove(RoleNames.Registered); break; } permissionstring.Permissions = string.Join(";", ids.ToArray()); diff --git a/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs b/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs index a6a3f2ba..b0e95901 100644 --- a/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs +++ b/Oqtane.Client/Themes/Controls/ModuleActionsBase.cs @@ -33,7 +33,7 @@ namespace Oqtane.Themes.Controls { actionList.Add(new ActionViewModel {Icon = Icons.Cog, 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)) + if (UserSecurity.GetPermissionStrings(ModuleState.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(RoleNames.Everyone)) { actionList.Add(new ActionViewModel {Icon=Icons.CircleX, Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) }); } @@ -141,8 +141,8 @@ namespace Oqtane.Themes.Controls 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); + if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone); + if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered); permissionstring.Permissions = string.Join(";", ids.ToArray()); } } @@ -159,8 +159,8 @@ namespace Oqtane.Themes.Controls if (permissionstring.PermissionName == PermissionNames.View) { List ids = permissionstring.Permissions.Split(';').ToList(); - ids.Remove(Constants.AllUsersRole); - ids.Remove(Constants.RegisteredRole); + ids.Remove(RoleNames.Everyone); + ids.Remove(RoleNames.Registered); permissionstring.Permissions = string.Join(";", ids.ToArray()); } } diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 0c2c0f69..5ddd4d70 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -81,10 +81,10 @@ else authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.Permissions); break; case SecurityAccessLevel.Admin: - authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole); + authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin); break; case SecurityAccessLevel.Host: - authorized = UserSecurity.IsAuthorized(PageState.User, Constants.HostRole); + authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); break; } } diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index c4422587..7b202b46 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -32,7 +32,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get() { return _aliases.GetAliases(); @@ -40,7 +40,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Alias Get(int id) { return _aliases.GetAlias(id); @@ -86,7 +86,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Alias Post([FromBody] Alias alias) { if (ModelState.IsValid) @@ -99,7 +99,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Alias Put(int id, [FromBody] Alias alias) { if (ModelState.IsValid) @@ -112,7 +112,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public void Delete(int id) { _aliases.DeleteAlias(id); diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 19281dff..73fad56e 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -58,7 +58,7 @@ namespace Oqtane.Controllers } else { - if (User.IsInRole(Constants.HostRole)) + if (User.IsInRole(RoleNames.Host)) { folder = GetFolderPath(folder); if (Directory.Exists(folder)) @@ -132,7 +132,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Models.File Put(int id, [FromBody] Models.File file) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.FolderId, PermissionNames.Edit)) @@ -164,7 +164,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { Models.File file = _files.GetFile(id); @@ -282,7 +282,7 @@ namespace Oqtane.Controllers } else { - if (User.IsInRole(Constants.HostRole)) + if (User.IsInRole(RoleNames.Host)) { folderPath = GetFolderPath(folder); } diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index 52a0c9fb..b4ad16c4 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -93,7 +93,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Folder Post([FromBody] Folder folder) { if (ModelState.IsValid) @@ -106,7 +106,7 @@ namespace Oqtane.Controllers else { permissions = new List { - new Permission(PermissionNames.Edit, Constants.AdminRole, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true), }.EncodePermissions(); } if (_userPermissions.IsAuthorized(User, PermissionNames.Edit, permissions)) @@ -141,7 +141,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Folder Put(int id, [FromBody] Folder folder) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit)) @@ -182,7 +182,7 @@ namespace Oqtane.Controllers // PUT api//?siteid=x&folderid=y&parentid=z [HttpPut] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Put(int siteid, int folderid, int? parentid) { if (_userPermissions.IsAuthorized(User, EntityNames.Folder, folderid, PermissionNames.Edit)) @@ -209,7 +209,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { if (_userPermissions.IsAuthorized(User, EntityNames.Folder, id, PermissionNames.Edit)) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 29583e8a..91a9fd4e 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -36,7 +36,7 @@ namespace Oqtane.Controllers { var installation = new Installation {Success = false, Message = ""}; - if (ModelState.IsValid && (User.IsInRole(Constants.HostRole) || string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))) + if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))) { installation = _databaseManager.Install(config); } @@ -57,7 +57,7 @@ namespace Oqtane.Controllers } [HttpGet("upgrade")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Installation Upgrade() { var installation = new Installation {Success = true, Message = ""}; diff --git a/Oqtane.Server/Controllers/JobController.cs b/Oqtane.Server/Controllers/JobController.cs index 8e1993aa..d578c357 100644 --- a/Oqtane.Server/Controllers/JobController.cs +++ b/Oqtane.Server/Controllers/JobController.cs @@ -28,7 +28,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public IEnumerable Get() { return _jobs.GetJobs(); @@ -36,7 +36,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Job Get(int id) { return _jobs.GetJob(id); @@ -44,7 +44,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Job Post([FromBody] Job job) { if (ModelState.IsValid) @@ -57,7 +57,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Job Put(int id, [FromBody] Job job) { if (ModelState.IsValid) @@ -70,7 +70,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { _jobs.DeleteJob(id); @@ -79,7 +79,7 @@ namespace Oqtane.Controllers // GET api//start [HttpGet("start/{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Start(int id) { Job job = _jobs.GetJob(id); @@ -93,7 +93,7 @@ namespace Oqtane.Controllers // GET api//stop [HttpGet("stop/{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Stop(int id) { Job job = _jobs.GetJob(id); diff --git a/Oqtane.Server/Controllers/JobLogController.cs b/Oqtane.Server/Controllers/JobLogController.cs index 0c3f8bc5..35637cb4 100644 --- a/Oqtane.Server/Controllers/JobLogController.cs +++ b/Oqtane.Server/Controllers/JobLogController.cs @@ -23,7 +23,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public IEnumerable Get() { return _jobLogs.GetJobLogs(); @@ -31,7 +31,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public JobLog Get(int id) { return _jobLogs.GetJobLog(id); @@ -39,7 +39,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public JobLog Post([FromBody] JobLog jobLog) { if (ModelState.IsValid) @@ -52,7 +52,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public JobLog Put(int id, [FromBody] JobLog jobLog) { if (ModelState.IsValid) @@ -65,7 +65,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { _jobLogs.DeleteJobLog(id); diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs index 8cccfd12..0afb9ad2 100644 --- a/Oqtane.Server/Controllers/LogController.cs +++ b/Oqtane.Server/Controllers/LogController.cs @@ -23,7 +23,7 @@ namespace Oqtane.Controllers // GET: api/?siteid=x&level=y&function=z&rows=50 [HttpGet] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get(string siteid, string level, string function, string rows) { return _logs.GetLogs(int.Parse(siteid), level, function, int.Parse(rows)); @@ -31,7 +31,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Log Get(int id) { return _logs.GetLog(id); diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index b90db0b8..907b4892 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -89,7 +89,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Module Post([FromBody] Module module) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit)) @@ -108,7 +108,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Module Put(int id, [FromBody] Module module) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit)) @@ -140,7 +140,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { if (_userPermissions.IsAuthorized(User, EntityNames.Module, id, PermissionNames.Edit)) @@ -157,7 +157,7 @@ namespace Oqtane.Controllers // GET api//export?moduleid=x [HttpGet("export")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public string Export(int moduleid) { string content = ""; @@ -175,7 +175,7 @@ namespace Oqtane.Controllers // POST api//import?moduleid=x [HttpPost("import")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public bool Import(int moduleid, [FromBody] string content) { bool success = false; diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 9c6377d0..59265773 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -81,7 +81,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public void Put(int id, [FromBody] ModuleDefinition moduleDefinition) { if (ModelState.IsValid) @@ -92,7 +92,7 @@ namespace Oqtane.Controllers } [HttpGet("install")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void InstallModules() { _logger.Log(LogLevel.Information, this, LogFunction.Create, "Modules Installed"); @@ -101,7 +101,7 @@ namespace Oqtane.Controllers // DELETE api//5?siteid=x [HttpDelete("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Delete(int id, int siteid) { ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid); @@ -168,7 +168,7 @@ namespace Oqtane.Controllers // POST api/?moduleid=x [HttpPost] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Post([FromBody] ModuleDefinition moduleDefinition, string moduleid) { if (ModelState.IsValid) diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index 5310f5c7..ec020e79 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -26,7 +26,7 @@ namespace Oqtane.Controllers // GET: api/?siteid=x&type=y&userid=z [HttpGet] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public IEnumerable Get(string siteid, string direction, string userid) { IEnumerable notifications = null; @@ -46,7 +46,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Notification Get(int id) { Notification notification = _notifications.GetNotification(id); @@ -59,7 +59,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Notification Post([FromBody] Notification notification) { if (IsAuthorized(notification.FromUserId)) @@ -72,7 +72,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Notification Put(int id, [FromBody] Notification notification) { if (IsAuthorized(notification.FromUserId)) @@ -85,7 +85,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { Notification notification = _notifications.GetNotification(id); diff --git a/Oqtane.Server/Controllers/PackageController.cs b/Oqtane.Server/Controllers/PackageController.cs index 51194245..95b22c33 100644 --- a/Oqtane.Server/Controllers/PackageController.cs +++ b/Oqtane.Server/Controllers/PackageController.cs @@ -27,7 +27,7 @@ namespace Oqtane.Controllers // GET: api/?tag=x [HttpGet] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public async Task> Get(string tag) { List packages = new List(); @@ -56,7 +56,7 @@ namespace Oqtane.Controllers } [HttpPost] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public async Task Post(string packageid, string version, string folder) { using (var httpClient = new HttpClient()) diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 01645921..5a6cff8b 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -102,7 +102,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Page Post([FromBody] Page page) { if (ModelState.IsValid) @@ -115,7 +115,7 @@ namespace Oqtane.Controllers else { permissions = new List { - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(); } @@ -147,7 +147,7 @@ namespace Oqtane.Controllers // POST api//5?userid=x [HttpPost("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Page Post(int id, string userid) { Page page = null; @@ -213,7 +213,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Page Put(int id, [FromBody] Page page) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) @@ -233,7 +233,7 @@ namespace Oqtane.Controllers // PUT api//?siteid=x&pageid=y&parentid=z [HttpPut] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Put(int siteid, int pageid, int? parentid) { if (_userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit)) @@ -261,7 +261,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { Page page = _pages.GetPage(id); diff --git a/Oqtane.Server/Controllers/PageModuleController.cs b/Oqtane.Server/Controllers/PageModuleController.cs index f2c0d489..093816d8 100644 --- a/Oqtane.Server/Controllers/PageModuleController.cs +++ b/Oqtane.Server/Controllers/PageModuleController.cs @@ -65,7 +65,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public PageModule Post([FromBody] PageModule pageModule) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit)) @@ -85,7 +85,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public PageModule Put(int id, [FromBody] PageModule pageModule) { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, pageModule.ModuleId, PermissionNames.Edit)) @@ -105,7 +105,7 @@ namespace Oqtane.Controllers // PUT api//?pageid=x&pane=y [HttpPut] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Put(int pageid, string pane) { if (_userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit)) @@ -133,7 +133,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { PageModule pagemodule = _pageModules.GetPageModule(id); diff --git a/Oqtane.Server/Controllers/ProfileController.cs b/Oqtane.Server/Controllers/ProfileController.cs index aa1158ac..91c0bd05 100644 --- a/Oqtane.Server/Controllers/ProfileController.cs +++ b/Oqtane.Server/Controllers/ProfileController.cs @@ -37,7 +37,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Profile Post([FromBody] Profile profile) { if (ModelState.IsValid) @@ -50,7 +50,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Profile Put(int id, [FromBody] Profile profile) { if (ModelState.IsValid) @@ -63,7 +63,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public void Delete(int id) { _profiles.DeleteProfile(id); diff --git a/Oqtane.Server/Controllers/RoleController.cs b/Oqtane.Server/Controllers/RoleController.cs index 418382c5..a0ce556e 100644 --- a/Oqtane.Server/Controllers/RoleController.cs +++ b/Oqtane.Server/Controllers/RoleController.cs @@ -23,7 +23,7 @@ namespace Oqtane.Controllers // GET: api/?siteid=x [HttpGet] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public IEnumerable Get(string siteid) { return _roles.GetRoles(int.Parse(siteid)); @@ -31,7 +31,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public Role Get(int id) { return _roles.GetRole(id); @@ -39,7 +39,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Role Post([FromBody] Role role) { if (ModelState.IsValid) @@ -52,7 +52,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Role Put(int id, [FromBody] Role role) { if (ModelState.IsValid) @@ -65,7 +65,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public void Delete(int id) { _roles.DeleteRole(id); diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index e9be3798..2ffaea12 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -124,10 +124,10 @@ namespace Oqtane.Controllers switch (entityName) { case EntityNames.Tenant: - authorized = User.IsInRole(Constants.HostRole); + authorized = User.IsInRole(RoleNames.Host); break; case EntityNames.Site: - authorized = User.IsInRole(Constants.AdminRole); + authorized = User.IsInRole(RoleNames.Admin); break; case EntityNames.Page: case EntityNames.Module: @@ -138,7 +138,7 @@ namespace Oqtane.Controllers authorized = true; if (permissionName == PermissionNames.Edit) { - authorized = User.IsInRole(Constants.AdminRole) || (_userPermissions.GetUser(User).UserId == entityId); + authorized = User.IsInRole(RoleNames.Admin) || (_userPermissions.GetUser(User).UserId == entityId); } break; } diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index c358ea3c..d4a50e27 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -28,7 +28,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public IEnumerable Get() { return _sites.GetSites(); @@ -57,7 +57,7 @@ namespace Oqtane.Controllers } else { - authorized = User.IsInRole(Constants.HostRole); + authorized = User.IsInRole(RoleNames.Host); } if (authorized) { @@ -70,7 +70,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Site Put(int id, [FromBody] Site site) { if (ModelState.IsValid) @@ -84,7 +84,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { _sites.DeleteSite(id); diff --git a/Oqtane.Server/Controllers/SiteTemplateController.cs b/Oqtane.Server/Controllers/SiteTemplateController.cs index c63170c1..ca98eadd 100644 --- a/Oqtane.Server/Controllers/SiteTemplateController.cs +++ b/Oqtane.Server/Controllers/SiteTemplateController.cs @@ -19,7 +19,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public IEnumerable Get() { return _siteTemplates.GetSiteTemplates(); diff --git a/Oqtane.Server/Controllers/SqlController.cs b/Oqtane.Server/Controllers/SqlController.cs index 5bce5a92..189002e8 100644 --- a/Oqtane.Server/Controllers/SqlController.cs +++ b/Oqtane.Server/Controllers/SqlController.cs @@ -30,7 +30,7 @@ namespace Oqtane.Controllers // POST: api/ [HttpPost] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public SqlQuery Post([FromBody] SqlQuery sqlquery) { var results = new List>(); diff --git a/Oqtane.Server/Controllers/SystemController.cs b/Oqtane.Server/Controllers/SystemController.cs index 2f5d7339..f45927a1 100644 --- a/Oqtane.Server/Controllers/SystemController.cs +++ b/Oqtane.Server/Controllers/SystemController.cs @@ -19,7 +19,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Dictionary Get() { Dictionary systeminfo = new Dictionary(); diff --git a/Oqtane.Server/Controllers/TenantController.cs b/Oqtane.Server/Controllers/TenantController.cs index 0f76fc78..cf251468 100644 --- a/Oqtane.Server/Controllers/TenantController.cs +++ b/Oqtane.Server/Controllers/TenantController.cs @@ -23,7 +23,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get() { return _tenants.GetTenants(); @@ -31,7 +31,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public Tenant Get(int id) { return _tenants.GetTenant(id); @@ -39,7 +39,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Tenant Post([FromBody] Tenant tenant) { if (ModelState.IsValid) @@ -52,7 +52,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public Tenant Put(int id, [FromBody] Tenant tenant) { if (ModelState.IsValid) @@ -65,7 +65,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { _tenants.DeleteTenant(id); diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index 3acb66aa..f99fb446 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -34,14 +34,14 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] - [Authorize(Roles = Constants.RegisteredRole)] + [Authorize(Roles = RoleNames.Registered)] public IEnumerable Get() { return _themes.GetThemes(); } [HttpGet("install")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void InstallThemes() { _logger.Log(LogLevel.Information, this, LogFunction.Create, "Themes Installed"); @@ -50,7 +50,7 @@ namespace Oqtane.Controllers // DELETE api//xxx [HttpDelete("{themename}")] - [Authorize(Roles = Constants.HostRole)] + [Authorize(Roles = RoleNames.Host)] public void Delete(string themename) { List themes = _themes.GetThemes().ToList(); diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index fff15612..e03f1022 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -77,7 +77,7 @@ namespace Oqtane.Controllers private User Filter(User user) { - if (user != null && !User.IsInRole(Constants.AdminRole) && User.Identity.Name?.ToLower() != user.Username.ToLower()) + if (user != null && !User.IsInRole(RoleNames.Admin) && User.Identity.Name?.ToLower() != user.Username.ToLower()) { user.DisplayName = ""; user.Email = ""; @@ -118,7 +118,7 @@ namespace Oqtane.Controllers bool verified; bool allowregistration; - if (user.Username == Constants.HostUser || User.IsInRole(Constants.AdminRole)) + if (user.Username == Constants.HostUser || User.IsInRole(RoleNames.Admin)) { verified = true; allowregistration = true; @@ -166,7 +166,7 @@ namespace Oqtane.Controllers // assign to host role if this is the host user ( initial installation ) if (user.Username == Constants.HostUser) { - int hostroleid = _roles.GetRoles(user.SiteId, true).Where(item => item.Name == Constants.HostRole).FirstOrDefault().RoleId; + int hostroleid = _roles.GetRoles(user.SiteId, true).Where(item => item.Name == RoleNames.Host).FirstOrDefault().RoleId; UserRole userrole = new UserRole(); userrole.UserId = newUser.UserId; userrole.RoleId = hostroleid; @@ -190,7 +190,7 @@ namespace Oqtane.Controllers Permissions = new List { new Permission(PermissionNames.Browse, newUser.UserId, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), new Permission(PermissionNames.Edit, newUser.UserId, true) }.EncodePermissions() }); @@ -242,7 +242,7 @@ namespace Oqtane.Controllers { if (ModelState.IsValid) { - if (User.IsInRole(Constants.AdminRole) || User.Identity.Name == user.Username) + if (User.IsInRole(RoleNames.Admin) || User.Identity.Name == user.Username) { if (user.Password != "") { @@ -270,7 +270,7 @@ namespace Oqtane.Controllers // DELETE api//5?siteid=x [HttpDelete("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public async Task Delete(int id) { IdentityUser identityuser = await _identityUserManager.FindByNameAsync(_users.GetUser(id).Username); @@ -460,9 +460,9 @@ namespace Oqtane.Controllers foreach (UserRole userrole in userroles) { roles += userrole.Role.Name + ";"; - if (userrole.Role.Name == Constants.HostRole && userroles.Where(item => item.Role.Name == Constants.AdminRole).FirstOrDefault() == null) + if (userrole.Role.Name == RoleNames.Host && userroles.Where(item => item.Role.Name == RoleNames.Admin).FirstOrDefault() == null) { - roles += Constants.AdminRole + ";"; + roles += RoleNames.Admin + ";"; } } if (roles != "") roles = ";" + roles; diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index 50b6d957..6eeb3de1 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -27,7 +27,7 @@ namespace Oqtane.Controllers // GET: api/?siteid=x [HttpGet] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get(string siteid) { return _userRoles.GetUserRoles(int.Parse(siteid)); @@ -35,7 +35,7 @@ namespace Oqtane.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public UserRole Get(int id) { return _userRoles.GetUserRole(id); @@ -43,7 +43,7 @@ namespace Oqtane.Controllers // POST api/ [HttpPost] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public UserRole Post([FromBody] UserRole userRole) { if (ModelState.IsValid) @@ -57,7 +57,7 @@ namespace Oqtane.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public UserRole Put(int id, [FromBody] UserRole userRole) { if (ModelState.IsValid) @@ -71,7 +71,7 @@ namespace Oqtane.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Roles = Constants.AdminRole)] + [Authorize(Roles = RoleNames.Admin)] public void Delete(int id) { UserRole userRole = _userRoles.GetUserRole(id); diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 6aa2369a..79c72c58 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -458,7 +458,7 @@ namespace Oqtane.Infrastructure }; user = users.AddUser(user); - var hostRoleId = roles.GetRoles(user.SiteId, true).FirstOrDefault(item => item.Name == Constants.HostRole)?.RoleId ?? 0; + var hostRoleId = roles.GetRoles(user.SiteId, true).FirstOrDefault(item => item.Name == RoleNames.Host)?.RoleId ?? 0; var userRole = new UserRole { UserId = user.UserId, RoleId = hostRoleId, EffectiveDate = null, ExpiryDate = null }; userroles.AddUserRole(userRole); @@ -477,7 +477,7 @@ namespace Oqtane.Infrastructure Permissions = new List { new Permission(PermissionNames.Browse, user.UserId, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), new Permission(PermissionNames.Edit, user.UserId, true), }.EncodePermissions(), }); diff --git a/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs b/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs index 8b71c33b..449b7df9 100644 --- a/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs +++ b/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs @@ -43,16 +43,16 @@ namespace Oqtane.SiteTemplates IsNavigation = true, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions() , PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Welcome To Oqtane...", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "

Oqtane is an open source modular application framework that provides advanced functionality for developing web and mobile applications on ASP.NET Core. It leverages the revolutionary new Blazor component model to compose a fully dynamic web development experience which can be hosted either client-side or server-side. Whether you are looking for a platform to accelerate your web development efforts, or simply interested in exploring the anatomy of a large-scale Blazor application, Oqtane provides a solid foundation based on proven enterprise architectural principles.

" + "

Join Our Community  Clone Our Repo

" + @@ -61,9 +61,9 @@ namespace Oqtane.SiteTemplates }, new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "MIT License", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "

Copyright (c) 2019-2020 .NET Foundation

" + "

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

" + @@ -72,9 +72,9 @@ namespace Oqtane.SiteTemplates }, new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.RegisteredRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "

Oqtane allows you to control access to your content using security roles. This module is only visible to Registered Users of the site.

" } @@ -89,16 +89,16 @@ namespace Oqtane.SiteTemplates IsNavigation = true, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.RegisteredRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.RegisteredRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "

Oqtane allows you to control access to your content using security roles. This page is only visible to Registered Users of the site.

" } @@ -113,16 +113,16 @@ namespace Oqtane.SiteTemplates IsNavigation = true, IsPersonalizable = true, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "My Page", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "

Oqtane offers native support for user personalized pages. If a page is identified as personalizable by the site administrator in the page settings, when an authenticated user visits the page they will see an edit button at the top right corner of the page next to their username. When they click this button the sytem will create a new version of the page and allow them to edit the page content.

" } diff --git a/Oqtane.Server/Infrastructure/SiteTemplates/EmptySiteTemplate.cs b/Oqtane.Server/Infrastructure/SiteTemplates/EmptySiteTemplate.cs index 33ccaf32..408fa3fe 100644 --- a/Oqtane.Server/Infrastructure/SiteTemplates/EmptySiteTemplate.cs +++ b/Oqtane.Server/Infrastructure/SiteTemplates/EmptySiteTemplate.cs @@ -31,9 +31,9 @@ namespace Oqtane.SiteTemplates IsNavigation = true, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List() }); diff --git a/Oqtane.Server/Infrastructure/UpgradeManager.cs b/Oqtane.Server/Infrastructure/UpgradeManager.cs index 2c538d97..0344de6e 100644 --- a/Oqtane.Server/Infrastructure/UpgradeManager.cs +++ b/Oqtane.Server/Infrastructure/UpgradeManager.cs @@ -40,9 +40,9 @@ namespace Oqtane.Infrastructure // EditMode = false, // PagePermissions = new List // { - // new Permission(PermissionNames.View, Constants.AdminRole, true), - // new Permission(PermissionNames.View, Constants.AllUsersRole, true), - // new Permission(PermissionNames.Edit, Constants.AdminRole, true) + // new Permission(PermissionNames.View, RoleNames.Admin, true), + // new Permission(PermissionNames.View, RoleNames.Everyone, true), + // new Permission(PermissionNames.Edit, RoleNames.Admin, true) // }.EncodePermissions(), // PageTemplateModules = new List // { @@ -51,9 +51,9 @@ namespace Oqtane.Infrastructure // ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "Test", Pane = "Content", // ModulePermissions = new List // { - // new Permission(PermissionNames.View, Constants.AdminRole, true), - // new Permission(PermissionNames.View, Constants.AllUsersRole, true), - // new Permission(PermissionNames.Edit, Constants.AdminRole, true) + // new Permission(PermissionNames.View, RoleNames.Admin, true), + // new Permission(PermissionNames.View, RoleNames.Everyone, true), + // new Permission(PermissionNames.Edit, RoleNames.Admin, true) // }.EncodePermissions(), // Content = "" // } diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs index b2bfc71d..b0d21ff2 100644 --- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs +++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs @@ -239,15 +239,15 @@ namespace Oqtane.Repository { moduledefinition.Permissions = new List { - new Permission(PermissionNames.Utilize, Constants.AdminRole, true) + new Permission(PermissionNames.Utilize, RoleNames.Admin, true) }.EncodePermissions(); } else { moduledefinition.Permissions = new List { - new Permission(PermissionNames.Utilize, Constants.AdminRole, true), - new Permission(PermissionNames.Utilize, Constants.RegisteredRole, true) + new Permission(PermissionNames.Utilize, RoleNames.Admin, true), + new Permission(PermissionNames.Utilize, RoleNames.Registered, true) }.EncodePermissions(); } diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 530360da..0130e5e3 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -60,9 +60,9 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -71,9 +71,9 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -89,9 +89,9 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -100,9 +100,9 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -119,9 +119,9 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -130,9 +130,9 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -148,9 +148,9 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.RegisteredRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -159,9 +159,9 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.RegisteredRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -174,8 +174,8 @@ namespace Oqtane.Repository Name = "Admin", Parent = "", Path = "admin", Icon = "", IsNavigation = false, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -184,8 +184,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -201,8 +201,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -211,8 +211,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -228,8 +228,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -238,8 +238,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -255,8 +255,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -265,8 +265,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -282,8 +282,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -292,8 +292,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -309,8 +309,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -319,8 +319,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -336,8 +336,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -346,8 +346,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -363,8 +363,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -373,8 +373,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), Content = "" } @@ -392,8 +392,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -402,8 +402,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -418,8 +418,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -428,8 +428,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Tenants.Index).ToModuleDefinitionName(), Title = "Tenant Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -440,8 +440,8 @@ namespace Oqtane.Repository Name = "Site Management", Parent = "Admin", Path = "admin/sites", Icon = Icons.Globe, IsNavigation = false, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -450,8 +450,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -462,8 +462,8 @@ namespace Oqtane.Repository Name = "Module Management", Parent = "Admin", Path = "admin/modules", Icon = Icons.Browser, IsNavigation = false, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -472,8 +472,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -484,8 +484,8 @@ namespace Oqtane.Repository Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Icon = Icons.Brush, IsNavigation = false, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -494,8 +494,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -506,8 +506,8 @@ namespace Oqtane.Repository Name = "Scheduled Jobs", Parent = "Admin", Path = "admin/jobs", Icon = Icons.Timer, IsNavigation = false, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -516,8 +516,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -533,8 +533,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -543,8 +543,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -560,8 +560,8 @@ namespace Oqtane.Repository IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -570,8 +570,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -582,8 +582,8 @@ namespace Oqtane.Repository Name = "System Update", Parent = "Admin", Path = "admin/update", Icon = Icons.Aperture, IsNavigation = false, IsPersonalizable = false, PagePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), PageTemplateModules = new List { @@ -592,8 +592,8 @@ namespace Oqtane.Repository ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = "Content", ModulePermissions = new List { - new Permission(PermissionNames.View, Constants.HostRole, true), - new Permission(PermissionNames.Edit, Constants.HostRole, true) + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) }.EncodePermissions(), Content = "" } @@ -640,18 +640,18 @@ namespace Oqtane.Repository { // create default entities for site List roles = _roleRepository.GetRoles(site.SiteId, true).ToList(); - if (!roles.Where(item => item.Name == Constants.AllUsersRole).Any()) + if (!roles.Where(item => item.Name == RoleNames.Everyone).Any()) { - _roleRepository.AddRole(new Role {SiteId = null, Name = Constants.AllUsersRole, Description = "All Users", IsAutoAssigned = false, IsSystem = true}); + _roleRepository.AddRole(new Role {SiteId = null, Name = RoleNames.Everyone, Description = "All Users", IsAutoAssigned = false, IsSystem = true}); } - if (!roles.Where(item => item.Name == Constants.HostRole).Any()) + if (!roles.Where(item => item.Name == RoleNames.Host).Any()) { - _roleRepository.AddRole(new Role {SiteId = null, Name = Constants.HostRole, Description = "Application Administrators", IsAutoAssigned = false, IsSystem = true}); + _roleRepository.AddRole(new Role {SiteId = null, Name = RoleNames.Host, Description = "Application Administrators", IsAutoAssigned = false, IsSystem = true}); } - _roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = Constants.RegisteredRole, Description = "Registered Users", IsAutoAssigned = true, IsSystem = true}); - _roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = Constants.AdminRole, Description = "Site Administrators", IsAutoAssigned = false, IsSystem = true}); + _roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Registered, Description = "Registered Users", IsAutoAssigned = true, IsSystem = true}); + _roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Admin, Description = "Site Administrators", IsAutoAssigned = false, IsSystem = true}); _profileRepository.AddProfile(new Profile {SiteId = site.SiteId, Name = "FirstName", Title = "First Name", Description = "Your First Or Given Name", Category = "Name", ViewOrder = 1, MaxLength = 50, DefaultValue = "", IsRequired = true, IsPrivate = false}); @@ -675,9 +675,9 @@ namespace Oqtane.Repository SiteId = site.SiteId, ParentId = null, Name = "Root", Path = "", Order = 1, IsSystem = true, Permissions = new List { - new Permission(PermissionNames.Browse, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AllUsersRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.Browse, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions() }); _folderRepository.AddFolder(new Folder @@ -685,9 +685,9 @@ namespace Oqtane.Repository SiteId = site.SiteId, ParentId = folder.FolderId, Name = "Users", Path = Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()), Order = 1, IsSystem = true, Permissions = new List { - new Permission(PermissionNames.Browse, Constants.AdminRole, true), - new Permission(PermissionNames.View, Constants.AdminRole, true), - new Permission(PermissionNames.Edit, Constants.AdminRole, true) + new Permission(PermissionNames.Browse, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions() }); diff --git a/Oqtane.Server/Security/ClaimsPrincipalFactory.cs b/Oqtane.Server/Security/ClaimsPrincipalFactory.cs index 1e945938..6ac81731 100644 --- a/Oqtane.Server/Security/ClaimsPrincipalFactory.cs +++ b/Oqtane.Server/Security/ClaimsPrincipalFactory.cs @@ -39,15 +39,15 @@ namespace Oqtane.Security { id.AddClaim(new Claim(_options.ClaimsIdentity.RoleClaimType, userrole.Role.Name)); // host users are members of every site - if (userrole.Role.Name == Constants.HostRole) + if (userrole.Role.Name == RoleNames.Host) { - if (userroles.Where(item => item.Role.Name == Constants.RegisteredRole).FirstOrDefault() == null) + if (userroles.Where(item => item.Role.Name == RoleNames.Registered).FirstOrDefault() == null) { - id.AddClaim(new Claim(_options.ClaimsIdentity.RoleClaimType, Constants.RegisteredRole)); + id.AddClaim(new Claim(_options.ClaimsIdentity.RoleClaimType, RoleNames.Registered)); } - if (userroles.Where(item => item.Role.Name == Constants.AdminRole).FirstOrDefault() == null) + if (userroles.Where(item => item.Role.Name == RoleNames.Admin).FirstOrDefault() == null) { - id.AddClaim(new Claim(_options.ClaimsIdentity.RoleClaimType, Constants.AdminRole)); + id.AddClaim(new Claim(_options.ClaimsIdentity.RoleClaimType, RoleNames.Admin)); } } } diff --git a/Oqtane.Shared/Security/UserSecurity.cs b/Oqtane.Shared/Security/UserSecurity.cs index a8e85304..ec2d0db0 100644 --- a/Oqtane.Shared/Security/UserSecurity.cs +++ b/Oqtane.Shared/Security/UserSecurity.cs @@ -85,14 +85,14 @@ namespace Oqtane.Security if (permission.StartsWith("!")) { string denyRole = permission.Replace("!", ""); - if (denyRole == Constants.AllUsersRole || IsAllowed(userId, roles, denyRole)) + if (denyRole == RoleNames.Everyone || IsAllowed(userId, roles, denyRole)) { allowed = false; } } else // grant permission { - if (permission == Constants.AllUsersRole || IsAllowed(userId, roles, permission)) + if (permission == RoleNames.Everyone || IsAllowed(userId, roles, permission)) { allowed = true; } diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index db62f416..ec6d7df7 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -1,10 +1,9 @@ using System; using System.Globalization; -namespace Oqtane.Shared -{ - public class Constants - { +namespace Oqtane.Shared { + + public class Constants { public const string PackageId = "Oqtane.Framework"; public const string Version = "1.0.4"; public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4"; @@ -41,10 +40,16 @@ namespace Oqtane.Shared public const string MasterTenant = "Master"; public const string DefaultSite = "Default Site"; - public const string AllUsersRole = "All Users"; - public const string HostRole = "Host Users"; - public const string AdminRole = "Administrators"; - public const string RegisteredRole = "Registered Users"; + const string RoleObsoleteMessage = "Use the corresponding memeber from Oqtane.Shared.RoleNames"; + + [Obsolete(RoleObsoleteMessage)] + public const string AllUsersRole = RoleNames.Everyone; + [Obsolete(RoleObsoleteMessage)] + public const string HostRole = RoleNames.Host; + [Obsolete(RoleObsoleteMessage)] + public const string AdminRole = RoleNames.Admin; + [Obsolete(RoleObsoleteMessage)] + public const string RegisteredRole = RoleNames.Registered; public const string ImageFiles = "jpg,jpeg,jpe,gif,bmp,png,svg,ico"; public const string UploadableFiles = "jpg,jpeg,jpe,gif,bmp,png,svg,ico,mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg,csv"; diff --git a/Oqtane.Shared/Shared/RoleNames.cs b/Oqtane.Shared/Shared/RoleNames.cs new file mode 100644 index 00000000..f526d613 --- /dev/null +++ b/Oqtane.Shared/Shared/RoleNames.cs @@ -0,0 +1,8 @@ +namespace Oqtane.Shared { + public class RoleNames { + public const string Everyone = "All Users"; + public const string Host = "Host Users"; + public const string Admin = "Administrators"; + public const string Registered = "Registered Users"; + } +} From becc779db8b6e2b40899df5530bc5983eb1ff123 Mon Sep 17 00:00:00 2001 From: Tony Valenti Date: Fri, 16 Oct 2020 10:07:01 -0500 Subject: [PATCH 063/114] Extracted "ViewModule" and "EditModule" into PolicyNames class. --- .../Modules/HtmlText/Controllers/HtmlTextController.cs | 8 ++++---- .../External/Server/[Owner].[Module].Server.csproj | 4 ++-- .../[Owner].[Module]/Controllers/[Module]Controller.cs | 10 +++++----- Oqtane.Shared/Shared/PolicyNames.cs | 10 ++++++++++ 4 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 Oqtane.Shared/Shared/PolicyNames.cs diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs index ba164d4f..6db9e5de 100644 --- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs +++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs @@ -24,7 +24,7 @@ namespace Oqtane.Modules.HtmlText.Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Policy = "ViewModule")] + [Authorize(Policy = PolicyNames.ViewModule)] public List Get(int id) { var list = new List(); @@ -47,7 +47,7 @@ namespace Oqtane.Modules.HtmlText.Controllers // POST api/ [HttpPost] - [Authorize(Policy = "EditModule")] + [Authorize(Policy = PolicyNames.EditModule)] public HtmlTextInfo Post([FromBody] HtmlTextInfo htmlText) { try @@ -68,7 +68,7 @@ namespace Oqtane.Modules.HtmlText.Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Policy = "EditModule")] + [Authorize(Policy = PolicyNames.EditModule)] public HtmlTextInfo Put(int id, [FromBody] HtmlTextInfo htmlText) { try @@ -89,7 +89,7 @@ namespace Oqtane.Modules.HtmlText.Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Policy = "EditModule")] + [Authorize(Policy = PolicyNames.EditModule)] public void Delete(int id) { try diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].[Module].Server.csproj b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].[Module].Server.csproj index 60db0e22..21883a65 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].[Module].Server.csproj +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].[Module].Server.csproj @@ -31,7 +31,7 @@ - [ServerReference] - [SharedReference] + + diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs index c8fe7485..5dcadfea 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs @@ -30,7 +30,7 @@ namespace [Owner].[Module].Controllers // GET: api/?moduleid=x [HttpGet] - [Authorize(Policy = "ViewModule")] + [Authorize(Policy = PolicyNames.ViewModule)] public IEnumerable Get(string moduleid) { return _[Module]Repository.Get[Module]s(int.Parse(moduleid)); @@ -38,7 +38,7 @@ namespace [Owner].[Module].Controllers // GET api//5 [HttpGet("{id}")] - [Authorize(Policy = "ViewModule")] + [Authorize(Policy = PolicyNames.ViewModule)] public Models.[Module] Get(int id) { Models.[Module] [Module] = _[Module]Repository.Get[Module](id); @@ -51,7 +51,7 @@ namespace [Owner].[Module].Controllers // POST api/ [HttpPost] - [Authorize(Policy = "EditModule")] + [Authorize(Policy = PolicyNames.EditModule)] public Models.[Module] Post([FromBody] Models.[Module] [Module]) { if (ModelState.IsValid && [Module].ModuleId == _entityId) @@ -64,7 +64,7 @@ namespace [Owner].[Module].Controllers // PUT api//5 [HttpPut("{id}")] - [Authorize(Policy = "EditModule")] + [Authorize(Policy = PolicyNames.EditModule)] public Models.[Module] Put(int id, [FromBody] Models.[Module] [Module]) { if (ModelState.IsValid && [Module].ModuleId == _entityId) @@ -77,7 +77,7 @@ namespace [Owner].[Module].Controllers // DELETE api//5 [HttpDelete("{id}")] - [Authorize(Policy = "EditModule")] + [Authorize(Policy = PolicyNames.EditModule)] public void Delete(int id) { Models.[Module] [Module] = _[Module]Repository.Get[Module](id); diff --git a/Oqtane.Shared/Shared/PolicyNames.cs b/Oqtane.Shared/Shared/PolicyNames.cs new file mode 100644 index 00000000..71e27a8d --- /dev/null +++ b/Oqtane.Shared/Shared/PolicyNames.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Oqtane.Shared { + public class PolicyNames { + public const string ViewModule = "ViewModule"; + public const string EditModule = "EditModule"; + } +} From f33fb4d001a441da3a4ea4f332f69124b46a3608 Mon Sep 17 00:00:00 2001 From: Tony Valenti Date: Fri, 16 Oct 2020 10:23:17 -0500 Subject: [PATCH 064/114] Factoring out Constants.AdminPane and Constants.HostUser --- Oqtane.Client/Modules/Admin/Sites/Add.razor | 4 ++-- Oqtane.Client/UI/Pane.razor | 4 ++-- Oqtane.Client/UI/SiteRouter.razor | 2 +- Oqtane.Server/Controllers/UserController.cs | 6 +++--- Oqtane.Server/Infrastructure/DatabaseManager.cs | 8 ++++---- Oqtane.Shared/Shared/Constants.cs | 7 +++++-- Oqtane.Shared/Shared/PaneNames.cs | 9 +++++++++ Oqtane.Shared/Shared/UserNames.cs | 9 +++++++++ 8 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 Oqtane.Shared/Shared/PaneNames.cs create mode 100644 Oqtane.Shared/Shared/UserNames.cs diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 042e168b..7ee36435 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -216,7 +216,7 @@ else private string _username = string.Empty; private string _password = string.Empty; private bool _integratedsecurity = true; - private string _hostusername = Constants.HostUser; + private string _hostusername = UserNames.Host; private string _hostpassword = string.Empty; private string _name = string.Empty; @@ -311,7 +311,7 @@ else // validate host credentials var user = new User(); user.SiteId = PageState.Site.SiteId; - user.Username = Constants.HostUser; + user.Username = UserNames.Host; user.Password = _hostpassword; user = await UserService.LoginUserAsync(user, false, false); if (user.IsAuthenticated) diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 5ddd4d70..32abb374 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -31,7 +31,7 @@ else protected override void OnParametersSet() { - if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && Name != Constants.AdminPane) + if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && Name != PaneNames.Admin) { _useadminborder = true; _paneadminborder = "app-pane-admin-border"; @@ -47,7 +47,7 @@ else { if (PageState.ModuleId != -1 && PageState.Action != Constants.DefaultAction) { - if (Name.ToLower() == Constants.AdminPane.ToLower()) + if (Name.ToLower() == PaneNames.Admin.ToLower()) { Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId); if (module != null && !module.IsDeleted) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index b79ea29d..ae34d6f8 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -505,7 +505,7 @@ // ensure module's pane exists in current page and if not, assign it to the Admin pane if (page.Panes == null || page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1) { - module.Pane = Constants.AdminPane; + module.Pane = PaneNames.Admin; } // calculate module position within pane diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index e03f1022..1a42ccd8 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -118,7 +118,7 @@ namespace Oqtane.Controllers bool verified; bool allowregistration; - if (user.Username == Constants.HostUser || User.IsInRole(RoleNames.Admin)) + if (user.Username == UserNames.Host || User.IsInRole(RoleNames.Admin)) { verified = true; allowregistration = true; @@ -164,7 +164,7 @@ namespace Oqtane.Controllers } // assign to host role if this is the host user ( initial installation ) - if (user.Username == Constants.HostUser) + if (user.Username == UserNames.Host) { int hostroleid = _roles.GetRoles(user.SiteId, true).Where(item => item.Name == RoleNames.Host).FirstOrDefault().RoleId; UserRole userrole = new UserRole(); @@ -206,7 +206,7 @@ namespace Oqtane.Controllers } } - if (newUser != null && user.Username != Constants.HostUser) + if (newUser != null && user.Username != UserNames.Host) { // add auto assigned roles to user for site List roles = _roles.GetRoles(user.SiteId).Where(item => item.IsAutoAssigned).ToList(); diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 79c72c58..28228280 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -83,7 +83,7 @@ namespace Oqtane.Infrastructure if (!string.IsNullOrEmpty(install.ConnectionString) && !string.IsNullOrEmpty(install.Aliases) && !string.IsNullOrEmpty(install.HostPassword) && !string.IsNullOrEmpty(install.HostEmail)) { // silent install - install.HostName = Constants.HostUser; + install.HostName = UserNames.Host; install.SiteTemplate = GetInstallationConfig(SettingKeys.SiteTemplateKey, Constants.DefaultSiteTemplate); install.DefaultTheme = GetInstallationConfig(SettingKeys.DefaultThemeKey, Constants.DefaultTheme); install.DefaultLayout = GetInstallationConfig(SettingKeys.DefaultLayoutKey, Constants.DefaultLayout); @@ -439,17 +439,17 @@ namespace Oqtane.Infrastructure }; site = sites.AddSite(site); - IdentityUser identityUser = identityUserManager.FindByNameAsync(Constants.HostUser).GetAwaiter().GetResult(); + IdentityUser identityUser = identityUserManager.FindByNameAsync(UserNames.Host).GetAwaiter().GetResult(); if (identityUser == null) { - identityUser = new IdentityUser { UserName = Constants.HostUser, Email = install.HostEmail, EmailConfirmed = true }; + identityUser = new IdentityUser { UserName = UserNames.Host, Email = install.HostEmail, EmailConfirmed = true }; var create = identityUserManager.CreateAsync(identityUser, install.HostPassword).GetAwaiter().GetResult(); if (create.Succeeded) { var user = new User { SiteId = site.SiteId, - Username = Constants.HostUser, + Username = UserNames.Host, Password = install.HostPassword, Email = install.HostEmail, DisplayName = install.HostName, diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index ec6d7df7..a4eeffb4 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -18,7 +18,9 @@ namespace Oqtane.Shared { public const string ActionToken = "{Action}"; public const string DefaultAction = "Index"; - public const string AdminPane = "Admin"; + + [Obsolete("Use PaneNames.Admin")] + public const string AdminPane = PaneNames.Admin; public const string ModuleDelimiter = "*"; public const string UrlParametersDelimiter = "!"; @@ -35,7 +37,8 @@ namespace Oqtane.Shared { public const string ContentUrl = "/api/file/download/"; - public const string HostUser = "host"; + [Obsolete("Use UserNames.Host instead.")] + public const string HostUser = UserNames.Host; public const string MasterTenant = "Master"; public const string DefaultSite = "Default Site"; diff --git a/Oqtane.Shared/Shared/PaneNames.cs b/Oqtane.Shared/Shared/PaneNames.cs new file mode 100644 index 00000000..063924f9 --- /dev/null +++ b/Oqtane.Shared/Shared/PaneNames.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Oqtane.Shared { + public class PaneNames { + public const string Admin = "Admin"; + } +} diff --git a/Oqtane.Shared/Shared/UserNames.cs b/Oqtane.Shared/Shared/UserNames.cs new file mode 100644 index 00000000..fdb83800 --- /dev/null +++ b/Oqtane.Shared/Shared/UserNames.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Oqtane.Shared { + public class UserNames { + public const string Host = "host"; + } +} From 766be6c929e261204a91b1bd27d123f4c720c782 Mon Sep 17 00:00:00 2001 From: Tony Valenti Date: Fri, 16 Oct 2020 10:37:17 -0500 Subject: [PATCH 065/114] Factor out default controller route. --- Oqtane.Server/Controllers/AliasController.cs | 2 +- Oqtane.Server/Controllers/FileController.cs | 2 +- Oqtane.Server/Controllers/FolderController.cs | 2 +- Oqtane.Server/Controllers/InstallationController.cs | 2 +- Oqtane.Server/Controllers/JobController.cs | 2 +- Oqtane.Server/Controllers/JobLogController.cs | 2 +- Oqtane.Server/Controllers/LogController.cs | 2 +- Oqtane.Server/Controllers/ModuleController.cs | 2 +- Oqtane.Server/Controllers/ModuleDefinitionController.cs | 2 +- Oqtane.Server/Controllers/NotificationController.cs | 2 +- Oqtane.Server/Controllers/PackageController.cs | 2 +- Oqtane.Server/Controllers/PageController.cs | 2 +- Oqtane.Server/Controllers/PageModuleController.cs | 2 +- Oqtane.Server/Controllers/ProfileController.cs | 2 +- Oqtane.Server/Controllers/RoleController.cs | 2 +- Oqtane.Server/Controllers/SettingController.cs | 2 +- Oqtane.Server/Controllers/SiteController.cs | 2 +- Oqtane.Server/Controllers/SiteTemplateController.cs | 2 +- Oqtane.Server/Controllers/SqlController.cs | 2 +- Oqtane.Server/Controllers/SystemController.cs | 2 +- Oqtane.Server/Controllers/TenantController.cs | 2 +- Oqtane.Server/Controllers/ThemeController.cs | 2 +- Oqtane.Server/Controllers/UserController.cs | 2 +- Oqtane.Server/Controllers/UserRoleController.cs | 2 +- .../Modules/HtmlText/Controllers/HtmlTextController.cs | 2 +- .../[Owner].[Module]/Controllers/[Module]Controller.cs | 2 +- Oqtane.Shared/Shared/ControllerRoutes.cs | 9 +++++++++ 27 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 Oqtane.Shared/Shared/ControllerRoutes.cs diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index 7b202b46..188160a0 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Http; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class AliasController : Controller { private readonly IAliasRepository _aliases; diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 73fad56e..fb43a7cb 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -22,7 +22,7 @@ using Microsoft.AspNetCore.Routing.Constraints; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class FileController : Controller { private readonly IWebHostEnvironment _environment; diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index b4ad16c4..aad20a77 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -15,7 +15,7 @@ using Microsoft.AspNetCore.Hosting; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class FolderController : Controller { private readonly IWebHostEnvironment _environment; diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 91a9fd4e..6ca0dff7 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -14,7 +14,7 @@ using Oqtane.Themes; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class InstallationController : Controller { private readonly IConfigurationRoot _config; diff --git a/Oqtane.Server/Controllers/JobController.cs b/Oqtane.Server/Controllers/JobController.cs index d578c357..03cf4e3b 100644 --- a/Oqtane.Server/Controllers/JobController.cs +++ b/Oqtane.Server/Controllers/JobController.cs @@ -12,7 +12,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class JobController : Controller { private readonly IJobRepository _jobs; diff --git a/Oqtane.Server/Controllers/JobLogController.cs b/Oqtane.Server/Controllers/JobLogController.cs index 35637cb4..055e90a0 100644 --- a/Oqtane.Server/Controllers/JobLogController.cs +++ b/Oqtane.Server/Controllers/JobLogController.cs @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class JobLogController : Controller { private readonly IJobLogRepository _jobLogs; diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs index 0afb9ad2..4de0abcb 100644 --- a/Oqtane.Server/Controllers/LogController.cs +++ b/Oqtane.Server/Controllers/LogController.cs @@ -9,7 +9,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class LogController : Controller { private readonly ILogManager _logger; diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index 907b4892..6abcbe1f 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -11,7 +11,7 @@ using Oqtane.Security; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class ModuleController : Controller { private readonly IModuleRepository _modules; diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 59265773..7e78fe87 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -19,7 +19,7 @@ using System.Text.Json; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class ModuleDefinitionController : Controller { private readonly IModuleDefinitionRepository _moduleDefinitions; diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index ec020e79..5c73eb78 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -10,7 +10,7 @@ using Oqtane.Security; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class NotificationController : Controller { private readonly INotificationRepository _notifications; diff --git a/Oqtane.Server/Controllers/PackageController.cs b/Oqtane.Server/Controllers/PackageController.cs index 95b22c33..10aa0696 100644 --- a/Oqtane.Server/Controllers/PackageController.cs +++ b/Oqtane.Server/Controllers/PackageController.cs @@ -15,7 +15,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class PackageController : Controller { private readonly IWebHostEnvironment _environment; diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 5a6cff8b..aab9c23d 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -13,7 +13,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class PageController : Controller { private readonly IPageRepository _pages; diff --git a/Oqtane.Server/Controllers/PageModuleController.cs b/Oqtane.Server/Controllers/PageModuleController.cs index 093816d8..0b238ecf 100644 --- a/Oqtane.Server/Controllers/PageModuleController.cs +++ b/Oqtane.Server/Controllers/PageModuleController.cs @@ -11,7 +11,7 @@ using Oqtane.Security; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class PageModuleController : Controller { private readonly IPageModuleRepository _pageModules; diff --git a/Oqtane.Server/Controllers/ProfileController.cs b/Oqtane.Server/Controllers/ProfileController.cs index 91c0bd05..19411487 100644 --- a/Oqtane.Server/Controllers/ProfileController.cs +++ b/Oqtane.Server/Controllers/ProfileController.cs @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class ProfileController : Controller { private readonly IProfileRepository _profiles; diff --git a/Oqtane.Server/Controllers/RoleController.cs b/Oqtane.Server/Controllers/RoleController.cs index a0ce556e..708e20c3 100644 --- a/Oqtane.Server/Controllers/RoleController.cs +++ b/Oqtane.Server/Controllers/RoleController.cs @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class RoleController : Controller { private readonly IRoleRepository _roles; diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index 2ffaea12..8e6563c2 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -10,7 +10,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class SettingController : Controller { private readonly ISettingRepository _settings; diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index d4a50e27..43a10dd1 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -10,7 +10,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class SiteController : Controller { private readonly ISiteRepository _sites; diff --git a/Oqtane.Server/Controllers/SiteTemplateController.cs b/Oqtane.Server/Controllers/SiteTemplateController.cs index ca98eadd..abb9e19b 100644 --- a/Oqtane.Server/Controllers/SiteTemplateController.cs +++ b/Oqtane.Server/Controllers/SiteTemplateController.cs @@ -7,7 +7,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class SiteTemplateController : Controller { private readonly ISiteTemplateRepository _siteTemplates; diff --git a/Oqtane.Server/Controllers/SqlController.cs b/Oqtane.Server/Controllers/SqlController.cs index 189002e8..7e7bedcc 100644 --- a/Oqtane.Server/Controllers/SqlController.cs +++ b/Oqtane.Server/Controllers/SqlController.cs @@ -14,7 +14,7 @@ using System; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class SqlController : Controller { private readonly ITenantRepository _tenants; diff --git a/Oqtane.Server/Controllers/SystemController.cs b/Oqtane.Server/Controllers/SystemController.cs index f45927a1..61c5593b 100644 --- a/Oqtane.Server/Controllers/SystemController.cs +++ b/Oqtane.Server/Controllers/SystemController.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Hosting; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class SystemController : Controller { private readonly IWebHostEnvironment _environment; diff --git a/Oqtane.Server/Controllers/TenantController.cs b/Oqtane.Server/Controllers/TenantController.cs index cf251468..6670d4dd 100644 --- a/Oqtane.Server/Controllers/TenantController.cs +++ b/Oqtane.Server/Controllers/TenantController.cs @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class TenantController : Controller { private readonly ITenantRepository _tenants; diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index f99fb446..0aa6916c 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -16,7 +16,7 @@ using System.Text.Json; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class ThemeController : Controller { private readonly IThemeRepository _themes; diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 1a42ccd8..5a97087a 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -18,7 +18,7 @@ using Oqtane.Extensions; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class UserController : Controller { private readonly IUserRepository _users; diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index 6eeb3de1..11c875de 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class UserRoleController : Controller { private readonly IUserRoleRepository _userRoles; diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs index 6db9e5de..74bf8564 100644 --- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs +++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs @@ -12,7 +12,7 @@ using Oqtane.Controllers; namespace Oqtane.Modules.HtmlText.Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class HtmlTextController : ModuleControllerBase { private readonly IHtmlTextRepository _htmlText; diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs index 5dcadfea..3e2fe7b8 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs @@ -10,7 +10,7 @@ using [Owner].[Module].Repository; namespace [Owner].[Module].Controllers { - [Route("{alias}/api/[controller]")] + [Route(ControllerRoutes.Default)] public class [Module]Controller : Controller { private readonly I[Module]Repository _[Module]Repository; diff --git a/Oqtane.Shared/Shared/ControllerRoutes.cs b/Oqtane.Shared/Shared/ControllerRoutes.cs new file mode 100644 index 00000000..07e170f3 --- /dev/null +++ b/Oqtane.Shared/Shared/ControllerRoutes.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Oqtane.Shared { + public class ControllerRoutes { + public const string Default = "{alias}/api/[controller]"; + } +} From 3e71bdfef3c8cb15480b91af621b65c0aaf0d983 Mon Sep 17 00:00:00 2001 From: Tony Valenti Date: Fri, 16 Oct 2020 10:38:19 -0500 Subject: [PATCH 066/114] Replace string with System.Net.Mime.MediaTypeNames.Application.Octet --- Oqtane.Server/Controllers/InstallationController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 6ca0dff7..73998b13 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -149,7 +149,7 @@ namespace Oqtane.Controllers } zipfile = memoryStream.ToArray(); } - return File(zipfile, "application/octet-stream", "oqtane.zip"); + return File(zipfile, System.Net.Mime.MediaTypeNames.Application.Octet, "oqtane.zip"); } else { From c683de2cdac71121f7fcd9ab11f2236715da2dce Mon Sep 17 00:00:00 2001 From: Tony Valenti Date: Fri, 16 Oct 2020 10:45:13 -0500 Subject: [PATCH 067/114] Refactor TenantNames.Master --- Oqtane.Client/Modules/Admin/Tenants/Edit.razor | 2 +- Oqtane.Client/Modules/Admin/Tenants/Index.razor | 2 +- Oqtane.Client/UI/Installer.razor | 6 +++--- Oqtane.Server/Infrastructure/DatabaseManager.cs | 8 ++++---- Oqtane.Server/Repository/TenantRepository.cs | 4 ++-- Oqtane.Shared/Shared/Constants.cs | 3 ++- Oqtane.Shared/Shared/TenantNames.cs | 9 +++++++++ 7 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 Oqtane.Shared/Shared/TenantNames.cs diff --git a/Oqtane.Client/Modules/Admin/Tenants/Edit.razor b/Oqtane.Client/Modules/Admin/Tenants/Edit.razor index 94ee91d6..245ce1cb 100644 --- a/Oqtane.Client/Modules/Admin/Tenants/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Tenants/Edit.razor @@ -9,7 +9,7 @@ - @if (name == Constants.MasterTenant) + @if (name == TenantNames.Master) { } diff --git a/Oqtane.Client/Modules/Admin/Tenants/Index.razor b/Oqtane.Client/Modules/Admin/Tenants/Index.razor index 1ce7c686..5858a059 100644 --- a/Oqtane.Client/Modules/Admin/Tenants/Index.razor +++ b/Oqtane.Client/Modules/Admin/Tenants/Index.razor @@ -17,7 +17,7 @@ else - + @context.Name diff --git a/Oqtane.Client/UI/Installer.razor b/Oqtane.Client/UI/Installer.razor index 8b915b5f..6ee0bba4 100644 --- a/Oqtane.Client/UI/Installer.razor +++ b/Oqtane.Client/UI/Installer.razor @@ -131,7 +131,7 @@ private string _databaseName = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm"); private string _username = string.Empty; private string _password = string.Empty; - private string _hostUsername = Constants.HostUser; + private string _hostUsername = UserNames.Host; private string _hostPassword = string.Empty; private string _confirmPassword = string.Empty; private string _hostEmail = string.Empty; @@ -188,8 +188,8 @@ Aliases = uri.Authority, HostEmail = _hostEmail, HostPassword = _hostPassword, - HostName = Constants.HostUser, - TenantName = Constants.MasterTenant, + HostName = UserNames.Host, + TenantName = TenantNames.Master, IsNewTenant = true, SiteName = Constants.DefaultSite }; diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 28228280..4f598322 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -72,7 +72,7 @@ namespace Oqtane.Infrastructure if (install == null) { // startup or silent installation - install = new InstallConfig { ConnectionString = _config.GetConnectionString(SettingKeys.ConnectionStringKey), TenantName = Constants.MasterTenant, IsNewTenant = false }; + install = new InstallConfig { ConnectionString = _config.GetConnectionString(SettingKeys.ConnectionStringKey), TenantName = TenantNames.Master, IsNewTenant = false }; if (!IsInstalled()) { @@ -192,7 +192,7 @@ namespace Oqtane.Infrastructure { var result = new Installation { Success = false, Message = string.Empty }; - if (install.TenantName == Constants.MasterTenant) + if (install.TenantName == TenantNames.Master) { MigrateScriptNamingConvention("Master", install.ConnectionString); @@ -245,7 +245,7 @@ namespace Oqtane.Infrastructure db.SaveChanges(); _cache.Remove("tenants"); - if (install.TenantName == Constants.MasterTenant) + if (install.TenantName == TenantNames.Master) { var job = new Job { Name = "Notification Job", JobType = "Oqtane.Infrastructure.NotificationJob, Oqtane.Server", Frequency = "m", Interval = 1, StartDate = null, EndDate = null, IsEnabled = false, IsStarted = false, IsExecuting = false, NextExecution = null, RetentionHistory = 10, CreatedBy = "", CreatedOn = DateTime.UtcNow, ModifiedBy = "", ModifiedOn = DateTime.UtcNow }; db.Job.Add(job); @@ -350,7 +350,7 @@ namespace Oqtane.Infrastructure foreach (var tenant in db.Tenant.ToList()) { int index = Array.FindIndex(versions, item => item == moduledefinition.Version); - if (tenant.Name == install.TenantName && install.TenantName != Constants.MasterTenant) + if (tenant.Name == install.TenantName && install.TenantName != TenantNames.Master) { index = -1; } diff --git a/Oqtane.Server/Repository/TenantRepository.cs b/Oqtane.Server/Repository/TenantRepository.cs index 6c22ba75..7df0cbe2 100644 --- a/Oqtane.Server/Repository/TenantRepository.cs +++ b/Oqtane.Server/Repository/TenantRepository.cs @@ -40,7 +40,7 @@ namespace Oqtane.Repository { var oldTenant =_db.Tenant.AsNoTracking().FirstOrDefault(t=> t.TenantId == tenant.TenantId); - if (oldTenant != null && (oldTenant.Name.Equals(Constants.MasterTenant, StringComparison.OrdinalIgnoreCase) && !oldTenant.Name.Equals(tenant.Name))) + if (oldTenant != null && (oldTenant.Name.Equals(TenantNames.Master, StringComparison.OrdinalIgnoreCase) && !oldTenant.Name.Equals(tenant.Name))) { throw new InvalidOperationException("Unable to rename the master tenant."); } @@ -59,7 +59,7 @@ namespace Oqtane.Repository public void DeleteTenant(int tenantId) { var tenant = GetTenant(tenantId); - if (tenant != null && !tenant.Name.Equals(Constants.MasterTenant, StringComparison.OrdinalIgnoreCase)) + if (tenant != null && !tenant.Name.Equals(TenantNames.Master, StringComparison.OrdinalIgnoreCase)) { _db.Tenant.Remove(tenant); _db.SaveChanges(); diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index a4eeffb4..c065f347 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -40,7 +40,8 @@ namespace Oqtane.Shared { [Obsolete("Use UserNames.Host instead.")] public const string HostUser = UserNames.Host; - public const string MasterTenant = "Master"; + [Obsolete("Use TenantNames.Master instead")] + public const string MasterTenant = TenantNames.Master; public const string DefaultSite = "Default Site"; const string RoleObsoleteMessage = "Use the corresponding memeber from Oqtane.Shared.RoleNames"; diff --git a/Oqtane.Shared/Shared/TenantNames.cs b/Oqtane.Shared/Shared/TenantNames.cs new file mode 100644 index 00000000..057235fd --- /dev/null +++ b/Oqtane.Shared/Shared/TenantNames.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Oqtane.Shared { + public class TenantNames { + public const string Master = "Master"; + } +} From 857d699c0d0c8c62b41350480af212ba20def938 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sun, 18 Oct 2020 00:55:16 +0300 Subject: [PATCH 068/114] Add .editorconfig --- .editorconfig | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..b9a82bce --- /dev/null +++ b/.editorconfig @@ -0,0 +1,53 @@ +root = true + +[*] +end_of_line = crlf +charset = utf-8 +indent_style = space +indent_size = 4 + +[*.{json,csproj,props,targets}] +indent_size = 2 + +[*.cs] +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true : suggestion +csharp_style_var_when_type_is_apparent = true : suggestion +csharp_style_var_elsewhere = true : suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true + +# Avoid "this." if not necessary +dotnet_style_qualification_for_field = false : suggestion +dotnet_style_qualification_for_property = false : suggestion +dotnet_style_qualification_for_method = false : suggestion +dotnet_style_qualification_for_event = false : suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true : suggestion +dotnet_style_predefined_type_for_member_access = false : suggestion + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true : none +csharp_style_pattern_matching_over_as_with_null_check = true : none +csharp_style_inlined_variable_declaration = true : none +csharp_style_throw_expression = true : none +csharp_style_conditional_delegate_call = true : none + +dotnet_style_object_initializer = true : suggestion +dotnet_style_collection_initializer = true : suggestion +dotnet_style_coalesce_expression = true : suggestion +dotnet_style_null_propagation = true : suggestion +dotnet_style_explicit_tuple_names = true : suggestion + +trim_trailing_whitespace = true +insert_final_newline = true \ No newline at end of file From d082c5427bb1977f10ccff6c7d7eed408716c879 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Sun, 18 Oct 2020 09:09:18 -0400 Subject: [PATCH 069/114] fixed compilation warnings in AuditInfo, fixed issue in ModuleMessage triggered in InstallWizard, fixed PWA JavaScript in ThemeBuilder for all browsers --- Oqtane.Client/Modules/Controls/AuditInfo.razor | 14 +++++++------- Oqtane.Client/Modules/Controls/ModuleMessage.razor | 4 ++-- Oqtane.Client/UI/ThemeBuilder.razor | 4 ++-- Oqtane.sln | 5 +++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/AuditInfo.razor b/Oqtane.Client/Modules/Controls/AuditInfo.razor index 3022c49f..026a2986 100644 --- a/Oqtane.Client/Modules/Controls/AuditInfo.razor +++ b/Oqtane.Client/Modules/Controls/AuditInfo.razor @@ -1,4 +1,4 @@ -@namespace Oqtane.Modules.Controls +@namespace Oqtane.Modules.Controls @inherits ModuleControlBase @if (_text != string.Empty) @@ -14,13 +14,13 @@ public string CreatedBy { get; set; } [Parameter] - public DateTime CreatedOn { get; set; } + public DateTime? CreatedOn { get; set; } [Parameter] public string ModifiedBy { get; set; } [Parameter] - public DateTime ModifiedOn { get; set; } + public DateTime? ModifiedOn { get; set; } [Parameter] public string DeletedBy { get; set; } @@ -37,7 +37,7 @@ protected override void OnParametersSet() { _text = string.Empty; - if (!String.IsNullOrEmpty(CreatedBy) || CreatedOn != null) + if (!String.IsNullOrEmpty(CreatedBy) || CreatedOn.HasValue) { _text += "

Created "; @@ -48,13 +48,13 @@ if (CreatedOn != null) { - _text += " on " + CreatedOn.ToString("MMM dd yyyy HH:mm:ss") + ""; + _text += " on " + CreatedOn.Value.ToString("MMM dd yyyy HH:mm:ss") + ""; } _text += "

"; } - if (!String.IsNullOrEmpty(ModifiedBy) || ModifiedOn != null) + if (!String.IsNullOrEmpty(ModifiedBy) || ModifiedOn.HasValue) { _text += "

Last modified "; @@ -65,7 +65,7 @@ if (ModifiedOn != null) { - _text += " on " + ModifiedOn.ToString("MMM dd yyyy HH:mm:ss") + ""; + _text += " on " + ModifiedOn.Value.ToString("MMM dd yyyy HH:mm:ss") + ""; } _text += "

"; diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index 680f45c0..ee846b13 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -1,4 +1,4 @@ -@namespace Oqtane.Modules.Controls +@namespace Oqtane.Modules.Controls @inherits ModuleControlBase @inject NavigationManager NavigationManager @@ -6,7 +6,7 @@ {