From fd573a9dd8f8e3921a5abec246478247e5f97185 Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Tue, 9 Feb 2021 21:16:14 -0500 Subject: [PATCH 01/53] Update bug-report.md --- .github/ISSUE_TEMPLATE/bug-report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 8c5a03a4880..a8866ca8026 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -41,6 +41,7 @@ Provide any additional context that may be helpful in understanding and/or resol Please add X in at least one of the boxes as appropriate. In order for an issue to be accepted, a developer needs to be able to reproduce the issue on a currently supported version. If you are looking for a workaround for an issue with an older version, please visit the forums at https://dnncommunity.org/forums --> * [ ] 10.00.00 alpha build +* [ ] 09.09.00 release candidate * [ ] 09.08.01 latest supported release ## Affected browser From b69712b575c321c9eb7bd9f739955ba399b42ef2 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 5 Feb 2021 12:50:56 -0600 Subject: [PATCH 02/53] Use Cake.AzurePipelines.Module --- Build/Build.csproj | 1 + Build/Program.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Build/Build.csproj b/Build/Build.csproj index b96ba8262a2..93338956bf0 100644 --- a/Build/Build.csproj +++ b/Build/Build.csproj @@ -7,6 +7,7 @@ $(MSBuildProjectDirectory) + diff --git a/Build/Program.cs b/Build/Program.cs index 7579ff2307d..eb6852fef06 100644 --- a/Build/Program.cs +++ b/Build/Program.cs @@ -1,5 +1,6 @@ using System; +using Cake.AzurePipelines.Module; using Cake.Frosting; public class Program @@ -10,6 +11,7 @@ public static int Main(string[] args) .UseContext() .UseLifetime() .UseWorkingDirectory("..") + .UseModule() .SetToolPath("../tools") .InstallTool(new Uri("nuget:?package=GitVersion.CommandLine&version=5.0.1")) .InstallTool(new Uri("nuget:?package=Microsoft.TestPlatform&version=16.8.0")) From ffce77eb8d75ad83c129380bbd0c4e48f47ca3a8 Mon Sep 17 00:00:00 2001 From: Michael Santoro Date: Wed, 10 Feb 2021 14:11:00 -0700 Subject: [PATCH 03/53] Fix AzureFolderProvider uploading same file with different case --- .../AzureFolderProvider/AzureFolderProvider.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs index 30a9891092b..bfd237594c3 100644 --- a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs +++ b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs @@ -270,6 +270,21 @@ protected override void MoveFolderInternal(FolderMappingInfo folderMapping, stri this.ClearCache(folderMapping.FolderMappingID); } + /* public override void UpdateFile(IFolderInfo folder, string fileName, Stream content) + { + // Azure is case sensitive. If you update dnninternals.pdf with DNNINTERNALS.pdf, to DNN it's the same + // so it just re-uploads it, causing both files to exist in Azure. + IFileInfo originalFile = FileManager.Instance.GetFile(folder, fileName); + + base.UpdateFile(folder, fileName, content); + + if (originalFile != null && originalFile.FileName != fileName) + { + FolderMappingInfo folderMapping = FolderMappingController.Instance.GetFolderMapping(folder.FolderMappingID); + this.DeleteFileInternal(folderMapping, folder.MappedPath + originalFile.FileName); + } + } + */ protected override void UpdateFileInternal(Stream stream, FolderMappingInfo folderMapping, string uri) { var container = this.GetContainer(folderMapping); From 6980f04079205aacd43afa525fc83a6e4caa5d86 Mon Sep 17 00:00:00 2001 From: Michael Santoro Date: Wed, 10 Feb 2021 14:23:44 -0700 Subject: [PATCH 04/53] Fixes #4481 AzureFolderProvider uploading same file with different case --- .../AzureFolderProvider/AzureFolderProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs index bfd237594c3..a0fe181ded4 100644 --- a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs +++ b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs @@ -270,7 +270,7 @@ protected override void MoveFolderInternal(FolderMappingInfo folderMapping, stri this.ClearCache(folderMapping.FolderMappingID); } - /* public override void UpdateFile(IFolderInfo folder, string fileName, Stream content) + public override void UpdateFile(IFolderInfo folder, string fileName, Stream content) { // Azure is case sensitive. If you update dnninternals.pdf with DNNINTERNALS.pdf, to DNN it's the same // so it just re-uploads it, causing both files to exist in Azure. @@ -283,8 +283,8 @@ protected override void MoveFolderInternal(FolderMappingInfo folderMapping, stri FolderMappingInfo folderMapping = FolderMappingController.Instance.GetFolderMapping(folder.FolderMappingID); this.DeleteFileInternal(folderMapping, folder.MappedPath + originalFile.FileName); } - } - */ + } + protected override void UpdateFileInternal(Stream stream, FolderMappingInfo folderMapping, string uri) { var container = this.GetContainer(folderMapping); From 0651ea551f5778a96b4b9ffdee86b848d7f5b5f2 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 12 Feb 2021 16:03:57 -0600 Subject: [PATCH 05/53] Remove duplicate references to Yarn.MsBuild This addresses the build warnings: D:\a\1\s\Build\BuildScripts\AEModule.build(3,3): warning MSB4011: "D:\a\1\s\packages\Yarn.MSBuild.1.16.0\build\Yarn.MSBuild.props" cannot be imported again. It was already imported at "D:\a\1\s\Dnn.AdminExperience\Dnn.PersonaBar.Extensions\Dnn.PersonaBar.Extensions.csproj (3,3)". This is most likely a build authoring error. This subsequent import will be ignored. D:\a\1\s\Dnn.AdminExperience\Dnn.PersonaBar.Extensions\Dnn.PersonaBar.Extensions.csproj(776,3): warning MSB4011: "D:\a\1\s\packages\Yarn.MSBuild.1.16.0\build\Yarn.MSBuild.targets" cannot be imported again. It was already imported at "D:\a\1\s\Build\BuildScripts\AEModule.build (4,3)". This is most likely a build authoring error. This subsequent import will be ignored. --- .../Dnn.PersonaBar.Extensions.csproj | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Dnn.PersonaBar.Extensions.csproj b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Dnn.PersonaBar.Extensions.csproj index 51945969234..de6ef826f30 100644 --- a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Dnn.PersonaBar.Extensions.csproj +++ b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Dnn.PersonaBar.Extensions.csproj @@ -1,6 +1,5 @@  - Debug @@ -766,12 +765,4 @@ - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file From e67b8a59b85259ee8a1bedeb09ea773c78c2f546 Mon Sep 17 00:00:00 2001 From: Jon Bockhorst Date: Fri, 12 Feb 2021 16:15:34 -0600 Subject: [PATCH 06/53] Fix PersonaBar loading when within an iframe --- .../Dnn.PersonaBar.UI/admin/personaBar/scripts/config.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/scripts/config.js b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/scripts/config.js index 694249735d3..ab3dc1f1bc6 100644 --- a/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/scripts/config.js +++ b/Dnn.AdminExperience/Library/Dnn.PersonaBar.UI/admin/personaBar/scripts/config.js @@ -2,11 +2,11 @@ define(['jquery'], function ($) { return { init: function () { - var inIframe = window !== window.top && typeof window.top.dnn !== "undefined"; + var inIframe = window.parent && typeof window.parent.dnn !== "undefined"; - var tabId = inIframe ? window.top.dnn.getVar('sf_tabId') : ''; - var siteRoot = inIframe ? window.top.dnn.getVar('sf_siteRoot') : ''; - var antiForgeryToken = inIframe ? window.top.document.getElementsByName('__RequestVerificationToken')[0].value : ''; + var tabId = inIframe ? window.parent.dnn.getVar('sf_tabId') : ''; + var siteRoot = inIframe ? window.parent.dnn.getVar('sf_siteRoot') : ''; + var antiForgeryToken = inIframe ? window.parent.document.getElementsByName('__RequestVerificationToken')[0].value : ''; var config = $.extend({}, { tabId: tabId, From a9211eace60ad08aeb71550714451876b69f7aa0 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Sat, 13 Feb 2021 20:49:35 -0600 Subject: [PATCH 07/53] Update Yarn.MsBuild --- Build/BuildScripts/AEModule.build | 4 +- .../Dnn.PersonaBar.Extensions/packages.config | 2 +- yarn.lock | 62 +++---------------- 3 files changed, 10 insertions(+), 58 deletions(-) diff --git a/Build/BuildScripts/AEModule.build b/Build/BuildScripts/AEModule.build index 92699faf715..f0e0e479836 100644 --- a/Build/BuildScripts/AEModule.build +++ b/Build/BuildScripts/AEModule.build @@ -1,7 +1,7 @@  - - + + $(MSBuildProjectDirectory)\Package\Resources\admin\personaBar diff --git a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/packages.config b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/packages.config index 18d1c6f560f..f4e514dfaf0 100644 --- a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/packages.config +++ b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ad1bf9d5a26..38cb1c6c9ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1247,32 +1247,6 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@dnnsoftware/dnn-react-common@9.7.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@dnnsoftware/dnn-react-common/-/dnn-react-common-2.1.2.tgz#8af42e5f4fe8075fb80b7f62d2b1f0893fe397d3" - integrity sha512-OvPmcaMGZbSnlxweT0jmhDe9lSiJYxNtHHht+mj8XHKts9g6/41RIP9EnCCbdaOt+bieuu15yG9EHI5aWHS++g== - dependencies: - interact.js "^1.2.8" - moment "^2.22.2" - raw-loader "0.5.1" - react-accessible-tooltip "^2.0.3" - react-collapse "^4.0.3" - react-custom-scrollbars "^4.2.1" - react-day-picker "^7.1.10" - react-height "^3.0.0" - react-modal "^3.5.1" - react-motion "^0.5.2" - react-scrollbar "^0.5.4" - react-slider "0.11.2" - react-tabs "2.3.0" - react-test-utils "0.0.1" - react-tooltip "^3.8.4" - react-widgets "^4.4.4" - redux-undo "^1.0.0-beta9" - scroll "^2.0.3" - shortid "^2.2.13" - throttle-debounce "^2.0.1" - "@emotion/cache@^10.0.9": version "10.0.9" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.9.tgz#e0c7b7a289f7530edcfad4dcf3858bd2e5700a6f" @@ -6371,6 +6345,11 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +dayjs@^1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2" + integrity sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw== + dayjs@^1.8.36: version "1.8.36" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50" @@ -8526,7 +8505,7 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global@^4.3.0, global@^4.3.2, global@~4.3.0: +global@^4.3.0, global@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= @@ -11354,7 +11333,7 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@^2.15.0, moment@^2.22.1, moment@^2.22.2: +moment@^2.22.1: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== @@ -13303,13 +13282,6 @@ raf@^3.1.0, raf@^3.4.0: dependencies: performance-now "^2.1.0" -rafl@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rafl/-/rafl-1.2.2.tgz#fe930f758211020d47e38815f5196a8be4150740" - integrity sha1-/pMPdYIRAg1H44gV9Rlqi+QVB0A= - dependencies: - global "~4.3.0" - railroad-diagrams@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" @@ -13373,11 +13345,6 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-loader@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" - integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= - raw-loader@2.0.0, raw-loader@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-2.0.0.tgz#e2813d9e1e3f80d1bbade5ad082e809679e20c26" @@ -13805,14 +13772,6 @@ react-syntax-highlighter@^8.0.1: prismjs "^1.8.4" refractor "^2.4.1" -react-tabs@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-2.3.0.tgz#0c37e786f288d369824acd06a96bd1818ab8b0dc" - integrity sha512-pYaefgVy76/36AMEP+B8YuVVzDHa3C5UFZ3REU78zolk0qMxEhKvUFofvDCXyLZwf0RZjxIfiwok1BEb18nHyA== - dependencies: - classnames "^2.2.0" - prop-types "^15.5.0" - react-tabs@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127" @@ -14822,13 +14781,6 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -scroll@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/scroll/-/scroll-2.0.3.tgz#0951b785544205fd17753bc3d294738ba16fc2ab" - integrity sha512-3ncZzf8gUW739h3LeS68nSssO60O+GGjT3SxzgofQmT8PIoyHzebql9HHPJopZX8iT6TKOdwaWFMqL6LzUN3DQ== - dependencies: - rafl "~1.2.1" - scroll@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/scroll/-/scroll-3.0.1.tgz#d5afb59fb3592ee3df31c89743e78b39e4cd8a26" From e5c1f9cea5c832ba0e5b8f8ddeb01a20b11d9871 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Mon, 15 Feb 2021 09:13:30 -0600 Subject: [PATCH 08/53] Use CI configuration for yarn install --frozen-lockfile ensures all dependencies are correctly specified in yarn.lock and does not try to update yarn.lock. This is desirable in CI both because it reduces extra work and because it ensures builds are consistent --- Build/BuildScripts/AEModule.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/BuildScripts/AEModule.build b/Build/BuildScripts/AEModule.build index 92699faf715..eedb593d6bf 100644 --- a/Build/BuildScripts/AEModule.build +++ b/Build/BuildScripts/AEModule.build @@ -45,7 +45,7 @@ - + \ No newline at end of file From 78c4f621f27884dba262d2bfdec27336ee5b58de Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Mon, 15 Feb 2021 09:19:22 -0600 Subject: [PATCH 09/53] Add Yarn caching Based on https://docs.microsoft.com/en-us/azure/devops/pipelines/release/caching?view=azure-devops#nodejsyarn --- azure-pipelines.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9b639a72280..c145dc635c3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,6 +4,8 @@ pool: variables: - name: "Build.ArtifactStagingDirectory" value: "Artifacts/" + - name: "YARN_CACHE_FOLDER" + value: "$(Pipeline.Workspace)/.yarn" parameters: - name: "CakeTarget" @@ -44,6 +46,13 @@ pr: steps: +- task: Cache@2 + displayName: Cache Yarn packages + inputs: + key: 'yarn | "$(Agent.OS)" | yarn.lock' + restoreKeys: 'yarn | "$(Agent.OS)"' + path: $(YARN_CACHE_FOLDER) + - task: PowerShell@2 displayName: 'Run DNN Update Versions' inputs: From af6c63f07749040815ebce9f4f3d8db86a534e81 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Mon, 15 Feb 2021 10:21:31 -0600 Subject: [PATCH 10/53] Remove references to Module Creator As of DNN 9.8.1, Module Creator is not included in the distribution of DNN (see #4208) --- .../SqlDataProvider/DotNetNuke.Data.SqlDataProvider | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/DotNetNuke.Data.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/DotNetNuke.Data.SqlDataProvider index 66a84fdd1c1..627c1cc4b2a 100644 --- a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/DotNetNuke.Data.SqlDataProvider +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/DotNetNuke.Data.SqlDataProvider @@ -6203,7 +6203,6 @@ INSERT INTO {databaseOwner}[{objectQualifier}ContentItems] ([ContentItemID], [Co INSERT INTO {databaseOwner}[{objectQualifier}ContentItems] ([ContentItemID], [Content], [ContentTypeID], [TabID], [ModuleID], [ContentKey], [Indexed], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [StateID]) VALUES (66, N'Site Management', 1, 17, -1, N'', 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL) INSERT INTO {databaseOwner}[{objectQualifier}ContentItems] ([ContentItemID], [Content], [ContentTypeID], [TabID], [ModuleID], [ContentKey], [Indexed], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [StateID]) VALUES (68, N'AdvancedSettings', 3, -1, -1, NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL) INSERT INTO {databaseOwner}[{objectQualifier}ContentItems] ([ContentItemID], [Content], [ContentTypeID], [TabID], [ModuleID], [ContentKey], [Indexed], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [StateID]) VALUES (69, N'Account Registration', 3, -1, -1, N'', 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL) -INSERT INTO {databaseOwner}[{objectQualifier}ContentItems] ([ContentItemID], [Content], [ContentTypeID], [TabID], [ModuleID], [ContentKey], [Indexed], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [StateID]) VALUES (70, N'Module Creator', 3, -1, -1, NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL) SET IDENTITY_INSERT {databaseOwner}[{objectQualifier}ContentItems] OFF PRINT(N'Add 119 rows to {databaseOwner}[{objectQualifier}EventLogConfig]') @@ -6419,7 +6418,6 @@ INSERT INTO {databaseOwner}[{objectQualifier}Packages] ([PackageID], [PortalID], INSERT INTO {databaseOwner}[{objectQualifier}Packages] ([PackageID], [PortalID], [Name], [FriendlyName], [Description], [PackageType], [Version], [License], [Manifest], [Owner], [Organization], [Url], [Email], [ReleaseNotes], [IsSystemPackage], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [FolderName], [IconFile]) VALUES (99, NULL, N'DotNetNuke.DNNCSSEXCLUDESkinObject', N'DNNCSSEXCLUDE SkinObject', N'', N'SkinObject', N'08.00.01', NULL, NULL, N'DNN', N'DNN Corp.', N'http://www.dnnsoftware.com', N'support@dnnsoftware.com', NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL, NULL) INSERT INTO {databaseOwner}[{objectQualifier}Packages] ([PackageID], [PortalID], [Name], [FriendlyName], [Description], [PackageType], [Version], [License], [Manifest], [Owner], [Organization], [Url], [Email], [ReleaseNotes], [IsSystemPackage], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [FolderName], [IconFile]) VALUES (100, NULL, N'DotNetNuke.DNNJSINCLUDESkinObject', N'DNNJSINCLUDE SkinObject', N'', N'SkinObject', N'08.00.01', NULL, NULL, N'DNN', N'DNN Corp.', N'http://www.dnnsoftware.com', N'support@dnnsoftware.com', NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL, NULL) INSERT INTO {databaseOwner}[{objectQualifier}Packages] ([PackageID], [PortalID], [Name], [FriendlyName], [Description], [PackageType], [Version], [License], [Manifest], [Owner], [Organization], [Url], [Email], [ReleaseNotes], [IsSystemPackage], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [FolderName], [IconFile]) VALUES (101, NULL, N'DotNetNuke.DNNJSEXCLUDESkinObject', N'DNNJSEXCLUDE SkinObject', N'', N'SkinObject', N'08.00.01', NULL, NULL, N'DNN', N'DNN Corp.', N'http://www.dnnsoftware.com', N'support@dnnsoftware.com', NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, NULL, NULL) -INSERT INTO {databaseOwner}[{objectQualifier}Packages] ([PackageID], [PortalID], [Name], [FriendlyName], [Description], [PackageType], [Version], [License], [Manifest], [Owner], [Organization], [Url], [Email], [ReleaseNotes], [IsSystemPackage], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [FolderName], [IconFile]) VALUES (102, NULL, N'DotNetNuke.Module Creator', N'Module Creator', N'Development of modules.', N'Module', N'1.0.0', N'', N'', N'DNN', N'DNN Corp.', N'http://www.dnnsoftware.com', N'support@dnnsoftware.com', N'', 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, N'', N'~/Icons/Sigma/ModuleCreator_32x32.png') SET IDENTITY_INSERT {databaseOwner}[{objectQualifier}Packages] OFF PRINT(N'Add 2 rows to {databaseOwner}[{objectQualifier}Taxonomy_Vocabularies]') @@ -6467,7 +6465,6 @@ INSERT INTO {databaseOwner}[{objectQualifier}DesktopModules] ([DesktopModuleID], INSERT INTO {databaseOwner}[{objectQualifier}DesktopModules] ([DesktopModuleID], [FriendlyName], [Description], [Version], [IsPremium], [IsAdmin], [BusinessControllerClass], [FolderName], [ModuleName], [SupportedFeatures], [CompatibleVersions], [Dependencies], [Permissions], [PackageID], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [ContentItemId], [Shareable], [AdminPage], [HostPage]) VALUES (60, N'Console', N'Display children pages as icon links for navigation.', N'07.01.00', 0, 0, N'', N'Admin/Console', N'Console', 0, NULL, NULL, NULL, 65, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 11, 0, NULL, NULL) INSERT INTO {databaseOwner}[{objectQualifier}DesktopModules] ([DesktopModuleID], [FriendlyName], [Description], [Version], [IsPremium], [IsAdmin], [BusinessControllerClass], [FolderName], [ModuleName], [SupportedFeatures], [CompatibleVersions], [Dependencies], [Permissions], [PackageID], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [ContentItemId], [Shareable], [AdminPage], [HostPage]) VALUES (63, N'ViewProfile', NULL, N'08.00.01', 0, 0, N'', N'Admin/ViewProfile', N'ViewProfile', 0, NULL, NULL, NULL, 69, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 17, 0, NULL, NULL) INSERT INTO {databaseOwner}[{objectQualifier}DesktopModules] ([DesktopModuleID], [FriendlyName], [Description], [Version], [IsPremium], [IsAdmin], [BusinessControllerClass], [FolderName], [ModuleName], [SupportedFeatures], [CompatibleVersions], [Dependencies], [Permissions], [PackageID], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [ContentItemId], [Shareable], [AdminPage], [HostPage]) VALUES (69, N'Account Registration', N'Allow users to create membership in the site.', N'08.00.01', 0, 0, N'', N'Admin/Security', N'Registration', 0, NULL, NULL, NULL, 96, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 69, 0, NULL, NULL) -INSERT INTO {databaseOwner}[{objectQualifier}DesktopModules] ([DesktopModuleID], [FriendlyName], [Description], [Version], [IsPremium], [IsAdmin], [BusinessControllerClass], [FolderName], [ModuleName], [SupportedFeatures], [CompatibleVersions], [Dependencies], [Permissions], [PackageID], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [ContentItemId], [Shareable], [AdminPage], [HostPage]) VALUES (70, N'Module Creator', N'Development of modules.', N'01.00.00', 0, 1, N'', N'Admin/ModuleCreator', N'ModuleCreator', 0, NULL, NULL, NULL, 102, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 70, 0, N'', N'') SET IDENTITY_INSERT {databaseOwner}[{objectQualifier}DesktopModules] OFF PRINT(N'Add 36 rows to {databaseOwner}[{objectQualifier}SkinControls]') @@ -6542,7 +6539,6 @@ INSERT INTO {databaseOwner}[{objectQualifier}ContentItems_Tags] ([ContentItemTag INSERT INTO {databaseOwner}[{objectQualifier}ContentItems_Tags] ([ContentItemTagID], [ContentItemID], [TermID]) VALUES (24, 19, 1) INSERT INTO {databaseOwner}[{objectQualifier}ContentItems_Tags] ([ContentItemTagID], [ContentItemID], [TermID]) VALUES (25, 65, 1) INSERT INTO {databaseOwner}[{objectQualifier}ContentItems_Tags] ([ContentItemTagID], [ContentItemID], [TermID]) VALUES (26, 8, 1) -INSERT INTO {databaseOwner}[{objectQualifier}ContentItems_Tags] ([ContentItemTagID], [ContentItemID], [TermID]) VALUES (27, 70, 4) SET IDENTITY_INSERT {databaseOwner}[{objectQualifier}ContentItems_Tags] OFF PRINT(N'Add 11 rows to {databaseOwner}[{objectQualifier}CoreMessaging_NotificationTypes]') @@ -6570,7 +6566,6 @@ INSERT INTO {databaseOwner}[{objectQualifier}ModuleDefinitions] ([ModuleDefID], INSERT INTO {databaseOwner}[{objectQualifier}ModuleDefinitions] ([ModuleDefID], [FriendlyName], [DesktopModuleID], [DefaultCacheTime], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [DefinitionName]) VALUES (102, N'Console', 60, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, N'Console') INSERT INTO {databaseOwner}[{objectQualifier}ModuleDefinitions] ([ModuleDefID], [FriendlyName], [DesktopModuleID], [DefaultCacheTime], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [DefinitionName]) VALUES (105, N'ViewProfile', 63, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, N'ViewProfile') INSERT INTO {databaseOwner}[{objectQualifier}ModuleDefinitions] ([ModuleDefID], [FriendlyName], [DesktopModuleID], [DefaultCacheTime], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [DefinitionName]) VALUES (111, N'Account Registration', 69, -1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, N'Account Registration') -INSERT INTO {databaseOwner}[{objectQualifier}ModuleDefinitions] ([ModuleDefID], [FriendlyName], [DesktopModuleID], [DefaultCacheTime], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [DefinitionName]) VALUES (112, N'Module Creator', 70, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, N'Module Creator') SET IDENTITY_INSERT {databaseOwner}[{objectQualifier}ModuleDefinitions] OFF PRINT(N'Add 2 rows to {databaseOwner}[{objectQualifier}Skins]') @@ -6620,14 +6615,13 @@ INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (168, 15, N'User Roles', N'User Roles', N'DesktopModules/Admin/Security/SecurityRoles.ascx', N'~/Icons/Sigma/SecurityRoles_32X32_Standard.png', 1, NULL, N'http://help.dotnetnuke.com/070100/default.htm#Documentation/Using the Control Panel/Admin Console/Security Roles/About the Security Roles Module.html', 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (202, 102, NULL, N'Console', N'DesktopModules/Admin/Console/ViewConsole.ascx', NULL, -1, 0, N'http://help.dotnetnuke.com/070100/default.htm#Documentation/Building Your Site/Installed Modules/Console/About the Console Module.htm', 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (203, 102, N'Settings', N'Console Settings', N'DesktopModules/Admin/Console/Settings.ascx', NULL, 2, 0, NULL, 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) -INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (205, NULL, N'ViewSource', N'Develop Module', N'DesktopModules/Admin/ModuleCreator/viewsource.ascx', N'~/Icons/Sigma/Source_32X32_Standard.png', 3, 0, NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) +INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (205, NULL, N'ViewSource', N'Develop Module', N'Admin/Modules/viewsource.ascx', N'~/Icons/Sigma/Source_32X32_Standard.png', 3, 0, NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (209, 105, NULL, NULL, N'DesktopModules/Admin/ViewProfile/ViewProfile.ascx', N'~/Icons/Sigma/Profile_32X32_Standard.png', 0, 0, N'http://help.dotnetnuke.com/070100/default.htm#Documentation/Managing Your User Account/Managing Your Profile/Managing your User Profile.html', 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (210, 105, N'Settings', N'Settings', N'DesktopModules/Admin/ViewProfile/Settings.ascx', N'~/Icons/Sigma/Profile_32X32_Standard.png', 1, 0, NULL, 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (218, NULL, N'ModulePermissions', N'ModulePermissions', N'Admin/Modules/ModulePermissions.ascx', N'~/Icons/Sigma/Moduledefinitions_32X32_Standard.png', 4, 0, NULL, 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (223, 111, NULL, N'Account Registration', N'DesktopModules/Admin/Security/Register.ascx', N'~/Icons/Sigma/Users_32x32_Standard.png', -1, NULL, N'', 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (224, NULL, N'UrlProviderSettings', N'UrlProviderSettings', N'DesktopModules/Admin/UrlManagement/UrlProviderSettings.ascx', NULL, 2, NULL, NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (225, NULL, N'PasswordReset', N'PasswordReset', N'Admin/Security/PasswordReset.ascx', N'', -1, 0, NULL, 1, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 1) -INSERT INTO {databaseOwner}[{objectQualifier}ModuleControls] ([ModuleControlID], [ModuleDefID], [ControlKey], [ControlTitle], [ControlSrc], [IconFile], [ControlType], [ViewOrder], [HelpUrl], [SupportsPartialRendering], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [SupportsPopUps]) VALUES (228, 112, NULL, NULL, N'DesktopModules/Admin/ModuleCreator/CreateModule.ascx', N'~/DesktopModules/Admin/ModuleCreator/icon.png', 3, 0, NULL, 0, @CreateBy, @CreateOn, @UpdateBy, @UpdateOn, 0) SET IDENTITY_INSERT {databaseOwner}[{objectQualifier}ModuleControls] OFF PRINT(N'Add 2 rows to {databaseOwner}[{objectQualifier}Modules]') From afe0d804c94ead3f66375e337fa7d023da965492 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Tue, 16 Feb 2021 14:50:45 -0600 Subject: [PATCH 11/53] Add async support to mail providers --- .../Library/Services/Mail/CoreMailProvider.cs | 240 ++++++++++++------ .../Services/Mail/MailKitMailProvider.cs | 221 +++++++++------- .../Library/Services/Mail/MailProvider.cs | 29 ++- 3 files changed, 325 insertions(+), 165 deletions(-) diff --git a/DNN Platform/Library/Services/Mail/CoreMailProvider.cs b/DNN Platform/Library/Services/Mail/CoreMailProvider.cs index f795021905d..b53e6a05de1 100644 --- a/DNN Platform/Library/Services/Mail/CoreMailProvider.cs +++ b/DNN Platform/Library/Services/Mail/CoreMailProvider.cs @@ -9,6 +9,8 @@ namespace DotNetNuke.Services.Mail using System.Net; using System.Net.Mail; using System.Text.RegularExpressions; + using System.Threading; + using System.Threading.Tasks; using DotNetNuke.Common.Utilities; using DotNetNuke.Entities.Host; @@ -24,24 +26,91 @@ public class CoreMailProvider : MailProvider /// public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) { - // validate smtp server - if (smtpInfo == null || string.IsNullOrEmpty(smtpInfo.Server)) + var (host, port, errorMessage) = ParseSmtpServer(ref smtpInfo); + if (errorMessage != null) { - if (string.IsNullOrWhiteSpace(Host.SMTPServer)) + return errorMessage; + } + + using (var mailMessage = CreateMailMessage(mailInfo, smtpInfo)) + { + try { - return "SMTP Server not configured"; + using (var smtpClient = CreateSmtpClient(smtpInfo, host, port)) + { + smtpClient.Send(mailMessage); + } + + return string.Empty; } + catch (Exception exc) + { + return HandleException(exc); + } + } + } - smtpInfo = new SmtpInfo + /// + public override async Task SendMailAsync(MailInfo mailInfo, SmtpInfo smtpInfo = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var (host, port, errorMessage) = ParseSmtpServer(ref smtpInfo); + if (errorMessage != null) + { + return errorMessage; + } + + using (var mailMessage = CreateMailMessage(mailInfo, smtpInfo)) + { + try + { + using (var smtpClient = CreateSmtpClient(smtpInfo, host, port)) + { + await smtpClient.SendMailAsync(mailMessage); + } + + return string.Empty; + } + catch (Exception exc) { - Server = Host.SMTPServer, - Authentication = Host.SMTPAuthentication, - Username = Host.SMTPUsername, - Password = Host.SMTPPassword, - EnableSSL = Host.EnableSMTPSSL, - }; + return HandleException(exc); + } + } + } + + private static string ValidateSmtpInfo(SmtpInfo smtpInfo) + { + if (smtpInfo != null && !string.IsNullOrEmpty(smtpInfo.Server)) + { + return null; + } + + if (!string.IsNullOrWhiteSpace(Host.SMTPServer)) + { + return null; + } + + return "SMTP Server not configured"; + } + + private static SmtpInfo GetDefaultSmtpInfo(SmtpInfo smtpInfo) + { + if (smtpInfo != null && !string.IsNullOrEmpty(smtpInfo.Server)) + { + return smtpInfo; } + return new SmtpInfo + { + Server = Host.SMTPServer, + Authentication = Host.SMTPAuthentication, + Username = Host.SMTPUsername, + Password = Host.SMTPPassword, + EnableSSL = Host.EnableSMTPSSL, + }; + } + + private static MailMessage CreateMailMessage(MailInfo mailInfo, SmtpInfo smtpInfo) + { // translate semi-colon delimiters to commas as ASP.NET 2.0 does not support semi-colons if (!string.IsNullOrEmpty(mailInfo.To)) { @@ -81,8 +150,9 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) var senderAddress = mailInfo.Sender; var senderDisplayName = mailInfo.FromName; var needUpdateSender = false; - if (smtpInfo.Username.Contains("@") && senderAddress == Host.HostEmail && - !senderAddress.Equals(smtpInfo.Username, StringComparison.InvariantCultureIgnoreCase)) + if (smtpInfo.Username.Contains("@") + && senderAddress == Host.HostEmail + && !senderAddress.Equals(smtpInfo.Username, StringComparison.InvariantCultureIgnoreCase)) { senderAddress = smtpInfo.Username; needUpdateSender = true; @@ -101,7 +171,9 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) } else if (smtpInfo.Username.Contains("@")) { - mailMessage.Sender = new MailAddress(smtpInfo.Username, Host.SMTPPortalEnabled ? PortalSettings.Current.PortalName : Host.HostTitle); + mailMessage.Sender = new MailAddress( + smtpInfo.Username, + Host.SMTPPortalEnabled ? PortalSettings.Current.PortalName : Host.HostTitle); } } @@ -121,81 +193,107 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) // message mailMessage.Subject = HtmlUtils.StripWhiteSpace(mailInfo.Subject, true); mailMessage.Body = mailInfo.Body; + return mailMessage; + } + + private static (string host, int? port, string errorMessage) ParseSmtpServer(ref SmtpInfo smtpInfo) + { + var errorMessage = ValidateSmtpInfo(smtpInfo); + if (errorMessage != null) + { + return (null, null, errorMessage); + } + + smtpInfo = GetDefaultSmtpInfo(smtpInfo); + smtpInfo.Server = smtpInfo.Server.Trim(); if (!SmtpServerRegex.IsMatch(smtpInfo.Server)) { - return Localize.GetString("SMTPConfigurationProblem"); + return (null, null, Localize.GetString("SMTPConfigurationProblem")); + } + + var smtpHostParts = smtpInfo.Server.Split(':'); + var host = smtpHostParts[0]; + if (smtpHostParts.Length <= 1) + { + return (host, null, null); + } + + // port is guaranteed to be of max 5 digits numeric by the RegEx check + var port = int.Parse(smtpHostParts[1]); + if (port < 1 || port > 65535) + { + return (null, null, Localize.GetString("SmtpInvalidPort")); } + return (host, port, null); + } + + private static SmtpClient CreateSmtpClient(SmtpInfo smtpInfo, string host, int? port) + { + SmtpClient client = null; try { - // to workaround problem in 4.0 need to specify host name - using (var smtpClient = new SmtpClient()) + client = new SmtpClient(); + client.Host = host; + if (port != null) { - var smtpHostParts = smtpInfo.Server.Split(':'); - smtpClient.Host = smtpHostParts[0]; - if (smtpHostParts.Length > 1) - { - // port is guaranteed to be of max 5 digits numeric by the RegEx check - var port = int.Parse(smtpHostParts[1]); - if (port < 1 || port > 65535) - { - return Localize.GetString("SmtpInvalidPort"); - } - - smtpClient.Port = port; - } + client.Port = port.Value; + } - switch (smtpInfo.Authentication) - { - case "": - case "0": // anonymous - break; - case "1": // basic - if (!string.IsNullOrEmpty(smtpInfo.Username) - && !string.IsNullOrEmpty(smtpInfo.Password)) - { - smtpClient.UseDefaultCredentials = false; - smtpClient.Credentials = new NetworkCredential( - smtpInfo.Username, - smtpInfo.Password); - } - - break; - case "2": // NTLM - smtpClient.UseDefaultCredentials = true; - break; - } + SetSmtpClientAuthentication(smtpInfo, client); - smtpClient.EnableSsl = smtpInfo.EnableSSL; - smtpClient.Send(mailMessage); - smtpClient.Dispose(); - } + client.EnableSsl = smtpInfo.EnableSSL; - return string.Empty; + var returnedClient = client; + client = null; + + return returnedClient; } - catch (Exception exc) + finally { - var retValue = Localize.GetString("SMTPConfigurationProblem") + " "; + client?.Dispose(); + } + } - // mail configuration problem - if (exc.InnerException != null) - { - retValue += string.Concat(exc.Message, Environment.NewLine, exc.InnerException.Message); - Exceptions.Exceptions.LogException(exc.InnerException); - } - else - { - retValue += exc.Message; - Exceptions.Exceptions.LogException(exc); - } + private static void SetSmtpClientAuthentication(SmtpInfo smtpInfo, SmtpClient smtpClient) + { + switch (smtpInfo.Authentication) + { + case "": + case "0": // anonymous + break; + case "1": // basic + if (!string.IsNullOrEmpty(smtpInfo.Username) && !string.IsNullOrEmpty(smtpInfo.Password)) + { + smtpClient.UseDefaultCredentials = false; + smtpClient.Credentials = new NetworkCredential(smtpInfo.Username, smtpInfo.Password); + } - return retValue; + break; + case "2": // NTLM + smtpClient.UseDefaultCredentials = true; + break; } - finally + } + + private static string HandleException(Exception exc) + { + var retValue = Localize.GetString("SMTPConfigurationProblem") + " "; + + // mail configuration problem + if (exc.InnerException != null) { - mailMessage.Dispose(); + retValue += string.Concat(exc.Message, Environment.NewLine, exc.InnerException.Message); + Exceptions.Exceptions.LogException(exc.InnerException); } + else + { + retValue += exc.Message; + Exceptions.Exceptions.LogException(exc); + } + + return retValue; } } } diff --git a/DNN Platform/Library/Services/Mail/MailKitMailProvider.cs b/DNN Platform/Library/Services/Mail/MailKitMailProvider.cs index 644d4c0cc4d..da581c6b5be 100644 --- a/DNN Platform/Library/Services/Mail/MailKitMailProvider.cs +++ b/DNN Platform/Library/Services/Mail/MailKitMailProvider.cs @@ -6,6 +6,8 @@ namespace DotNetNuke.Services.Mail using System; using System.Linq; using System.Text.RegularExpressions; + using System.Threading; + using System.Threading.Tasks; using DotNetNuke.Common.Utilities; using DotNetNuke.Entities.Host; @@ -26,24 +28,140 @@ public class MailKitMailProvider : MailProvider /// public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) { - // validate smtp server + try + { + var (host, port, errorMessage) = ParseSmtpServer(ref smtpInfo); + if (errorMessage != null) + { + return errorMessage; + } + + var mailMessage = CreateMailMessage(mailInfo, smtpInfo); + + using (var smtpClient = new SmtpClient()) + { + smtpClient.Connect(host, port, SecureSocketOptions.Auto); + + if (smtpInfo.Authentication == "1" && !string.IsNullOrEmpty(smtpInfo.Username) && !string.IsNullOrEmpty(smtpInfo.Password)) + { + smtpClient.Authenticate(smtpInfo.Username, smtpInfo.Password); + } + + smtpClient.Send(mailMessage); + smtpClient.Disconnect(true); + } + + return string.Empty; + } + catch (Exception exc) + { + return HandleException(exc); + } + } + + /// + public override async Task SendMailAsync(MailInfo mailInfo, SmtpInfo smtpInfo = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var (host, port, errorMessage) = ParseSmtpServer(ref smtpInfo); + if (errorMessage != null) + { + return errorMessage; + } + + var mailMessage = CreateMailMessage(mailInfo, smtpInfo); + + try + { + using (var smtpClient = new SmtpClient()) + { + await smtpClient.ConnectAsync(host, port, SecureSocketOptions.Auto, cancellationToken); + + if (smtpInfo.Authentication == "1" && !string.IsNullOrEmpty(smtpInfo.Username) && !string.IsNullOrEmpty(smtpInfo.Password)) + { + await smtpClient.AuthenticateAsync(smtpInfo.Username, smtpInfo.Password, cancellationToken); + } + + await smtpClient.SendAsync(mailMessage, cancellationToken); + await smtpClient.DisconnectAsync(true, cancellationToken); + } + + return string.Empty; + } + catch (Exception exc) + { + return HandleException(exc); + } + } + + private static (string host, int port, string errorMessage) ParseSmtpServer(ref SmtpInfo smtpInfo) + { + var port = 25; if (smtpInfo == null || string.IsNullOrEmpty(smtpInfo.Server)) { if (string.IsNullOrWhiteSpace(Host.SMTPServer)) { - return "SMTP Server not configured"; + return (null, port, "SMTP Server not configured"); } smtpInfo = new SmtpInfo - { - Server = Host.SMTPServer, - Authentication = Host.SMTPAuthentication, - Username = Host.SMTPUsername, - Password = Host.SMTPPassword, - EnableSSL = Host.EnableSMTPSSL, - }; + { + Server = Host.SMTPServer, + Authentication = Host.SMTPAuthentication, + Username = Host.SMTPUsername, + Password = Host.SMTPPassword, + EnableSSL = Host.EnableSMTPSSL, + }; + } + + if (smtpInfo.Authentication == "2") + { + throw new NotSupportedException("NTLM authentication is not supported by MailKit provider"); + } + + smtpInfo.Server = smtpInfo.Server.Trim(); + if (!SmtpServerRegex.IsMatch(smtpInfo.Server)) + { + return (null, port, Localize.GetString("SMTPConfigurationProblem")); } + var smtpHostParts = smtpInfo.Server.Split(':'); + var host = smtpHostParts[0]; + if (smtpHostParts.Length <= 1) + { + return (host, port, null); + } + + // port is guaranteed to be of max 5 digits numeric by the RegEx check + port = int.Parse(smtpHostParts[1]); + if (port < 1 || port > 65535) + { + return (host, port, Localize.GetString("SmtpInvalidPort")); + } + + return (host, port, null); + } + + private static string HandleException(Exception exc) + { + var retValue = Localize.GetString("SMTPConfigurationProblem") + " "; + + // mail configuration problem + if (exc.InnerException != null) + { + retValue += string.Concat(exc.Message, Environment.NewLine, exc.InnerException.Message); + Exceptions.Exceptions.LogException(exc.InnerException); + } + else + { + retValue += exc.Message; + Exceptions.Exceptions.LogException(exc); + } + + return retValue; + } + + private static MimeMessage CreateMailMessage(MailInfo mailInfo, SmtpInfo smtpInfo) + { var mailMessage = new MimeMessage(); mailMessage.From.Add(ParseAddressWithDisplayName(displayName: mailInfo.FromName, address: mailInfo.From)); @@ -84,8 +202,9 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) var senderAddress = mailInfo.Sender; var senderDisplayName = mailInfo.FromName; var needUpdateSender = false; - if (smtpInfo.Username.Contains("@") && senderAddress == Host.HostEmail && - !senderAddress.Equals(smtpInfo.Username, StringComparison.InvariantCultureIgnoreCase)) + if (smtpInfo.Username.Contains("@") + && senderAddress == Host.HostEmail + && !senderAddress.Equals(smtpInfo.Username, StringComparison.InvariantCultureIgnoreCase)) { senderAddress = smtpInfo.Username; needUpdateSender = true; @@ -99,7 +218,9 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) if (needUpdateSender) { - mailMessage.Sender = ParseAddressWithDisplayName(displayName: senderDisplayName, address: senderAddress); + mailMessage.Sender = ParseAddressWithDisplayName( + displayName: senderDisplayName, + address: senderAddress); } } else if (smtpInfo.Username.Contains("@")) @@ -110,10 +231,7 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) } } - var builder = new BodyBuilder - { - TextBody = Mail.ConvertToText(mailInfo.Body), - }; + var builder = new BodyBuilder { TextBody = Mail.ConvertToText(mailInfo.Body), }; if (mailInfo.BodyFormat == MailFormat.Html) { @@ -132,76 +250,7 @@ public override string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null) // message mailMessage.Subject = HtmlUtils.StripWhiteSpace(mailInfo.Subject, true); mailMessage.Body = builder.ToMessageBody(); - - smtpInfo.Server = smtpInfo.Server.Trim(); - - if (!SmtpServerRegex.IsMatch(smtpInfo.Server)) - { - return Localize.GetString("SMTPConfigurationProblem"); - } - - try - { - var smtpHostParts = smtpInfo.Server.Split(':'); - var host = smtpHostParts[0]; - var port = 25; - - if (smtpHostParts.Length > 1) - { - // port is guaranteed to be of max 5 digits numeric by the RegEx check - port = int.Parse(smtpHostParts[1]); - if (port < 1 || port > 65535) - { - return Localize.GetString("SmtpInvalidPort"); - } - } - - // to workaround problem in 4.0 need to specify host name - using (var smtpClient = new SmtpClient()) - { - smtpClient.Connect(host, port, SecureSocketOptions.Auto); - - switch (smtpInfo.Authentication) - { - case "": - case "0": // anonymous - break; - case "1": // basic - if (!string.IsNullOrEmpty(smtpInfo.Username) - && !string.IsNullOrEmpty(smtpInfo.Password)) - { - smtpClient.Authenticate(smtpInfo.Username, smtpInfo.Password); - } - - break; - case "2": // NTLM (Not Supported by MailKit) - throw new NotSupportedException("NTLM authentication is not supported by MailKit provider"); - } - - smtpClient.Send(mailMessage); - smtpClient.Disconnect(true); - } - - return string.Empty; - } - catch (Exception exc) - { - var retValue = Localize.GetString("SMTPConfigurationProblem") + " "; - - // mail configuration problem - if (exc.InnerException != null) - { - retValue += string.Concat(exc.Message, Environment.NewLine, exc.InnerException.Message); - Exceptions.Exceptions.LogException(exc.InnerException); - } - else - { - retValue += exc.Message; - Exceptions.Exceptions.LogException(exc); - } - - return retValue; - } + return mailMessage; } private static MailboxAddress ParseAddressWithDisplayName(string displayName, string address) diff --git a/DNN Platform/Library/Services/Mail/MailProvider.cs b/DNN Platform/Library/Services/Mail/MailProvider.cs index d3220397869..163f4334847 100644 --- a/DNN Platform/Library/Services/Mail/MailProvider.cs +++ b/DNN Platform/Library/Services/Mail/MailProvider.cs @@ -3,22 +3,35 @@ // See the LICENSE file in the project root for more information namespace DotNetNuke.Services.Mail { + using System.Threading; + using System.Threading.Tasks; + using DotNetNuke.ComponentModel; /// A provider with the ability to send emails. public abstract class MailProvider - { - /// Sends an email. - /// Information about the message to send. - /// Information about the SMTP server via which to send the message. - /// if the message send successfully, otherwise an error message. - public abstract string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null); - - /// Gets the currently configured instance. + { + /// Gets the currently configured instance. /// A instance. public static MailProvider Instance() { return ComponentFactory.GetComponent(); } + + /// Sends an email. + /// Information about the message to send. + /// Information about the SMTP server via which to send the message. + /// if the message send successfully, otherwise an error message. + public abstract string SendMail(MailInfo mailInfo, SmtpInfo smtpInfo = null); + + /// Sends an email. + /// Information about the message to send. + /// Information about the SMTP server via which to send the message. + /// The cancellation token. + /// if the message send successfully, otherwise an error message. + public virtual async Task SendMailAsync(MailInfo mailInfo, SmtpInfo smtpInfo = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return this.SendMail(mailInfo, smtpInfo); + } } } From c4a6e76dc71a650b8df635fb06c11cc2ff5e0671 Mon Sep 17 00:00:00 2001 From: msant7 Date: Wed, 17 Feb 2021 06:44:56 -0700 Subject: [PATCH 12/53] Update DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs Co-authored-by: Daniel Valadas --- .../AzureFolderProvider.cs | 635 +++++++++--------- 1 file changed, 321 insertions(+), 314 deletions(-) diff --git a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs index a0fe181ded4..33d4fc66899 100644 --- a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs +++ b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs @@ -2,280 +2,287 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -namespace DotNetNuke.Providers.FolderProviders.AzureFolderProvider -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Net; - using System.Threading; - using System.Web.Caching; - - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.Providers.FolderProviders.Components; - using DotNetNuke.Services.FileSystem; - using Microsoft.WindowsAzure.Storage; - using Microsoft.WindowsAzure.Storage.Auth; - using Microsoft.WindowsAzure.Storage.Blob; - - /// - /// Windows Azure Storage Folder Provider. - /// - public class AzureFolderProvider : BaseRemoteStorageProvider - { - public AzureFolderProvider() - { - ServicePointManager.DefaultConnectionLimit = 100; - ServicePointManager.UseNagleAlgorithm = false; - ServicePointManager.Expect100Continue = false; - } - - protected override string FileNotFoundMessage - { - get - { - return "Azure File Not Found"; - } - } - - protected override string ObjectCacheKey - { - get { return "Azure_Object_{0}_{1}"; } - } - - protected override string ListObjectsCacheKey - { - get { return "Azure_ListObjects_{0}"; } - } - - /// - /// Azure Storage doesn't support folders, so we create a file in order for the folder to not be deleted during future synchronizations. - /// The file has an extension not allowed by host. This way the file won't be added during synchronizations. - /// - public override void AddFolder(string folderPath, FolderMappingInfo folderMapping, string mappedPath) - { - Requires.NotNull("folderPath", folderPath); - Requires.NotNull("folderMapping", folderMapping); - - this.UpdateFileInternal(new MemoryStream(), folderMapping, mappedPath + Constants.PlaceHolderFileName); - } - - /// - /// Gets the direct Url to the file. - /// - /// - public override string GetFileUrl(IFileInfo file) - { - Requires.NotNull("file", file); - - var folderMapping = FolderMappingController.Instance.GetFolderMapping(file.PortalId, file.FolderMappingID); - var directLink = string.IsNullOrEmpty(GetSetting(folderMapping, Constants.DirectLink)) || GetSetting(folderMapping, Constants.DirectLink).ToLowerInvariant() == "true"; - - if (directLink) - { - var folder = FolderManager.Instance.GetFolder(file.FolderId); - var uri = folder.MappedPath + file.FileName; - - var container = this.GetContainer(folderMapping); - var blob = container.GetBlobReference(uri); - var absuri = blob.Uri.AbsoluteUri; - var customDomain = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.CustomDomain); - - if (!string.IsNullOrEmpty(customDomain)) - { - var customUri = new UriBuilder(customDomain).Uri; - absuri = - new UriBuilder(blob.Uri.AbsoluteUri) { Host = customUri.Host, Scheme = customUri.Scheme, Port = customUri.Port } - .Uri.AbsoluteUri; - } - - const string groupPolicyIdentifier = "DNNFileManagerPolicy"; - - var permissions = container.GetPermissions(); - - SharedAccessBlobPolicy policy; - - permissions.SharedAccessPolicies.TryGetValue(groupPolicyIdentifier, out policy); - - if (policy == null) - { - policy = new SharedAccessBlobPolicy { Permissions = SharedAccessBlobPermissions.Read, SharedAccessExpiryTime = DateTime.UtcNow.AddYears(100) }; - - permissions.SharedAccessPolicies.Add(groupPolicyIdentifier, policy); - } - else - { - policy.Permissions = SharedAccessBlobPermissions.Read; - policy.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(100); - } - - /* - * Workaround for CONTENT-3662 - * The Azure Client Storage api has issue when used with Italian Thread.Culture or eventually other cultures - * (see this article for further information https://connect.microsoft.com/VisualStudio/feedback/details/760974/windows-azure-sdk-cloudblobcontainer-setpermissions-permissions-as-microsoft-windowsazure-storageclient-blobcontainerpermissions-error). - * This code changes the thread culture to en-US - */ - var currentCulture = Thread.CurrentThread.CurrentCulture; - if (currentCulture.Name != "en-US") - { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US"); - } - - container.SetPermissions(permissions); - - var signature = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy(), groupPolicyIdentifier); - - // Reset original Thread Culture - if (currentCulture.Name != "en-US") - { - Thread.CurrentThread.CurrentCulture = currentCulture; - } - - return absuri + signature; - } - - return FileLinkClickController.Instance.GetFileLinkClick(file); - } - - /// - /// Gets the URL of the image to display in FileManager tree. - /// - /// - public override string GetFolderProviderIconPath() - { - return Globals.ResolveUrl("~/Providers/FolderProviders/AzureFolderProvider/images/FolderAzure_32x32_Standard.png"); - } - - public List GetAllContainers(FolderMappingInfo folderMapping) - { - List containers = new List(); - var accountName = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountName); - var accountKey = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountKey); - var useHttps = GetBooleanSetting(folderMapping, Constants.UseHttps); - - var sc = new StorageCredentials(accountName, accountKey); - var csa = new CloudStorageAccount(sc, useHttps); - var blobClient = csa.CreateCloudBlobClient(); - blobClient.ListContainers().ToList().ForEach(x => containers.Add(x.Name)); - return containers; - } - - protected override void CopyFileInternal(FolderMappingInfo folderMapping, string sourceUri, string newUri) - { - var container = this.GetContainer(folderMapping); - - var sourceBlob = container.GetBlobReference(sourceUri); - var newBlob = container.GetBlobReference(newUri); - - newBlob.StartCopy(sourceBlob.Uri); - - this.ClearCache(folderMapping.FolderMappingID); - } - - protected override void DeleteFileInternal(FolderMappingInfo folderMapping, string uri) - { - var container = this.GetContainer(folderMapping); - var blob = container.GetBlobReference(uri); - - blob.DeleteIfExists(); - - this.ClearCache(folderMapping.FolderMappingID); - } - - protected override void DeleteFolderInternal(FolderMappingInfo folderMapping, IFolderInfo folder) - { - this.DeleteFileInternal(folderMapping, folder.MappedPath + Constants.PlaceHolderFileName); - } - - protected override Stream GetFileStreamInternal(FolderMappingInfo folderMapping, string uri) - { - var container = this.GetContainer(folderMapping); - var blob = container.GetBlockBlobReference(uri); - - var memoryStream = new MemoryStream(); - blob.DownloadToStream(memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - - return memoryStream; - } - - protected override IList GetObjectList(FolderMappingInfo folderMapping) - { - var cacheKey = string.Format(this.ListObjectsCacheKey, folderMapping.FolderMappingID); - - return CBO.GetCachedObject>( - new CacheItemArgs( - cacheKey, - this.ListObjectsCacheTimeout, - CacheItemPriority.Default, - folderMapping.FolderMappingID), - c => - { - var container = this.GetContainer(folderMapping); - var synchBatchSize = GetIntegerSetting(folderMapping, Constants.SyncBatchSize, Constants.DefaultSyncBatchSize); - - BlobContinuationToken continuationToken = null; - BlobResultSegment resultSegment = null; - - var list = new List(); - do - { - // This overload allows control of the page size. You can return all remaining results by passing null for the maxResults parameter, - // or by calling a different overload. - resultSegment = container.ListBlobsSegmented(string.Empty, true, BlobListingDetails.All, synchBatchSize, continuationToken, null, null); - foreach (var blobItem in resultSegment.Results) - { - list.Add(new AzureRemoteStorageItem { Blob = new AzureBlob(blobItem as CloudBlob) }); - } - - // Get the continuation token. - continuationToken = resultSegment.ContinuationToken; - } - while (continuationToken != null); - - return list; - }); - } - - protected override void MoveFileInternal(FolderMappingInfo folderMapping, string sourceUri, string newUri) - { - var container = this.GetContainer(folderMapping); - - var sourceBlob = container.GetBlobReference(sourceUri); - var newBlob = container.GetBlobReference(newUri); - - newBlob.StartCopy(sourceBlob.Uri); - sourceBlob.Delete(); - - this.ClearCache(folderMapping.FolderMappingID); - } - - protected override void MoveFolderInternal(FolderMappingInfo folderMapping, string sourceUri, string newUri) - { - var container = this.GetContainer(folderMapping); - var directory = container.GetDirectoryReference(sourceUri); - var blobs = directory.ListBlobs(true); - - foreach (var blobItem in blobs) - { - var blob = (CloudBlob)blobItem; - var newBlob = container.GetBlobReference(newUri + blobItem.Uri.LocalPath.Substring(directory.Uri.LocalPath.Length)); - newBlob.StartCopy(blob.Uri); - blob.Delete(); - } - - this.ClearCache(folderMapping.FolderMappingID); - } - +namespace DotNetNuke.Providers.FolderProviders.AzureFolderProvider +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Net; + using System.Threading; + using System.Web.Caching; + + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Providers.FolderProviders.Components; + using DotNetNuke.Services.FileSystem; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Auth; + using Microsoft.WindowsAzure.Storage.Blob; + + /// + /// Windows Azure Storage Folder Provider. + /// + public class AzureFolderProvider : BaseRemoteStorageProvider + { + public AzureFolderProvider() + { + ServicePointManager.DefaultConnectionLimit = 100; + ServicePointManager.UseNagleAlgorithm = false; + ServicePointManager.Expect100Continue = false; + } + + protected override string FileNotFoundMessage + { + get + { + return "Azure File Not Found"; + } + } + + protected override string ObjectCacheKey + { + get { return "Azure_Object_{0}_{1}"; } + } + + protected override string ListObjectsCacheKey + { + get { return "Azure_ListObjects_{0}"; } + } + + /// + /// Azure Storage doesn't support folders, so we create a file in order for the folder to not be deleted during future synchronizations. + /// The file has an extension not allowed by host. This way the file won't be added during synchronizations. + /// + public override void AddFolder(string folderPath, FolderMappingInfo folderMapping, string mappedPath) + { + Requires.NotNull("folderPath", folderPath); + Requires.NotNull("folderMapping", folderMapping); + + this.UpdateFileInternal(new MemoryStream(), folderMapping, mappedPath + Constants.PlaceHolderFileName); + } + + /// + /// Gets the direct Url to the file. + /// + /// + public override string GetFileUrl(IFileInfo file) + { + Requires.NotNull("file", file); + + var folderMapping = FolderMappingController.Instance.GetFolderMapping(file.PortalId, file.FolderMappingID); + var directLink = string.IsNullOrEmpty(GetSetting(folderMapping, Constants.DirectLink)) || GetSetting(folderMapping, Constants.DirectLink).ToLowerInvariant() == "true"; + + if (directLink) + { + var folder = FolderManager.Instance.GetFolder(file.FolderId); + var uri = folder.MappedPath + file.FileName; + + var container = this.GetContainer(folderMapping); + var blob = container.GetBlobReference(uri); + var absuri = blob.Uri.AbsoluteUri; + var customDomain = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.CustomDomain); + + if (!string.IsNullOrEmpty(customDomain)) + { + var customUri = new UriBuilder(customDomain).Uri; + absuri = + new UriBuilder(blob.Uri.AbsoluteUri) { Host = customUri.Host, Scheme = customUri.Scheme, Port = customUri.Port } + .Uri.AbsoluteUri; + } + + const string groupPolicyIdentifier = "DNNFileManagerPolicy"; + + var permissions = container.GetPermissions(); + + SharedAccessBlobPolicy policy; + + permissions.SharedAccessPolicies.TryGetValue(groupPolicyIdentifier, out policy); + + if (policy == null) + { + policy = new SharedAccessBlobPolicy { Permissions = SharedAccessBlobPermissions.Read, SharedAccessExpiryTime = DateTime.UtcNow.AddYears(100) }; + + permissions.SharedAccessPolicies.Add(groupPolicyIdentifier, policy); + } + else + { + policy.Permissions = SharedAccessBlobPermissions.Read; + policy.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(100); + } + + /* + * Workaround for CONTENT-3662 + * The Azure Client Storage api has issue when used with Italian Thread.Culture or eventually other cultures + * (see this article for further information https://connect.microsoft.com/VisualStudio/feedback/details/760974/windows-azure-sdk-cloudblobcontainer-setpermissions-permissions-as-microsoft-windowsazure-storageclient-blobcontainerpermissions-error). + * This code changes the thread culture to en-US + */ + var currentCulture = Thread.CurrentThread.CurrentCulture; + if (currentCulture.Name != "en-US") + { + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US"); + } + + container.SetPermissions(permissions); + + var signature = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy(), groupPolicyIdentifier); + + // Reset original Thread Culture + if (currentCulture.Name != "en-US") + { + Thread.CurrentThread.CurrentCulture = currentCulture; + } + + return absuri + signature; + } + + return FileLinkClickController.Instance.GetFileLinkClick(file); + } + + /// + /// Gets the URL of the image to display in FileManager tree. + /// + /// + public override string GetFolderProviderIconPath() + { + return Globals.ResolveUrl("~/Providers/FolderProviders/AzureFolderProvider/images/FolderAzure_32x32_Standard.png"); + } + + public List GetAllContainers(FolderMappingInfo folderMapping) + { + List containers = new List(); + var accountName = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountName); + var accountKey = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountKey); + var useHttps = GetBooleanSetting(folderMapping, Constants.UseHttps); + + var sc = new StorageCredentials(accountName, accountKey); + var csa = new CloudStorageAccount(sc, useHttps); + var blobClient = csa.CreateCloudBlobClient(); + blobClient.ListContainers().ToList().ForEach(x => containers.Add(x.Name)); + return containers; + } + + protected override void CopyFileInternal(FolderMappingInfo folderMapping, string sourceUri, string newUri) + { + var container = this.GetContainer(folderMapping); + + var sourceBlob = container.GetBlobReference(sourceUri); + var newBlob = container.GetBlobReference(newUri); + + newBlob.StartCopy(sourceBlob.Uri); + + this.ClearCache(folderMapping.FolderMappingID); + } + + protected override void DeleteFileInternal(FolderMappingInfo folderMapping, string uri) + { + var container = this.GetContainer(folderMapping); + var blob = container.GetBlobReference(uri); + + blob.DeleteIfExists(); + + this.ClearCache(folderMapping.FolderMappingID); + } + + protected override void DeleteFolderInternal(FolderMappingInfo folderMapping, IFolderInfo folder) + { + this.DeleteFileInternal(folderMapping, folder.MappedPath + Constants.PlaceHolderFileName); + } + + protected override Stream GetFileStreamInternal(FolderMappingInfo folderMapping, string uri) + { + var container = this.GetContainer(folderMapping); + var blob = container.GetBlockBlobReference(uri); + + var memoryStream = new MemoryStream(); + blob.DownloadToStream(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + + return memoryStream; + } + + protected override IList GetObjectList(FolderMappingInfo folderMapping) + { + var cacheKey = string.Format(this.ListObjectsCacheKey, folderMapping.FolderMappingID); + + return CBO.GetCachedObject>( + new CacheItemArgs( + cacheKey, + this.ListObjectsCacheTimeout, + CacheItemPriority.Default, + folderMapping.FolderMappingID), + c => + { + var container = this.GetContainer(folderMapping); + var synchBatchSize = GetIntegerSetting(folderMapping, Constants.SyncBatchSize, Constants.DefaultSyncBatchSize); + + BlobContinuationToken continuationToken = null; + BlobResultSegment resultSegment = null; + + var list = new List(); + do + { + // This overload allows control of the page size. You can return all remaining results by passing null for the maxResults parameter, + // or by calling a different overload. + resultSegment = container.ListBlobsSegmented(string.Empty, true, BlobListingDetails.All, synchBatchSize, continuationToken, null, null); + foreach (var blobItem in resultSegment.Results) + { + list.Add(new AzureRemoteStorageItem { Blob = new AzureBlob(blobItem as CloudBlob) }); + } + + // Get the continuation token. + continuationToken = resultSegment.ContinuationToken; + } + while (continuationToken != null); + + return list; + }); + } + + protected override void MoveFileInternal(FolderMappingInfo folderMapping, string sourceUri, string newUri) + { + var container = this.GetContainer(folderMapping); + + var sourceBlob = container.GetBlobReference(sourceUri); + var newBlob = container.GetBlobReference(newUri); + + newBlob.StartCopy(sourceBlob.Uri); + sourceBlob.Delete(); + + this.ClearCache(folderMapping.FolderMappingID); + } + + protected override void MoveFolderInternal(FolderMappingInfo folderMapping, string sourceUri, string newUri) + { + var container = this.GetContainer(folderMapping); + var directory = container.GetDirectoryReference(sourceUri); + var blobs = directory.ListBlobs(true); + + foreach (var blobItem in blobs) + { + var blob = (CloudBlob)blobItem; + var newBlob = container.GetBlobReference(newUri + blobItem.Uri.LocalPath.Substring(directory.Uri.LocalPath.Length)); + newBlob.StartCopy(blob.Uri); + blob.Delete(); + } + + this.ClearCache(folderMapping.FolderMappingID); + } + + /// + /// Updates a file in Azure folder provider. + /// + /// + /// Azure is case sensitive. If you update dnninternals.pdf with DNNINTERNALS.pdf, to DNN it's the same + /// so it just re-uploads it, causing both files to exist in Azure. This azure specific method deletes the + /// old existing duplicate that only differs in case as part of the update. + /// public override void UpdateFile(IFolderInfo folder, string fileName, Stream content) { - // Azure is case sensitive. If you update dnninternals.pdf with DNNINTERNALS.pdf, to DNN it's the same - // so it just re-uploads it, causing both files to exist in Azure. IFileInfo originalFile = FileManager.Instance.GetFile(folder, fileName); + base.UpdateFile(folder, fileName, content); if (originalFile != null && originalFile.FileName != fileName) @@ -285,47 +292,47 @@ public override void UpdateFile(IFolderInfo folder, string fileName, Stream cont } } - protected override void UpdateFileInternal(Stream stream, FolderMappingInfo folderMapping, string uri) - { - var container = this.GetContainer(folderMapping); - var blob = container.GetBlockBlobReference(uri); - - stream.Seek(0, SeekOrigin.Begin); - blob.UploadFromStream(stream); - - // Set the content type - blob.Properties.ContentType = FileContentTypeManager.Instance.GetContentType(Path.GetExtension(uri)); - blob.SetProperties(); - - this.ClearCache(folderMapping.FolderMappingID); - } - - private static void CheckSettings(FolderMappingInfo folderMapping) - { - var settings = folderMapping.FolderMappingSettings; - - if (string.IsNullOrEmpty((string)settings[Constants.AccountName]) || - string.IsNullOrEmpty((string)settings[Constants.AccountKey]) || - string.IsNullOrEmpty((string)settings[Constants.Container]) || - string.IsNullOrEmpty((string)settings[Constants.UseHttps])) - { - throw new Exception("Settings cannot be found."); - } - } - - private CloudBlobContainer GetContainer(FolderMappingInfo folderMapping) - { - CheckSettings(folderMapping); - - var accountName = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountName); - var accountKey = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountKey); - var container = GetSetting(folderMapping, Constants.Container); - var useHttps = GetBooleanSetting(folderMapping, Constants.UseHttps); - - var sc = new StorageCredentials(accountName, accountKey); - var csa = new CloudStorageAccount(sc, useHttps); - var blobClient = csa.CreateCloudBlobClient(); - return blobClient.GetContainerReference(container); - } - } -} + protected override void UpdateFileInternal(Stream stream, FolderMappingInfo folderMapping, string uri) + { + var container = this.GetContainer(folderMapping); + var blob = container.GetBlockBlobReference(uri); + + stream.Seek(0, SeekOrigin.Begin); + blob.UploadFromStream(stream); + + // Set the content type + blob.Properties.ContentType = FileContentTypeManager.Instance.GetContentType(Path.GetExtension(uri)); + blob.SetProperties(); + + this.ClearCache(folderMapping.FolderMappingID); + } + + private static void CheckSettings(FolderMappingInfo folderMapping) + { + var settings = folderMapping.FolderMappingSettings; + + if (string.IsNullOrEmpty((string)settings[Constants.AccountName]) || + string.IsNullOrEmpty((string)settings[Constants.AccountKey]) || + string.IsNullOrEmpty((string)settings[Constants.Container]) || + string.IsNullOrEmpty((string)settings[Constants.UseHttps])) + { + throw new Exception("Settings cannot be found."); + } + } + + private CloudBlobContainer GetContainer(FolderMappingInfo folderMapping) + { + CheckSettings(folderMapping); + + var accountName = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountName); + var accountKey = this.GetEncryptedSetting(folderMapping.FolderMappingSettings, Constants.AccountKey); + var container = GetSetting(folderMapping, Constants.Container); + var useHttps = GetBooleanSetting(folderMapping, Constants.UseHttps); + + var sc = new StorageCredentials(accountName, accountKey); + var csa = new CloudStorageAccount(sc, useHttps); + var blobClient = csa.CreateCloudBlobClient(); + return blobClient.GetContainerReference(container); + } + } +} From 89d4304362ca12c8dcf37653d240fd5de97503c0 Mon Sep 17 00:00:00 2001 From: Michael Santoro Date: Wed, 17 Feb 2021 08:34:18 -0700 Subject: [PATCH 13/53] #4499 Take Page Stylesheet from FolderProvider, add CSS to content types --- .../FileSystem/FileContentTypeManager.cs | 1 + DNN Platform/Website/Default.aspx.cs | 41 ++++++++++++++++++- .../SqlDataProvider/09.09.01.SqlDataProvider | 12 ++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider diff --git a/DNN Platform/Library/Services/FileSystem/FileContentTypeManager.cs b/DNN Platform/Library/Services/FileSystem/FileContentTypeManager.cs index 67c6764af95..d7efa9f7ad3 100644 --- a/DNN Platform/Library/Services/FileSystem/FileContentTypeManager.cs +++ b/DNN Platform/Library/Services/FileSystem/FileContentTypeManager.cs @@ -101,6 +101,7 @@ private Dictionary GetDefaultContentTypes() contentTypes.Add("pps", "application/vnd.ms-powerpoint"); contentTypes.Add("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); contentTypes.Add("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"); + contentTypes.Add("css", "text/css"); return contentTypes; } diff --git a/DNN Platform/Website/Default.aspx.cs b/DNN Platform/Website/Default.aspx.cs index 872a682d09f..65f10cc5017 100644 --- a/DNN Platform/Website/Default.aspx.cs +++ b/DNN Platform/Website/Default.aspx.cs @@ -632,8 +632,29 @@ private void InitializePage() // register the custom stylesheet of current page if (this.PortalSettings.ActiveTab.TabSettings.ContainsKey("CustomStylesheet") && !string.IsNullOrEmpty(this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString())) { - var customStylesheet = Path.Combine(this.PortalSettings.HomeDirectory, this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString()); - ClientResourceManager.RegisterStyleSheet(this, customStylesheet); + var customStylesheet = this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString(); + var cssIncluded = false; + + // Try and go through the FolderProvider first, if it gives back an external url, include it + // as a in the Page Header + IFileInfo fi = GetPageStylesheetFileInfo(); + if (fi != null) + { + string url = FileManager.Instance.GetUrl(fi); + if (url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) || url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) + { + string cssLink = string.Format("", url); + this.Page.Header.Controls.Add(new LiteralControl(cssLink)); + cssIncluded = true; + } + } + + // Include it as DNN always has, as a relative path through ClientResourceManager + if (!cssIncluded) + { + var customStylesheetPath = Path.Combine(this.PortalSettings.HomeDirectory, customStylesheet); + ClientResourceManager.RegisterStyleSheet(this, customStylesheetPath); + } } // Cookie Consent @@ -737,5 +758,21 @@ private IFileInfo GetBackgroundFileInfoCallBack(CacheItemArgs itemArgs) { return FileManager.Instance.GetFile(this.PortalSettings.PortalId, this.PortalSettings.BackgroundFile); } + + private IFileInfo GetPageStylesheetFileInfo() + { + string cacheKey = string.Format(Common.Utilities.DataCache.PortalCacheKey, this.PortalSettings.PortalId, "PageStylesheet" + this.PortalSettings.ActiveTab.TabID); + var file = CBO.GetCachedObject( + new CacheItemArgs(cacheKey, Common.Utilities.DataCache.PortalCacheTimeOut, Common.Utilities.DataCache.PortalCachePriority), + this.GetPageStylesheetInfoCallBack); + + return file; + } + + private IFileInfo GetPageStylesheetInfoCallBack(CacheItemArgs itemArgs) + { + var customStylesheet = this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString(); + return FileManager.Instance.GetFile(this.PortalSettings.PortalId, customStylesheet); + } } } diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider new file mode 100644 index 00000000000..63a8149c0ea --- /dev/null +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider @@ -0,0 +1,12 @@ +/************************************************************/ +/***** SqlDataProvider *****/ +/***** *****/ +/***** *****/ +/***** Note: To manually execute this script you must *****/ +/***** perform a search and replace operation *****/ +/***** for {databaseOwner} and {objectQualifier} *****/ +/***** *****/ +/************************************************************/ + +-- Add CSS contnet type, this will help when a Page Style Sheet is uploaded to a folder provider such as AzureFolderProvider. +INSERT INTO {databaseOwner}[{objectQualifier}Lists] ( [ListName], [Value], [Text], [ParentID], [Level], [SortOrder], [DefinitionID], [Description], [PortalID], [SystemList], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate]) VALUES (N'ContentTypes', N'css', N'text/css', 0, 0, 0, -1, N'', -1, 1, -1, '2020-02-17 09:13:51.647', -1, '2020-02-17 09:13:51.647') From d885ef93f2b0c975a62baa962f0ecde351440d3b Mon Sep 17 00:00:00 2001 From: Michael Santoro Date: Wed, 17 Feb 2021 08:41:22 -0700 Subject: [PATCH 14/53] #4499 check if css record exists (in case a user added it to their dnn) --- .../DataProviders/SqlDataProvider/09.09.01.SqlDataProvider | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider index 63a8149c0ea..63840ef1044 100644 --- a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider @@ -9,4 +9,7 @@ /************************************************************/ -- Add CSS contnet type, this will help when a Page Style Sheet is uploaded to a folder provider such as AzureFolderProvider. -INSERT INTO {databaseOwner}[{objectQualifier}Lists] ( [ListName], [Value], [Text], [ParentID], [Level], [SortOrder], [DefinitionID], [Description], [PortalID], [SystemList], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate]) VALUES (N'ContentTypes', N'css', N'text/css', 0, 0, 0, -1, N'', -1, 1, -1, '2020-02-17 09:13:51.647', -1, '2020-02-17 09:13:51.647') +IF NOT EXISTS (SELECT * FROM {databaseOwner}{objectQualifier}Lists WHERE ListName='ContentTypes' AND Value = 'css') +BEGIN + INSERT INTO {databaseOwner}[{objectQualifier}Lists] ( [ListName], [Value], [Text], [ParentID], [Level], [SortOrder], [DefinitionID], [Description], [PortalID], [SystemList], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate]) VALUES (N'ContentTypes', N'css', N'text/css', 0, 0, 0, -1, N'', -1, 1, -1, '2020-02-17 09:13:51.647', -1, '2020-02-17 09:13:51.647') +END From 07d7b37d580be5ffcc36ad4ad581dee1ea9a51b4 Mon Sep 17 00:00:00 2001 From: msant7 Date: Mon, 22 Feb 2021 06:04:43 -0700 Subject: [PATCH 15/53] Update DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider Co-authored-by: Brian Dukes --- .../DataProviders/SqlDataProvider/09.09.01.SqlDataProvider | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider index 63840ef1044..5bc71e40009 100644 --- a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider @@ -8,7 +8,7 @@ /***** *****/ /************************************************************/ --- Add CSS contnet type, this will help when a Page Style Sheet is uploaded to a folder provider such as AzureFolderProvider. +-- Add CSS content type, this will help when a Page Style Sheet is uploaded to a folder provider such as AzureFolderProvider. IF NOT EXISTS (SELECT * FROM {databaseOwner}{objectQualifier}Lists WHERE ListName='ContentTypes' AND Value = 'css') BEGIN INSERT INTO {databaseOwner}[{objectQualifier}Lists] ( [ListName], [Value], [Text], [ParentID], [Level], [SortOrder], [DefinitionID], [Description], [PortalID], [SystemList], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate]) VALUES (N'ContentTypes', N'css', N'text/css', 0, 0, 0, -1, N'', -1, 1, -1, '2020-02-17 09:13:51.647', -1, '2020-02-17 09:13:51.647') From 1574d99641a0d62699c454b0e61c24fe566a03a4 Mon Sep 17 00:00:00 2001 From: msant7 Date: Mon, 22 Feb 2021 06:04:58 -0700 Subject: [PATCH 16/53] Update DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider Co-authored-by: Brian Dukes --- .../DataProviders/SqlDataProvider/09.09.01.SqlDataProvider | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider index 5bc71e40009..05b2b72ca6c 100644 --- a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.01.SqlDataProvider @@ -11,5 +11,5 @@ -- Add CSS content type, this will help when a Page Style Sheet is uploaded to a folder provider such as AzureFolderProvider. IF NOT EXISTS (SELECT * FROM {databaseOwner}{objectQualifier}Lists WHERE ListName='ContentTypes' AND Value = 'css') BEGIN - INSERT INTO {databaseOwner}[{objectQualifier}Lists] ( [ListName], [Value], [Text], [ParentID], [Level], [SortOrder], [DefinitionID], [Description], [PortalID], [SystemList], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate]) VALUES (N'ContentTypes', N'css', N'text/css', 0, 0, 0, -1, N'', -1, 1, -1, '2020-02-17 09:13:51.647', -1, '2020-02-17 09:13:51.647') + INSERT INTO {databaseOwner}[{objectQualifier}Lists] ( [ListName], [Value], [Text], [ParentID], [Level], [SortOrder], [DefinitionID], [Description], [PortalID], [SystemList], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate]) VALUES (N'ContentTypes', N'css', N'text/css', 0, 0, 0, -1, N'', -1, 1, -1, GETDATE(), -1, GETDATE()) END From 91f620ec197a5341c3d40183cfe6478a4f0908ea Mon Sep 17 00:00:00 2001 From: Michael Santoro Date: Tue, 23 Feb 2021 07:06:35 -0700 Subject: [PATCH 17/53] refactor including the CustomStyleSheet after fixing an issue in ClientResourceManager.Register Stylesheet --- .../ClientResourceManager.cs | 3 +- DNN Platform/Website/Default.aspx.cs | 37 +++++++------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs b/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs index 38d26173136..df949124bf1 100644 --- a/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs +++ b/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs @@ -297,7 +297,8 @@ public static void RegisterStyleSheet(Page page, string filePath, int priority, // Some "legacy URLs" could be using their own query string versioning scheme (and we've forced them to use the new API through re-routing PageBase.RegisterStyleSheet // Ensure that physical CSS files with query strings have their query strings removed - if (filePath.Contains(".css?")) + // Ignore absolute urls, they will not exist locally + if (!Uri.TryCreate(filePath, UriKind.Absolute, out _) && filePath.Contains(".css?")) { var filePathSansQueryString = RemoveQueryString(filePath); if (File.Exists(page.Server.MapPath(filePathSansQueryString))) diff --git a/DNN Platform/Website/Default.aspx.cs b/DNN Platform/Website/Default.aspx.cs index 65f10cc5017..d37f01ad8c4 100644 --- a/DNN Platform/Website/Default.aspx.cs +++ b/DNN Platform/Website/Default.aspx.cs @@ -632,28 +632,17 @@ private void InitializePage() // register the custom stylesheet of current page if (this.PortalSettings.ActiveTab.TabSettings.ContainsKey("CustomStylesheet") && !string.IsNullOrEmpty(this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString())) { - var customStylesheet = this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString(); - var cssIncluded = false; - - // Try and go through the FolderProvider first, if it gives back an external url, include it - // as a in the Page Header - IFileInfo fi = GetPageStylesheetFileInfo(); - if (fi != null) + var styleSheet = this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString(); + + // Try and go through the FolderProvider first + var stylesheetFile = GetPageStylesheetFileInfo(styleSheet); + if (stylesheetFile != null) { - string url = FileManager.Instance.GetUrl(fi); - if (url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) || url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) - { - string cssLink = string.Format("", url); - this.Page.Header.Controls.Add(new LiteralControl(cssLink)); - cssIncluded = true; - } + ClientResourceManager.RegisterStyleSheet(this, FileManager.Instance.GetUrl(stylesheetFile)); } - - // Include it as DNN always has, as a relative path through ClientResourceManager - if (!cssIncluded) + else { - var customStylesheetPath = Path.Combine(this.PortalSettings.HomeDirectory, customStylesheet); - ClientResourceManager.RegisterStyleSheet(this, customStylesheetPath); + ClientResourceManager.RegisterStyleSheet(this, styleSheet); } } @@ -759,11 +748,11 @@ private IFileInfo GetBackgroundFileInfoCallBack(CacheItemArgs itemArgs) return FileManager.Instance.GetFile(this.PortalSettings.PortalId, this.PortalSettings.BackgroundFile); } - private IFileInfo GetPageStylesheetFileInfo() + private IFileInfo GetPageStylesheetFileInfo(string styleSheet) { - string cacheKey = string.Format(Common.Utilities.DataCache.PortalCacheKey, this.PortalSettings.PortalId, "PageStylesheet" + this.PortalSettings.ActiveTab.TabID); + string cacheKey = string.Format(Common.Utilities.DataCache.PortalCacheKey, this.PortalSettings.PortalId, "PageStylesheet" + styleSheet); var file = CBO.GetCachedObject( - new CacheItemArgs(cacheKey, Common.Utilities.DataCache.PortalCacheTimeOut, Common.Utilities.DataCache.PortalCachePriority), + new CacheItemArgs(cacheKey, Common.Utilities.DataCache.PortalCacheTimeOut, Common.Utilities.DataCache.PortalCachePriority, styleSheet), this.GetPageStylesheetInfoCallBack); return file; @@ -771,8 +760,8 @@ private IFileInfo GetPageStylesheetFileInfo() private IFileInfo GetPageStylesheetInfoCallBack(CacheItemArgs itemArgs) { - var customStylesheet = this.PortalSettings.ActiveTab.TabSettings["CustomStylesheet"].ToString(); - return FileManager.Instance.GetFile(this.PortalSettings.PortalId, customStylesheet); + var styleSheet = itemArgs.Params[0].ToString(); + return FileManager.Instance.GetFile(this.PortalSettings.PortalId, styleSheet); } } } From 19ce6719b365d0627c74ace2bb568cf0abaaa645 Mon Sep 17 00:00:00 2001 From: rhaiamz Date: Fri, 26 Feb 2021 15:23:15 +0200 Subject: [PATCH 18/53] Make sure the content is decoded before being passed to tokenization providers. --- DNN Platform/Modules/HTML/Components/HtmlTextController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DNN Platform/Modules/HTML/Components/HtmlTextController.cs b/DNN Platform/Modules/HTML/Components/HtmlTextController.cs index 40734829bb4..0fd2f5f4229 100644 --- a/DNN Platform/Modules/HTML/Components/HtmlTextController.cs +++ b/DNN Platform/Modules/HTML/Components/HtmlTextController.cs @@ -70,6 +70,9 @@ public HtmlTextController() /// public static string FormatHtmlText(int moduleId, string content, HtmlModuleSettings settings, PortalSettings portalSettings, Page page) { + // Html decode content + content = HttpUtility.HtmlDecode(content); + // token replace if (settings.ReplaceTokens) { @@ -83,9 +86,6 @@ public static string FormatHtmlText(int moduleId, string content, HtmlModuleSett content = tr.ReplaceEnvironmentTokens(content); } - // Html decode content - content = HttpUtility.HtmlDecode(content); - // manage relative paths content = ManageRelativePaths(content, portalSettings.HomeDirectory, "src", portalSettings.PortalId); content = ManageRelativePaths(content, portalSettings.HomeDirectory, "background", portalSettings.PortalId); From e2429fe1e6032ed83e0dc8f23784a5e96b3429ca Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Fri, 26 Feb 2021 09:00:33 -0500 Subject: [PATCH 19/53] Updates bug report as per 9.9.0 release Updates bug report as per 9.9.0 release --- .github/ISSUE_TEMPLATE/bug-report.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index a8866ca8026..f0ed13ea799 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -41,8 +41,7 @@ Provide any additional context that may be helpful in understanding and/or resol Please add X in at least one of the boxes as appropriate. In order for an issue to be accepted, a developer needs to be able to reproduce the issue on a currently supported version. If you are looking for a workaround for an issue with an older version, please visit the forums at https://dnncommunity.org/forums --> * [ ] 10.00.00 alpha build -* [ ] 09.09.00 release candidate -* [ ] 09.08.01 latest supported release +* [ ] 09.09.00 latest supported release ## Affected browser \ No newline at end of file diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Utilities/packages.config b/DNN Platform/Tests/DotNetNuke.Tests.Utilities/packages.config index 76fb243f5a6..7195fcf31e4 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Utilities/packages.config +++ b/DNN Platform/Tests/DotNetNuke.Tests.Utilities/packages.config @@ -1,8 +1,11 @@  + + + \ No newline at end of file From 18f25e4eb4f8277287b813691d47dedbb91ec102 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 26 Feb 2021 14:14:37 -0600 Subject: [PATCH 24/53] Remove object qualifier from test config --- DNN Platform/Tests/App.config | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DNN Platform/Tests/App.config b/DNN Platform/Tests/App.config index 819b7782aed..408737941cf 100644 --- a/DNN Platform/Tests/App.config +++ b/DNN Platform/Tests/App.config @@ -47,7 +47,6 @@ - @@ -254,7 +253,7 @@ - + From 539a475af8c0092e229cfdf628c89b11ac0f8c8f Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 26 Feb 2021 14:29:41 -0600 Subject: [PATCH 25/53] Adjust whitespace in project files --- .../Dnn.Modules.Console.csproj | 2 +- .../Azure/Dnn.AzureConnector.csproj | 2 +- .../Dnn.GoogleAnalyticsConnector.csproj | 2 +- .../Dnn.GoogleTagManagerConnector.csproj | 2 +- .../CountryListBox/CountryListBox.csproj | 2 +- .../Dnn.AuthServices.Jwt.csproj | 2 +- .../DotNetNuke.Instrumentation.csproj | 2 +- .../DotNetNuke.Log4Net.csproj | 2 +- .../DotNetNuke.Web.Client.csproj | 2 +- .../DotNetNuke.Web.Mvc.csproj | 2 +- .../DotNetNuke.Web.Razor.csproj | 2 +- .../DotNetNuke.WebUtility.vbproj | 2 +- .../HttpModules/DotNetNuke.HttpModules.csproj | 2 +- .../DotNetNuke.Modules.CoreMessaging.csproj | 2 +- .../DDRMenu/DotNetNuke.Modules.DDRMenu.csproj | 2 +- .../DnnExportImport/DnnExportImport.csproj | 2 +- .../DnnExportImportLibrary.csproj | 2 +- .../Groups/DotNetNuke.Modules.Groups.csproj | 2 +- ...otNetNuke.Modules.HtmlEditorManager.csproj | 2 +- .../Journal/DotNetNuke.Modules.Journal.csproj | 2 +- .../DotNetNuke.Modules.MemberDirectory.csproj | 2 +- .../DotNetNuke.Modules.RazorHost.csproj | 2 +- .../Dnn.Modules.ResourceManager.csproj | 582 +++++++++--------- .../DotNetNuke.Authentication.Facebook.csproj | 2 +- .../DotNetNuke.Authentication.Google.csproj | 2 +- ...tNetNuke.Authentication.LiveConnect.csproj | 2 +- .../DotNetNuke.Authentication.Twitter.csproj | 2 +- ...aching.SimpleWebFarmCachingProvider.csproj | 2 +- .../DotNetNuke.Providers.AspNetCCP.csproj | 2 +- ...otNetNuke.Providers.FolderProviders.csproj | 2 +- .../DNNConnect.CKEditorProvider.csproj | 2 +- .../Syndication/DotNetNuke.Syndication.csproj | 2 +- .../Website/DotNetNuke.Website.csproj | 2 +- 33 files changed, 323 insertions(+), 323 deletions(-) diff --git a/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj b/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj index 95c98bc2d82..b1804ed3691 100644 --- a/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj +++ b/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Connectors/Azure/Dnn.AzureConnector.csproj b/DNN Platform/Connectors/Azure/Dnn.AzureConnector.csproj index 7565f8c9cb4..6751dd4d5ae 100644 --- a/DNN Platform/Connectors/Azure/Dnn.AzureConnector.csproj +++ b/DNN Platform/Connectors/Azure/Dnn.AzureConnector.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Connectors/GoogleAnalytics/Dnn.GoogleAnalyticsConnector.csproj b/DNN Platform/Connectors/GoogleAnalytics/Dnn.GoogleAnalyticsConnector.csproj index 21fa00c372d..882073da5e1 100644 --- a/DNN Platform/Connectors/GoogleAnalytics/Dnn.GoogleAnalyticsConnector.csproj +++ b/DNN Platform/Connectors/GoogleAnalytics/Dnn.GoogleAnalyticsConnector.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Connectors/GoogleTagManager/Dnn.GoogleTagManagerConnector.csproj b/DNN Platform/Connectors/GoogleTagManager/Dnn.GoogleTagManagerConnector.csproj index 7eae879f455..c6aca0e3b7e 100644 --- a/DNN Platform/Connectors/GoogleTagManager/Dnn.GoogleTagManagerConnector.csproj +++ b/DNN Platform/Connectors/GoogleTagManager/Dnn.GoogleTagManagerConnector.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Controls/CountryListBox/CountryListBox.csproj b/DNN Platform/Controls/CountryListBox/CountryListBox.csproj index 728f5bab080..bfba6b31b61 100644 --- a/DNN Platform/Controls/CountryListBox/CountryListBox.csproj +++ b/DNN Platform/Controls/CountryListBox/CountryListBox.csproj @@ -1,7 +1,7 @@  - true + true 9.0.30729 diff --git a/DNN Platform/Dnn.AuthServices.Jwt/Dnn.AuthServices.Jwt.csproj b/DNN Platform/Dnn.AuthServices.Jwt/Dnn.AuthServices.Jwt.csproj index 47edf0e8e3f..331a3eea173 100644 --- a/DNN Platform/Dnn.AuthServices.Jwt/Dnn.AuthServices.Jwt.csproj +++ b/DNN Platform/Dnn.AuthServices.Jwt/Dnn.AuthServices.Jwt.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj b/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj index bb606a9f3d0..1066264806b 100644 --- a/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj +++ b/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj b/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj index 8e8c4b6bfa4..8500047afa1 100644 --- a/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj +++ b/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj @@ -21,7 +21,7 @@ --> - true + true {04F77171-0634-46E0-A95E-D7477C88712E} diff --git a/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj b/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj index 33b48665016..1f2a6fe52ff 100644 --- a/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj +++ b/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj b/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj index 4d4875e754b..89ec7d39709 100644 --- a/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj +++ b/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj b/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj index 7551766c35c..19bb5995df8 100644 --- a/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj +++ b/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj b/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj index 6f2720e74d9..5bf23761030 100644 --- a/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj +++ b/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj @@ -1,7 +1,7 @@  - true + true Local diff --git a/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj b/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj index 7ca56a4b41c..e08540e4502 100644 --- a/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj +++ b/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj @@ -1,7 +1,7 @@  - true + true 9.0.30729 diff --git a/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj b/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj index 6e966dbd890..8e23bbcf9c7 100644 --- a/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj +++ b/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/DDRMenu/DotNetNuke.Modules.DDRMenu.csproj b/DNN Platform/Modules/DDRMenu/DotNetNuke.Modules.DDRMenu.csproj index 3b2f1a875f6..129dc0c860b 100644 --- a/DNN Platform/Modules/DDRMenu/DotNetNuke.Modules.DDRMenu.csproj +++ b/DNN Platform/Modules/DDRMenu/DotNetNuke.Modules.DDRMenu.csproj @@ -2,7 +2,7 @@ - true + true 10.0 diff --git a/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj b/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj index baecef75046..6c69c0040a6 100644 --- a/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj +++ b/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/DnnExportImportLibrary/DnnExportImportLibrary.csproj b/DNN Platform/Modules/DnnExportImportLibrary/DnnExportImportLibrary.csproj index 1cd6b46387b..33424383015 100644 --- a/DNN Platform/Modules/DnnExportImportLibrary/DnnExportImportLibrary.csproj +++ b/DNN Platform/Modules/DnnExportImportLibrary/DnnExportImportLibrary.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj b/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj index 00aa28be20f..bd5aa8bfbb7 100644 --- a/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj +++ b/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj b/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj index 4e8a0f684b5..d30eaea91b5 100644 --- a/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj +++ b/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj b/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj index f7cd08a1201..20e817a9980 100644 --- a/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj +++ b/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj b/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj index 60d553ca76f..62f03eee400 100644 --- a/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj +++ b/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/RazorHost/DotNetNuke.Modules.RazorHost.csproj b/DNN Platform/Modules/RazorHost/DotNetNuke.Modules.RazorHost.csproj index ce701608b77..56000ff3e1d 100644 --- a/DNN Platform/Modules/RazorHost/DotNetNuke.Modules.RazorHost.csproj +++ b/DNN Platform/Modules/RazorHost/DotNetNuke.Modules.RazorHost.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj b/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj index 58b194a71cc..fd8de42f29b 100644 --- a/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj +++ b/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj @@ -1,292 +1,292 @@ - - - - - true - - - Debug - AnyCPU - - - 2.0 - {7D61A32C-0F21-453F-A981-BD8E5A3A5304} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Dnn.Modules.ResourceManager - Dnn.Modules.ResourceManager - v4.7.2 - false - - - - - - - - true - full - true - true - bin\ - bin\Dnn.Modules.ResourceManager.xml - 1591 - AllRules.ruleset - 7 - true - 4 - - - pdbonly - false - true - true - bin\ - bin\Dnn.Modules.ResourceManager.xml - 1591 - AllRules.ruleset - 7 - true - 4 - - - - False - ..\..\..\Packages\Microsoft.Extensions.DependencyInjection.2.1.1\lib\net461\Microsoft.Extensions.DependencyInjection.dll - - - False - ..\..\..\Packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll - - - ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - False - ..\..\..\Packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll - - - - - False - ..\..\..\Packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll - - - - - - - - - - - - - - - - - - - SolutionInfo.cs - - - - - - - - - - - - - - - - - - - - - - - EditFolderMapping.ascx - ASPXCodeBehind - - - EditFolderMapping.ascx - - - - - - - - - - - - - - - - - - - - - - - - - Settings.ascx - ASPXCodeBehind - - - Settings.ascx - - - View.ascx - ASPXCodeBehind - - - View.ascx - - - stylecop.json - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - - - - - - - Designer - - - - - {6928A9B1-F88A-4581-A132-D3EB38669BB0} - DotNetNuke.Abstractions - - - {3cd5f6b8-8360-4862-80b6-f402892db7dd} - DotNetNuke.Instrumentation - - - {c4823821-cfb3-4394-851f-e39d0974efbd} - DotNetNuke.ModulePipeline - - - {03e3afa5-ddc9-48fb-a839-ad4282ce237e} - DotNetNuke.Web.Client - - - {4912f062-f8a8-4f9d-8f8e-244ebee1acbd} - DotNetNuke.WebUtility - - - {ee1329fe-fd88-4e1a-968c-345e394ef080} - DotNetNuke.Web - - - {6b29aded-7b56-4484-bea5-c0e09079535b} - DotNetNuke.Library - - - - - - - - - - - - - - - - web.config - - - web.config - - - - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - True - - - - + + + + + true + + + Debug + AnyCPU + + + 2.0 + {7D61A32C-0F21-453F-A981-BD8E5A3A5304} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Dnn.Modules.ResourceManager + Dnn.Modules.ResourceManager + v4.7.2 + false + + + + + + + + true + full + true + true + bin\ + bin\Dnn.Modules.ResourceManager.xml + 1591 + AllRules.ruleset + 7 + true + 4 + + + pdbonly + false + true + true + bin\ + bin\Dnn.Modules.ResourceManager.xml + 1591 + AllRules.ruleset + 7 + true + 4 + + + + False + ..\..\..\Packages\Microsoft.Extensions.DependencyInjection.2.1.1\lib\net461\Microsoft.Extensions.DependencyInjection.dll + + + False + ..\..\..\Packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + False + ..\..\..\Packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + + + + + False + ..\..\..\Packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + + + + + + + + + + + + + + + + + + + SolutionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + EditFolderMapping.ascx + ASPXCodeBehind + + + EditFolderMapping.ascx + + + + + + + + + + + + + + + + + + + + + + + + + Settings.ascx + ASPXCodeBehind + + + Settings.ascx + + + View.ascx + ASPXCodeBehind + + + View.ascx + + + stylecop.json + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + + + Designer + + + + + {6928A9B1-F88A-4581-A132-D3EB38669BB0} + DotNetNuke.Abstractions + + + {3cd5f6b8-8360-4862-80b6-f402892db7dd} + DotNetNuke.Instrumentation + + + {c4823821-cfb3-4394-851f-e39d0974efbd} + DotNetNuke.ModulePipeline + + + {03e3afa5-ddc9-48fb-a839-ad4282ce237e} + DotNetNuke.Web.Client + + + {4912f062-f8a8-4f9d-8f8e-244ebee1acbd} + DotNetNuke.WebUtility + + + {ee1329fe-fd88-4e1a-968c-345e394ef080} + DotNetNuke.Web + + + {6b29aded-7b56-4484-bea5-c0e09079535b} + DotNetNuke.Library + + + + + + + + + + + + + + + + web.config + + + web.config + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + True + + + + \ No newline at end of file diff --git a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Facebook/DotNetNuke.Authentication.Facebook.csproj b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Facebook/DotNetNuke.Authentication.Facebook.csproj index 232a0b6aa7b..93b87011a43 100644 --- a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Facebook/DotNetNuke.Authentication.Facebook.csproj +++ b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Facebook/DotNetNuke.Authentication.Facebook.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Google/DotNetNuke.Authentication.Google.csproj b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Google/DotNetNuke.Authentication.Google.csproj index fa41ec771c8..cff158337da 100644 --- a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Google/DotNetNuke.Authentication.Google.csproj +++ b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Google/DotNetNuke.Authentication.Google.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.LiveConnect/DotNetNuke.Authentication.LiveConnect.csproj b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.LiveConnect/DotNetNuke.Authentication.LiveConnect.csproj index a48fb2b3ac2..afebbc241d1 100644 --- a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.LiveConnect/DotNetNuke.Authentication.LiveConnect.csproj +++ b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.LiveConnect/DotNetNuke.Authentication.LiveConnect.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Twitter/DotNetNuke.Authentication.Twitter.csproj b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Twitter/DotNetNuke.Authentication.Twitter.csproj index 3dc5f680070..92d65036ac1 100644 --- a/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Twitter/DotNetNuke.Authentication.Twitter.csproj +++ b/DNN Platform/Providers/AuthenticationProviders/DotNetNuke.Authentication.Twitter/DotNetNuke.Authentication.Twitter.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Providers/CachingProviders/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider.csproj b/DNN Platform/Providers/CachingProviders/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider.csproj index 6107c5f4f91..301135123e1 100644 --- a/DNN Platform/Providers/CachingProviders/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider.csproj +++ b/DNN Platform/Providers/CachingProviders/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider/DotNetNuke.Providers.Caching.SimpleWebFarmCachingProvider.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Providers/ClientCapabilityProviders/Provider.AspNetCCP/DotNetNuke.Providers.AspNetCCP.csproj b/DNN Platform/Providers/ClientCapabilityProviders/Provider.AspNetCCP/DotNetNuke.Providers.AspNetCCP.csproj index db52caca51b..0c03dc4ea59 100644 --- a/DNN Platform/Providers/ClientCapabilityProviders/Provider.AspNetCCP/DotNetNuke.Providers.AspNetCCP.csproj +++ b/DNN Platform/Providers/ClientCapabilityProviders/Provider.AspNetCCP/DotNetNuke.Providers.AspNetCCP.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Providers/FolderProviders/DotNetNuke.Providers.FolderProviders.csproj b/DNN Platform/Providers/FolderProviders/DotNetNuke.Providers.FolderProviders.csproj index 9368de7f08d..311dd434658 100644 --- a/DNN Platform/Providers/FolderProviders/DotNetNuke.Providers.FolderProviders.csproj +++ b/DNN Platform/Providers/FolderProviders/DotNetNuke.Providers.FolderProviders.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/DNNConnect.CKEditorProvider.csproj b/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/DNNConnect.CKEditorProvider.csproj index 1221682dddd..0e7944ff74c 100644 --- a/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/DNNConnect.CKEditorProvider.csproj +++ b/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/DNNConnect.CKEditorProvider.csproj @@ -2,7 +2,7 @@ - true + true Debug diff --git a/DNN Platform/Syndication/DotNetNuke.Syndication.csproj b/DNN Platform/Syndication/DotNetNuke.Syndication.csproj index bd491e5976d..b2a4f5b887b 100644 --- a/DNN Platform/Syndication/DotNetNuke.Syndication.csproj +++ b/DNN Platform/Syndication/DotNetNuke.Syndication.csproj @@ -1,7 +1,7 @@  - true + true Debug diff --git a/DNN Platform/Website/DotNetNuke.Website.csproj b/DNN Platform/Website/DotNetNuke.Website.csproj index b1a73978bc9..ceac22d8aa1 100644 --- a/DNN Platform/Website/DotNetNuke.Website.csproj +++ b/DNN Platform/Website/DotNetNuke.Website.csproj @@ -2,7 +2,7 @@ - true + true Debug From 19316b4a4d11631c334b2aa4fe62ff1a2dfa4210 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 26 Feb 2021 14:43:26 -0600 Subject: [PATCH 26/53] Clean up UrlRewriteTests --- .../DotNetNuke.Tests.Urls/UrlRewriteTests.cs | 1355 ++++++++--------- 1 file changed, 676 insertions(+), 679 deletions(-) diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs b/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs index 4113fcb8fa5..d5f4e7b0d1e 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs +++ b/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs @@ -1,683 +1,680 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information +namespace DotNetNuke.Tests.Urls +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Globalization; + using System.Web; -namespace DotNetNuke.Tests.Urls -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Collections.Specialized; - using System.Globalization; - using System.Web; - - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.Data; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Entities.Tabs; - using DotNetNuke.Entities.Urls; - using DotNetNuke.Entities.Users; - using DotNetNuke.HttpModules.UrlRewrite; - using DotNetNuke.Services.Localization; - using DotNetNuke.Tests.Utilities; - using NUnit.Framework; - - [TestFixture] - public class UrlRewriteTests : UrlTestBase - { - private const string _defaultPage = Globals.glbDefaultPage; - private const string _testPage = "Test Page"; - private const string _aboutUsPageName = "About Us"; - private int _tabId; - private string _redirectMode; - private Locale _customLocale; - private string _securePageName; - private PortalAliasInfo _primaryAlias; - private bool _sslEnforced; - private bool _sslEnabled; - - public UrlRewriteTests() - : base(0) - { - } - - [SetUp] - public override void SetUp() - { - base.SetUp(); - - this.DeleteTab(_testPage); - this.CreateTab(_testPage); - this.UpdateTabName(this._tabId, "About Us"); - this.UpdateTabSkin(this._tabId, string.Empty); - CacheController.FlushPageIndexFromCache(); - this.GetDefaultAlias(); - this._redirectMode = PortalController.GetPortalSetting("PortalAliasMapping", this.PortalId, "CANONICALURL"); - this._sslEnforced = PortalController.GetPortalSettingAsBoolean("SSLEnforced", this.PortalId, false); - this._sslEnabled = PortalController.GetPortalSettingAsBoolean("SSLEnabled", this.PortalId, false); - this._primaryAlias = null; - this._customLocale = null; - DataCache.ClearCache(); - } - - [TearDown] - public override void TearDown() - { - base.TearDown(); - - this.DeleteTab(_testPage); - this.UpdateTabName(this._tabId, "About Us"); - this.UpdateTabSkin(this._tabId, "[G]Skins/Xcillion/Inner.ascx"); - - if (!string.IsNullOrEmpty(this._securePageName)) - { - var tab = TabController.Instance.GetTabByName(this._securePageName, this.PortalId); - if (tab != null) - { - tab.IsSecure = false; - - this.UpdateTab(tab); - } - } - - if (this._customLocale != null) - { - Localization.RemoveLanguageFromPortals(this._customLocale.LanguageId, true); - Localization.DeleteLanguage(this._customLocale, true); - } - - if (this._primaryAlias != null) - { - PortalAliasController.Instance.DeletePortalAlias(this._primaryAlias); - } - - this.SetDefaultAlias(this.DefaultAlias); - PortalController.UpdatePortalSetting(this.PortalId, "PortalAliasMapping", this._redirectMode, true, "en-us"); - PortalController.UpdatePortalSetting(this.PortalId, "SSLEnforced", this._sslEnforced.ToString(), true, "en-us"); - PortalController.UpdatePortalSetting(this.PortalId, "SSLEnabled", this._sslEnabled.ToString(), true, "en-us"); - - foreach (var tabUrl in CBO.FillCollection(DataProvider.Instance().GetTabUrls(this.PortalId))) - { - TabController.Instance.DeleteTabUrl(tabUrl, this.PortalId, true); - } - } - - [TestFixtureSetUp] - public override void TestFixtureSetUp() - { - base.TestFixtureSetUp(); - - var tab = TabController.Instance.GetTabByName(_aboutUsPageName, this.PortalId); - if (tab == null) - { - this.CreateTab(_aboutUsPageName); - tab = TabController.Instance.GetTabByName(_aboutUsPageName, this.PortalId); - } - - this._tabId = tab.TabID; - - // Add Portal Aliases - var aliasController = PortalAliasController.Instance; - TestUtil.ReadStream(string.Format("{0}", "Aliases"), (line, header) => - { - string[] fields = line.Split(','); - var alias = aliasController.GetPortalAlias(fields[0], this.PortalId); - if (alias == null) - { - alias = new PortalAliasInfo - { - HTTPAlias = fields[0], - PortalID = this.PortalId, - }; - PortalAliasController.Instance.AddPortalAlias(alias); - } - }); - TestUtil.ReadStream(string.Format("{0}", "Users"), (line, header) => - { - string[] fields = line.Split(','); - - TestUtil.AddUser(this.PortalId, fields[0].Trim(), fields[1].Trim(), fields[2].Trim()); - }); - } - - [TestFixtureTearDown] - public override void TestFixtureTearDown() - { - base.TestFixtureTearDown(); - - var aliasController = PortalAliasController.Instance; - TestUtil.ReadStream(string.Format("{0}", "Aliases"), (line, header) => - { - string[] fields = line.Split(','); - var alias = aliasController.GetPortalAlias(fields[0], this.PortalId); - PortalAliasController.Instance.DeletePortalAlias(alias); - }); - TestUtil.ReadStream(string.Format("{0}", "Users"), (line, header) => - { - string[] fields = line.Split(','); - - TestUtil.DeleteUser(this.PortalId, fields[0]); - }); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_BasicTestCases")] - public void AdvancedUrlRewriter_BasicTest(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_DeletedTabHandlingTestCases")] - public void AdvancedUrlRewriter_DeletedTabHandling(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - var tab = TabController.Instance.GetTabByName(_testPage, this.PortalId); - if (Convert.ToBoolean(testFields["HardDeleted"])) - { - this.DeleteTab(_testPage); - CacheController.FlushPageIndexFromCache(); - } - else - { - tab.IsDeleted = Convert.ToBoolean(testFields["SoftDeleted"]); - tab.DisableLink = Convert.ToBoolean(testFields["Disabled"]); - if (Convert.ToBoolean(testFields["Expired"])) - { - tab.EndDate = DateTime.Now - TimeSpan.FromDays(1); - } - - this.UpdateTab(tab); - CacheController.FlushPageIndexFromCache(); - } - - string deletedTabHandling = testFields.GetValue("DeletedTabHandling"); - - if (!string.IsNullOrEmpty(deletedTabHandling)) - { - switch (deletedTabHandling) - { - case "Do404Error": - settings.DeletedTabHandlingType = DeletedTabHandlingType.Do404Error; - break; - default: - settings.DeletedTabHandlingType = DeletedTabHandlingType.Do301RedirectToPortalHome; - break; - } - } - - this.SetDefaultAlias(testFields); - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_DoNotRedirect")] - public void AdvancedUrlRewriter_DoNotRedirect(Dictionary testFields) - { - var tabName = testFields["Page Name"]; - var doNotRedirect = testFields["DoNotRedirect"]; - - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - this.UpdateTabSetting(tabName, "DoNotRedirect", doNotRedirect); - settings.UseBaseFriendlyUrls = testFields["UseBaseFriendlyUrls"]; - - this.ExecuteTest(settings, testFields, true); - - this.UpdateTabSetting(tabName, "DoNotRedirect", "False"); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_ForwardExternalUrlTestCases")] - public void AdvancedUrlRewriter_ForwardExternalUrls(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - var tab = TabController.Instance.GetTabByName(_testPage, this.PortalId); - tab.Url = testFields["ExternalUrl"]; - TabController.Instance.UpdateTab(tab); - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_ForceLowerCaseTestCases")] - public void AdvancedUrlRewriter_ForceLowerCase(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - string forceLowerCaseRegex = testFields.GetValue("ForceLowerCaseRegex"); - - if (!string.IsNullOrEmpty(forceLowerCaseRegex)) - { - settings.ForceLowerCaseRegex = forceLowerCaseRegex; - } - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_RegexTestCases")] - public void AdvancedUrlRewriter_Regex(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - string regexSetting = testFields["Setting"]; - string regexValue = testFields["Value"]; - if (!string.IsNullOrEmpty(regexValue)) - { - switch (regexSetting) - { - case "IgnoreRegex": - settings.IgnoreRegex = regexValue; - break; - case "DoNotRewriteRegex": - settings.DoNotRewriteRegex = regexValue; - break; - case "UseSiteUrlsRegex": - settings.UseSiteUrlsRegex = regexValue; - break; - case "DoNotRedirectRegex": - settings.DoNotRedirectRegex = regexValue; - break; - case "DoNotRedirectSecureRegex": - settings.DoNotRedirectSecureRegex = regexValue; - break; - case "ForceLowerCaseRegex": - settings.ForceLowerCaseRegex = regexValue; - break; - case "NoFriendlyUrlRegex": - settings.NoFriendlyUrlRegex = regexValue; - break; - case "DoNotIncludeInPathRegex": - settings.DoNotIncludeInPathRegex = regexValue; - break; - case "ValidExtensionlessUrlsRegex": - settings.ValidExtensionlessUrlsRegex = regexValue; - break; - case "RegexMatch": - settings.RegexMatch = regexValue; - break; - } - } - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_ReplaceCharsTestCases")] - public void AdvancedUrlRewriter_ReplaceChars(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - string testPageName = testFields.GetValue("TestPageName"); - TabInfo tab = null; - if (!string.IsNullOrEmpty(testPageName)) - { - var tabName = testFields["Page Name"]; - tab = TabController.Instance.GetTabByName(tabName, this.PortalId); - tab.TabName = testPageName; - TabController.Instance.UpdateTab(tab); - - // Refetch tab from DB - tab = TabController.Instance.GetTab(tab.TabID, tab.PortalID, false); - } - - string autoAscii = testFields.GetValue("AutoAscii"); - - if (!string.IsNullOrEmpty(autoAscii)) - { - settings.AutoAsciiConvert = Convert.ToBoolean(autoAscii); - } - - TestUtil.GetReplaceCharDictionary(testFields, settings.ReplaceCharacterDictionary); - - this.SetDefaultAlias(testFields); - - this.ExecuteTestForTab(tab, settings, testFields); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_ReplaceSpaceTestCases")] - public void AdvancedUrlRewriter_ReplaceSpace(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - string replaceSpaceWith = testFields.GetValue("ReplaceSpaceWith"); - if (!string.IsNullOrEmpty(replaceSpaceWith)) - { - settings.ReplaceSpaceWith = replaceSpaceWith; - } - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_SiteRootRedirectTestCases")] - public void AdvancedUrlRewriter_SiteRootRedirect(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", "SiteRootRedirect", this.PortalId); - - string scheme = testFields["Scheme"]; - - this.ExecuteTest(settings, testFields, true); - if (testFields["TestName"].Contains("Resubmit")) - { - var httpAlias = testFields["Alias"]; - settings.DoNotRedirectRegex = scheme + httpAlias; - - this.ExecuteTest(settings, testFields, true); - } - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_PrimaryPortalAliasTestCases")] - public void AdvancedUrlRewriter_0_PrimaryPortalAlias(Dictionary testFields) - { - string defaultAlias = testFields["DefaultAlias"]; - - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - - string language = testFields["Language"].Trim(); - string skin = testFields["Skin"].Trim(); - if (!string.IsNullOrEmpty(language)) - { - this._customLocale = new Locale { Code = language, Fallback = "en-US" }; - this._customLocale.Text = CultureInfo.GetCultureInfo(this._customLocale.Code).NativeName; - Localization.SaveLanguage(this._customLocale); - Localization.AddLanguageToPortals(this._customLocale.LanguageId); - } - - if (testFields.ContainsKey("Final Url")) - { - testFields["Final Url"] = testFields["Final Url"].Replace("{useAlias}", defaultAlias); - } - - PortalController.UpdatePortalSetting(this.PortalId, "PortalAliasMapping", "REDIRECT", true, "en-us"); - var alias = PortalAliasController.Instance.GetPortalAlias(defaultAlias, this.PortalId); - if (alias == null) - { - alias = new PortalAliasInfo - { - HTTPAlias = defaultAlias, - PortalID = this.PortalId, - IsPrimary = true, - }; - if (!(string.IsNullOrEmpty(language) && string.IsNullOrEmpty(skin))) - { - alias.CultureCode = language; - alias.Skin = skin; - } - - PortalAliasController.Instance.AddPortalAlias(alias); - } - - this.SetDefaultAlias(defaultAlias); - this.ExecuteTest(settings, testFields, false); - - alias = PortalAliasController.Instance.GetPortalAlias(defaultAlias, this.PortalId); - if (alias != null) - { - PortalAliasController.Instance.DeletePortalAlias(alias); - } - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_VanityUrlTestCases")] - public void AdvancedUrlRewriter_VanityUrl(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - settings.DeletedTabHandlingType = DeletedTabHandlingType.Do301RedirectToPortalHome; - - var vanityUrl = testFields.GetValue("VanityUrl", string.Empty); - var userName = testFields.GetValue("UserName", string.Empty); - var redirectOld = testFields.GetValue("RedirectOldProfileUrl", string.Empty); - - if (!string.IsNullOrEmpty(userName)) - { - var user = UserController.GetUserByName(this.PortalId, userName); - if (user != null) - { - user.VanityUrl = vanityUrl; - UserController.UpdateUser(this.PortalId, user); - } - } - - if (!string.IsNullOrEmpty(redirectOld)) - { - settings.RedirectOldProfileUrl = Convert.ToBoolean(redirectOld); - } - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_SecureRedirectTestCases")] - public void AdvancedUrlRewriter_SecureRedirect(Dictionary testFields) - { - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); - var isClient = Convert.ToBoolean(testFields["Client"]); - - this._securePageName = testFields["Page Name"].Trim(); - - PortalController.UpdatePortalSetting(this.PortalId, "SSLEnforced", testFields["Enforced"].Trim(), true, "en-us"); - PortalController.UpdatePortalSetting(this.PortalId, "SSLEnabled", testFields["Enabled"].Trim(), true, "en-us"); - - var isSecure = Convert.ToBoolean(testFields["IsSecure"].Trim()); - - if (isSecure) - { - var tab = TabController.Instance.GetTabByName(this._securePageName, this.PortalId); - tab.IsSecure = true; - - this.UpdateTab(tab); - } - - settings.SSLClientRedirect = isClient; - - this.ExecuteTest(settings, testFields, true); - } - - [Test] - [TestCaseSource(typeof(UrlTestFactoryClass), "UrlRewrite_JiraTests")] - public void AdvancedUrlRewriter_JiraTests(Dictionary testFields) - { - var testName = testFields.GetValue("Test File", string.Empty); - - var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", "Jira_Tests", testName + ".csv", this.PortalId); - var dictionary = UrlTestFactoryClass.GetDictionary("UrlRewrite", "Jira_Tests", testName + "_dic.csv"); - - int homeTabId = -1; - foreach (var keyValuePair in dictionary) - { - switch (keyValuePair.Key) - { - case "HomeTabId": - homeTabId = this.UpdateHomeTab(int.Parse(keyValuePair.Value)); - break; - default: - break; - } - } - - this.ExecuteTest(settings, testFields, true); - - if (homeTabId != -1) - { - this.UpdateHomeTab(homeTabId); - } - } - - private void CreateSimulatedRequest(Uri url) - { - var simulator = new Instance.Utilities.HttpSimulator.HttpSimulator("/", this.WebsitePhysicalAppPath); - simulator.SimulateRequest(url); - - var browserCaps = new HttpBrowserCapabilities { Capabilities = new Hashtable() }; - HttpContext.Current.Request.Browser = browserCaps; - } - - private void ProcessRequest(FriendlyUrlSettings settings, UrlTestHelper testHelper) - { - var provider = new AdvancedUrlRewriter(); - - provider.ProcessTestRequestWithContext( - HttpContext.Current, - HttpContext.Current.Request.Url, - true, - testHelper.Result, - settings); - testHelper.Response = HttpContext.Current.Response; - } - - private string ReplaceTokens(Dictionary testFields, string url, string tabId) - { - var defaultAlias = testFields.GetValue("DefaultAlias", string.Empty); - var httpAlias = testFields.GetValue("Alias", string.Empty); - var tabName = testFields["Page Name"]; - var vanityUrl = testFields.GetValue("VanityUrl", string.Empty); - var homeTabId = testFields.GetValue("HomeTabId", string.Empty); - - var userName = testFields.GetValue("UserName", string.Empty); - string userId = string.Empty; - if (!string.IsNullOrEmpty(userName)) - { - var user = UserController.GetUserByName(this.PortalId, userName); - if (user != null) - { - userId = user.UserID.ToString(); - } - } - - return url.Replace("{alias}", httpAlias) - .Replace("{usealias}", defaultAlias) - .Replace("{tabName}", tabName) - .Replace("{tabId}", tabId) - .Replace("{portalId}", this.PortalId.ToString()) - .Replace("{vanityUrl}", vanityUrl) - .Replace("{userId}", userId) - .Replace("{defaultPage}", _defaultPage); - } - - private void DeleteTab(string tabName) - { - var tab = TabController.Instance.GetTabByName(tabName, this.PortalId); - - if (tab != null) - { - TabController.Instance.DeleteTab(tab.TabID, this.PortalId); - } - } - - private void ExecuteTestForTab(TabInfo tab, FriendlyUrlSettings settings, Dictionary testFields) - { - var httpAlias = testFields.GetValue("Alias", string.Empty); - var scheme = testFields["Scheme"]; - var url = testFields["Test Url"]; - var result = testFields["Expected Url"]; - var expectedStatus = int.Parse(testFields["Status"]); - var redirectUrl = testFields.GetValue("Final Url"); - var redirectReason = testFields.GetValue("RedirectReason"); - - var tabID = (tab == null) ? "-1" : tab.TabID.ToString(); - - var expectedResult = this.ReplaceTokens(testFields, result, tabID); - var testurl = this.ReplaceTokens(testFields, url, tabID); - var expectedRedirectUrl = this.ReplaceTokens(testFields, redirectUrl, tabID); - - this.CreateSimulatedRequest(new Uri(testurl)); - - var request = HttpContext.Current.Request; - var testHelper = new UrlTestHelper - { - HttpAliasFull = scheme + httpAlias + "/", - Result = new UrlAction(request) - { - IsSecureConnection = request.IsSecureConnection, - RawUrl = request.RawUrl, - }, - RequestUri = new Uri(testurl), - QueryStringCol = new NameValueCollection(), - }; - - this.ProcessRequest(settings, testHelper); - - // Test expected response status - Assert.AreEqual(expectedStatus, testHelper.Response.StatusCode); - - switch (expectedStatus) - { - case 200: - // Test expected rewrite path - if (!string.IsNullOrEmpty(expectedResult)) - { - Assert.AreEqual(expectedResult, testHelper.Result.RewritePath.TrimStart('/')); - } - - break; - case 301: - case 302: - // Test for final Url if redirected - Assert.IsTrue(expectedRedirectUrl.Equals(testHelper.Result.FinalUrl.TrimStart('/'), StringComparison.InvariantCultureIgnoreCase)); - Assert.AreEqual(redirectReason, testHelper.Result.Reason.ToString(), "Redirect reason incorrect"); - break; - } - } - - private void ExecuteTest(FriendlyUrlSettings settings, Dictionary testFields, bool setDefaultAlias) - { - var tabName = testFields["Page Name"]; - var tab = TabController.Instance.GetTabByName(tabName, this.PortalId); - - if (setDefaultAlias) - { - this.SetDefaultAlias(testFields); - } - - this.ExecuteTestForTab(tab, settings, testFields); - } - - private void UpdateTab(TabInfo tab) - { - if (tab != null) - { - TabController.Instance.UpdateTab(tab); - } - } - - private void UpdateTabName(int tabId, string newName) - { - var tab = TabController.Instance.GetTab(tabId, this.PortalId, false); - tab.TabName = newName; - TabController.Instance.UpdateTab(tab); - } - - private void UpdateTabSkin(int tabId, string newSkin) - { - var tab = TabController.Instance.GetTab(tabId, this.PortalId, false); - tab.SkinSrc = newSkin; - TabController.Instance.UpdateTab(tab); - } - - private int UpdateHomeTab(int homeTabId) - { - var portalInfo = PortalController.Instance.GetPortal(this.PortalId); - int oldHomeTabId = portalInfo.HomeTabId; - portalInfo.HomeTabId = homeTabId; - - return oldHomeTabId; - } - - private void UpdateTabSetting(string tabName, string settingName, string settingValue) - { - var tab = TabController.Instance.GetTabByName(tabName, this.PortalId); - tab.TabSettings[settingName] = settingValue; - TabController.Instance.UpdateTab(tab); - } - } -} + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Data; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Entities.Urls; + using DotNetNuke.Entities.Users; + using DotNetNuke.Services.Localization; + using NUnit.Framework; + + [TestFixture] + public class UrlRewriteTests : UrlTestBase + { + private const string DefaultPage = Globals.glbDefaultPage; + private const string TestPage = "Test Page"; + private const string AboutUsPageName = "About Us"; + private int tabId; + private string redirectMode; + private Locale customLocale; + private string securePageName; + private PortalAliasInfo primaryAlias; + private bool sslEnforced; + private bool sslEnabled; + + public UrlRewriteTests() + : base(0) + { + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + this.DeleteTab(TestPage); + this.CreateTab(TestPage); + this.UpdateTabName(this.tabId, "About Us"); + this.UpdateTabSkin(this.tabId, string.Empty); + CacheController.FlushPageIndexFromCache(); + this.GetDefaultAlias(); + this.redirectMode = PortalController.GetPortalSetting("PortalAliasMapping", this.PortalId, "CANONICALURL"); + this.sslEnforced = PortalController.GetPortalSettingAsBoolean("SSLEnforced", this.PortalId, false); + this.sslEnabled = PortalController.GetPortalSettingAsBoolean("SSLEnabled", this.PortalId, false); + this.primaryAlias = null; + this.customLocale = null; + DataCache.ClearCache(); + } + + [TearDown] + public override void TearDown() + { + base.TearDown(); + + this.DeleteTab(TestPage); + this.UpdateTabName(this.tabId, "About Us"); + this.UpdateTabSkin(this.tabId, "[G]Skins/Xcillion/Inner.ascx"); + + if (!string.IsNullOrEmpty(this.securePageName)) + { + var tab = TabController.Instance.GetTabByName(this.securePageName, this.PortalId); + if (tab != null) + { + tab.IsSecure = false; + + this.UpdateTab(tab); + } + } + + if (this.customLocale != null) + { + Localization.RemoveLanguageFromPortals(this.customLocale.LanguageId, true); + Localization.DeleteLanguage(this.customLocale, true); + } + + if (this.primaryAlias != null) + { + PortalAliasController.Instance.DeletePortalAlias(this.primaryAlias); + } + + this.SetDefaultAlias(this.DefaultAlias); + PortalController.UpdatePortalSetting(this.PortalId, "PortalAliasMapping", this.redirectMode, true, "en-us"); + PortalController.UpdatePortalSetting(this.PortalId, "SSLEnforced", this.sslEnforced.ToString(), true, "en-us"); + PortalController.UpdatePortalSetting(this.PortalId, "SSLEnabled", this.sslEnabled.ToString(), true, "en-us"); + + foreach (var tabUrl in CBO.FillCollection(DataProvider.Instance().GetTabUrls(this.PortalId))) + { + TabController.Instance.DeleteTabUrl(tabUrl, this.PortalId, true); + } + } + + [TestFixtureSetUp] + public override void TestFixtureSetUp() + { + base.TestFixtureSetUp(); + + var tab = TabController.Instance.GetTabByName(AboutUsPageName, this.PortalId); + if (tab == null) + { + this.CreateTab(AboutUsPageName); + tab = TabController.Instance.GetTabByName(AboutUsPageName, this.PortalId); + } + + this.tabId = tab.TabID; + + // Add Portal Aliases + var aliasController = PortalAliasController.Instance; + TestUtil.ReadStream("Aliases", (line, header) => + { + var fields = line.Split(','); + var alias = aliasController.GetPortalAlias(fields[0], this.PortalId); + if (alias == null) + { + alias = new PortalAliasInfo + { + HTTPAlias = fields[0], + PortalID = this.PortalId, + }; + PortalAliasController.Instance.AddPortalAlias(alias); + } + }); + TestUtil.ReadStream("Users", (line, header) => + { + var fields = line.Split(','); + + TestUtil.AddUser(this.PortalId, fields[0].Trim(), fields[1].Trim(), fields[2].Trim()); + }); + } + + [TestFixtureTearDown] + public override void TestFixtureTearDown() + { + base.TestFixtureTearDown(); + + var aliasController = PortalAliasController.Instance; + TestUtil.ReadStream("Aliases", (line, header) => + { + var fields = line.Split(','); + var alias = aliasController.GetPortalAlias(fields[0], this.PortalId); + PortalAliasController.Instance.DeletePortalAlias(alias); + }); + TestUtil.ReadStream("Users", (line, header) => + { + var fields = line.Split(','); + + TestUtil.DeleteUser(this.PortalId, fields[0]); + }); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_BasicTestCases))] + public void AdvancedUrlRewriter_BasicTest(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_DeletedTabHandlingTestCases))] + public void AdvancedUrlRewriter_DeletedTabHandling(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var tab = TabController.Instance.GetTabByName(TestPage, this.PortalId); + if (Convert.ToBoolean(testFields["HardDeleted"])) + { + this.DeleteTab(TestPage); + CacheController.FlushPageIndexFromCache(); + } + else + { + tab.IsDeleted = Convert.ToBoolean(testFields["SoftDeleted"]); + tab.DisableLink = Convert.ToBoolean(testFields["Disabled"]); + if (Convert.ToBoolean(testFields["Expired"])) + { + tab.EndDate = DateTime.Now - TimeSpan.FromDays(1); + } + + this.UpdateTab(tab); + CacheController.FlushPageIndexFromCache(); + } + + var deletedTabHandling = testFields.GetValue("DeletedTabHandling"); + + if (!string.IsNullOrEmpty(deletedTabHandling)) + { + switch (deletedTabHandling) + { + case "Do404Error": + settings.DeletedTabHandlingType = DeletedTabHandlingType.Do404Error; + break; + default: + settings.DeletedTabHandlingType = DeletedTabHandlingType.Do301RedirectToPortalHome; + break; + } + } + + this.SetDefaultAlias(testFields); + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_DoNotRedirect))] + public void AdvancedUrlRewriter_DoNotRedirect(Dictionary testFields) + { + var tabName = testFields["Page Name"]; + var doNotRedirect = testFields["DoNotRedirect"]; + + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + this.UpdateTabSetting(tabName, "DoNotRedirect", doNotRedirect); + settings.UseBaseFriendlyUrls = testFields["UseBaseFriendlyUrls"]; + + this.ExecuteTest(settings, testFields, true); + + this.UpdateTabSetting(tabName, "DoNotRedirect", "False"); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_ForwardExternalUrlTestCases))] + public void AdvancedUrlRewriter_ForwardExternalUrls(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var tab = TabController.Instance.GetTabByName(TestPage, this.PortalId); + tab.Url = testFields["ExternalUrl"]; + TabController.Instance.UpdateTab(tab); + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_ForceLowerCaseTestCases))] + public void AdvancedUrlRewriter_ForceLowerCase(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var forceLowerCaseRegex = testFields.GetValue("ForceLowerCaseRegex"); + + if (!string.IsNullOrEmpty(forceLowerCaseRegex)) + { + settings.ForceLowerCaseRegex = forceLowerCaseRegex; + } + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_RegexTestCases))] + public void AdvancedUrlRewriter_Regex(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var regexSetting = testFields["Setting"]; + var regexValue = testFields["Value"]; + if (!string.IsNullOrEmpty(regexValue)) + { + switch (regexSetting) + { + case "IgnoreRegex": + settings.IgnoreRegex = regexValue; + break; + case "DoNotRewriteRegex": + settings.DoNotRewriteRegex = regexValue; + break; + case "UseSiteUrlsRegex": + settings.UseSiteUrlsRegex = regexValue; + break; + case "DoNotRedirectRegex": + settings.DoNotRedirectRegex = regexValue; + break; + case "DoNotRedirectSecureRegex": + settings.DoNotRedirectSecureRegex = regexValue; + break; + case "ForceLowerCaseRegex": + settings.ForceLowerCaseRegex = regexValue; + break; + case "NoFriendlyUrlRegex": + settings.NoFriendlyUrlRegex = regexValue; + break; + case "DoNotIncludeInPathRegex": + settings.DoNotIncludeInPathRegex = regexValue; + break; + case "ValidExtensionlessUrlsRegex": + settings.ValidExtensionlessUrlsRegex = regexValue; + break; + case "RegexMatch": + settings.RegexMatch = regexValue; + break; + } + } + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_ReplaceCharsTestCases))] + public void AdvancedUrlRewriter_ReplaceChars(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var testPageName = testFields.GetValue("TestPageName"); + TabInfo tab = null; + if (!string.IsNullOrEmpty(testPageName)) + { + var tabName = testFields["Page Name"]; + tab = TabController.Instance.GetTabByName(tabName, this.PortalId); + tab.TabName = testPageName; + TabController.Instance.UpdateTab(tab); + + // Refetch tab from DB + tab = TabController.Instance.GetTab(tab.TabID, tab.PortalID, false); + } + + var autoAscii = testFields.GetValue("AutoAscii"); + + if (!string.IsNullOrEmpty(autoAscii)) + { + settings.AutoAsciiConvert = Convert.ToBoolean(autoAscii); + } + + TestUtil.GetReplaceCharDictionary(testFields, settings.ReplaceCharacterDictionary); + + this.SetDefaultAlias(testFields); + + this.ExecuteTestForTab(tab, settings, testFields); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_ReplaceSpaceTestCases))] + public void AdvancedUrlRewriter_ReplaceSpace(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var replaceSpaceWith = testFields.GetValue("ReplaceSpaceWith"); + if (!string.IsNullOrEmpty(replaceSpaceWith)) + { + settings.ReplaceSpaceWith = replaceSpaceWith; + } + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_SiteRootRedirectTestCases))] + public void AdvancedUrlRewriter_SiteRootRedirect(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", "SiteRootRedirect", this.PortalId); + + var scheme = testFields["Scheme"]; + + this.ExecuteTest(settings, testFields, true); + if (testFields["TestName"].Contains("Resubmit")) + { + var httpAlias = testFields["Alias"]; + settings.DoNotRedirectRegex = scheme + httpAlias; + + this.ExecuteTest(settings, testFields, true); + } + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_PrimaryPortalAliasTestCases))] + public void AdvancedUrlRewriter_0_PrimaryPortalAlias(Dictionary testFields) + { + var defaultAlias = testFields["DefaultAlias"]; + + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + + var language = testFields["Language"].Trim(); + var skin = testFields["Skin"].Trim(); + if (!string.IsNullOrEmpty(language)) + { + this.customLocale = new Locale { Code = language, Fallback = "en-US" }; + this.customLocale.Text = CultureInfo.GetCultureInfo(this.customLocale.Code).NativeName; + Localization.SaveLanguage(this.customLocale); + Localization.AddLanguageToPortals(this.customLocale.LanguageId); + } + + if (testFields.ContainsKey("Final Url")) + { + testFields["Final Url"] = testFields["Final Url"].Replace("{useAlias}", defaultAlias); + } + + PortalController.UpdatePortalSetting(this.PortalId, "PortalAliasMapping", "REDIRECT", true, "en-us"); + var alias = PortalAliasController.Instance.GetPortalAlias(defaultAlias, this.PortalId); + if (alias == null) + { + alias = new PortalAliasInfo + { + HTTPAlias = defaultAlias, + PortalID = this.PortalId, + IsPrimary = true, + }; + if (!(string.IsNullOrEmpty(language) && string.IsNullOrEmpty(skin))) + { + alias.CultureCode = language; + alias.Skin = skin; + } + + PortalAliasController.Instance.AddPortalAlias(alias); + } + + this.SetDefaultAlias(defaultAlias); + this.ExecuteTest(settings, testFields, false); + + alias = PortalAliasController.Instance.GetPortalAlias(defaultAlias, this.PortalId); + if (alias != null) + { + PortalAliasController.Instance.DeletePortalAlias(alias); + } + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_VanityUrlTestCases))] + public void AdvancedUrlRewriter_VanityUrl(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + settings.DeletedTabHandlingType = DeletedTabHandlingType.Do301RedirectToPortalHome; + + var vanityUrl = testFields.GetValue("VanityUrl", string.Empty); + var userName = testFields.GetValue("UserName", string.Empty); + var redirectOld = testFields.GetValue("RedirectOldProfileUrl", string.Empty); + + if (!string.IsNullOrEmpty(userName)) + { + var user = UserController.GetUserByName(this.PortalId, userName); + if (user != null) + { + user.VanityUrl = vanityUrl; + UserController.UpdateUser(this.PortalId, user); + } + } + + if (!string.IsNullOrEmpty(redirectOld)) + { + settings.RedirectOldProfileUrl = Convert.ToBoolean(redirectOld); + } + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_SecureRedirectTestCases))] + public void AdvancedUrlRewriter_SecureRedirect(Dictionary testFields) + { + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", testFields["TestName"], this.PortalId); + var isClient = Convert.ToBoolean(testFields["Client"]); + + this.securePageName = testFields["Page Name"].Trim(); + + PortalController.UpdatePortalSetting(this.PortalId, "SSLEnforced", testFields["Enforced"].Trim(), true, "en-us"); + PortalController.UpdatePortalSetting(this.PortalId, "SSLEnabled", testFields["Enabled"].Trim(), true, "en-us"); + + var isSecure = Convert.ToBoolean(testFields["IsSecure"].Trim()); + + if (isSecure) + { + var tab = TabController.Instance.GetTabByName(this.securePageName, this.PortalId); + tab.IsSecure = true; + + this.UpdateTab(tab); + } + + settings.SSLClientRedirect = isClient; + + this.ExecuteTest(settings, testFields, true); + } + + [Test] + [TestCaseSource(typeof(UrlTestFactoryClass), nameof(UrlTestFactoryClass.UrlRewrite_JiraTests))] + public void AdvancedUrlRewriter_JiraTests(Dictionary testFields) + { + var testName = testFields.GetValue("Test File", string.Empty); + + var settings = UrlTestFactoryClass.GetSettings("UrlRewrite", "Jira_Tests", testName + ".csv", this.PortalId); + var dictionary = UrlTestFactoryClass.GetDictionary("UrlRewrite", "Jira_Tests", testName + "_dic.csv"); + + var homeTabId = -1; + foreach (var keyValuePair in dictionary) + { + switch (keyValuePair.Key) + { + case "HomeTabId": + homeTabId = this.UpdateHomeTab(int.Parse(keyValuePair.Value)); + break; + default: + break; + } + } + + this.ExecuteTest(settings, testFields, true); + + if (homeTabId != -1) + { + this.UpdateHomeTab(homeTabId); + } + } + + private void CreateSimulatedRequest(Uri url) + { + var simulator = new Instance.Utilities.HttpSimulator.HttpSimulator("/", this.WebsitePhysicalAppPath); + simulator.SimulateRequest(url); + + var browserCaps = new HttpBrowserCapabilities { Capabilities = new Hashtable() }; + HttpContext.Current.Request.Browser = browserCaps; + } + + private void ProcessRequest(FriendlyUrlSettings settings, UrlTestHelper testHelper) + { + var provider = new AdvancedUrlRewriter(); + + provider.ProcessTestRequestWithContext( + HttpContext.Current, + HttpContext.Current.Request.Url, + true, + testHelper.Result, + settings); + testHelper.Response = HttpContext.Current.Response; + } + + private string ReplaceTokens(Dictionary testFields, string url, string theTabId) + { + var defaultAlias = testFields.GetValue("DefaultAlias", string.Empty); + var httpAlias = testFields.GetValue("Alias", string.Empty); + var tabName = testFields["Page Name"]; + var vanityUrl = testFields.GetValue("VanityUrl", string.Empty); + var homeTabId = testFields.GetValue("HomeTabId", string.Empty); + + var userName = testFields.GetValue("UserName", string.Empty); + var userId = string.Empty; + if (!string.IsNullOrEmpty(userName)) + { + var user = UserController.GetUserByName(this.PortalId, userName); + if (user != null) + { + userId = user.UserID.ToString(); + } + } + + return url.Replace("{alias}", httpAlias) + .Replace("{usealias}", defaultAlias) + .Replace("{tabName}", tabName) + .Replace("{tabId}", theTabId) + .Replace("{portalId}", this.PortalId.ToString()) + .Replace("{vanityUrl}", vanityUrl) + .Replace("{userId}", userId) + .Replace("{defaultPage}", DefaultPage); + } + + private void DeleteTab(string tabName) + { + var tab = TabController.Instance.GetTabByName(tabName, this.PortalId); + + if (tab != null) + { + TabController.Instance.DeleteTab(tab.TabID, this.PortalId); + } + } + + private void ExecuteTestForTab(TabInfo tab, FriendlyUrlSettings settings, Dictionary testFields) + { + var httpAlias = testFields.GetValue("Alias", string.Empty); + var scheme = testFields["Scheme"]; + var url = testFields["Test Url"]; + var result = testFields["Expected Url"]; + var expectedStatus = int.Parse(testFields["Status"]); + var redirectUrl = testFields.GetValue("Final Url"); + var redirectReason = testFields.GetValue("RedirectReason"); + + var theTabId = (tab == null) ? "-1" : tab.TabID.ToString(); + + var expectedResult = this.ReplaceTokens(testFields, result, theTabId); + var testUrl = this.ReplaceTokens(testFields, url, theTabId); + var expectedRedirectUrl = this.ReplaceTokens(testFields, redirectUrl, theTabId); + + this.CreateSimulatedRequest(new Uri(testUrl)); + + var request = HttpContext.Current.Request; + var testHelper = new UrlTestHelper + { + HttpAliasFull = scheme + httpAlias + "/", + Result = new UrlAction(request) + { + IsSecureConnection = request.IsSecureConnection, + RawUrl = request.RawUrl, + }, + RequestUri = new Uri(testUrl), + QueryStringCol = new NameValueCollection(), + }; + + this.ProcessRequest(settings, testHelper); + + // Test expected response status + Assert.AreEqual(expectedStatus, testHelper.Response.StatusCode); + + switch (expectedStatus) + { + case 200: + // Test expected rewrite path + if (!string.IsNullOrEmpty(expectedResult)) + { + Assert.AreEqual(expectedResult, testHelper.Result.RewritePath.TrimStart('/')); + } + + break; + case 301: + case 302: + // Test for final Url if redirected + Assert.IsTrue(expectedRedirectUrl.Equals(testHelper.Result.FinalUrl.TrimStart('/'), StringComparison.InvariantCultureIgnoreCase)); + Assert.AreEqual(redirectReason, testHelper.Result.Reason.ToString(), "Redirect reason incorrect"); + break; + } + } + + private void ExecuteTest(FriendlyUrlSettings settings, Dictionary testFields, bool setDefaultAlias) + { + var tabName = testFields["Page Name"]; + var tab = TabController.Instance.GetTabByName(tabName, this.PortalId); + + if (setDefaultAlias) + { + this.SetDefaultAlias(testFields); + } + + this.ExecuteTestForTab(tab, settings, testFields); + } + + private void UpdateTab(TabInfo tab) + { + if (tab != null) + { + TabController.Instance.UpdateTab(tab); + } + } + + private void UpdateTabName(int theTabId, string newName) + { + var tab = TabController.Instance.GetTab(theTabId, this.PortalId, false); + tab.TabName = newName; + TabController.Instance.UpdateTab(tab); + } + + private void UpdateTabSkin(int theTabId, string newSkin) + { + var tab = TabController.Instance.GetTab(theTabId, this.PortalId, false); + tab.SkinSrc = newSkin; + TabController.Instance.UpdateTab(tab); + } + + private int UpdateHomeTab(int homeTabId) + { + var portalInfo = PortalController.Instance.GetPortal(this.PortalId); + var oldHomeTabId = portalInfo.HomeTabId; + portalInfo.HomeTabId = homeTabId; + + return oldHomeTabId; + } + + private void UpdateTabSetting(string tabName, string settingName, string settingValue) + { + var tab = TabController.Instance.GetTabByName(tabName, this.PortalId); + tab.TabSettings[settingName] = settingValue; + TabController.Instance.UpdateTab(tab); + } + } +} From 95d01b7b71df9a75cf12dde3e015e7b6d21830c9 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 26 Feb 2021 14:52:59 -0600 Subject: [PATCH 27/53] Remove obsolete usages from UrlRewriteTests --- .../DotNetNuke.Tests.Urls/UrlRewriteTests.cs | 42 ++++++++++--------- DNN_Platform.sln.DotSettings | 6 ++- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs b/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs index d5f4e7b0d1e..85f72bb53ab 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs +++ b/DNN Platform/Tests/DotNetNuke.Tests.Urls/UrlRewriteTests.cs @@ -10,6 +10,7 @@ namespace DotNetNuke.Tests.Urls using System.Globalization; using System.Web; + using DotNetNuke.Abstractions.Portals; using DotNetNuke.Common; using DotNetNuke.Common.Utilities; using DotNetNuke.Data; @@ -18,6 +19,9 @@ namespace DotNetNuke.Tests.Urls using DotNetNuke.Entities.Urls; using DotNetNuke.Entities.Users; using DotNetNuke.Services.Localization; + + using Microsoft.Extensions.DependencyInjection; + using NUnit.Framework; [TestFixture] @@ -86,7 +90,7 @@ public override void TearDown() if (this.primaryAlias != null) { - PortalAliasController.Instance.DeletePortalAlias(this.primaryAlias); + Globals.DependencyProvider.GetRequiredService().DeletePortalAlias(this.primaryAlias); } this.SetDefaultAlias(this.DefaultAlias); @@ -115,19 +119,17 @@ public override void TestFixtureSetUp() this.tabId = tab.TabID; // Add Portal Aliases - var aliasController = PortalAliasController.Instance; + var aliasController = Globals.DependencyProvider.GetRequiredService(); TestUtil.ReadStream("Aliases", (line, header) => { var fields = line.Split(','); var alias = aliasController.GetPortalAlias(fields[0], this.PortalId); if (alias == null) { - alias = new PortalAliasInfo - { - HTTPAlias = fields[0], - PortalID = this.PortalId, - }; - PortalAliasController.Instance.AddPortalAlias(alias); + alias = new PortalAliasInfo(); + alias.HttpAlias = fields[0]; + alias.PortalId = this.PortalId; + aliasController.AddPortalAlias(alias); } }); TestUtil.ReadStream("Users", (line, header) => @@ -143,12 +145,12 @@ public override void TestFixtureTearDown() { base.TestFixtureTearDown(); - var aliasController = PortalAliasController.Instance; + var aliasController = Globals.DependencyProvider.GetRequiredService(); TestUtil.ReadStream("Aliases", (line, header) => { var fields = line.Split(','); var alias = aliasController.GetPortalAlias(fields[0], this.PortalId); - PortalAliasController.Instance.DeletePortalAlias(alias); + aliasController.DeletePortalAlias(alias); }); TestUtil.ReadStream("Users", (line, header) => { @@ -396,31 +398,31 @@ public void AdvancedUrlRewriter_0_PrimaryPortalAlias(Dictionary } PortalController.UpdatePortalSetting(this.PortalId, "PortalAliasMapping", "REDIRECT", true, "en-us"); - var alias = PortalAliasController.Instance.GetPortalAlias(defaultAlias, this.PortalId); + + var portalAliasService = Globals.DependencyProvider.GetRequiredService(); + var alias = portalAliasService.GetPortalAlias(defaultAlias, this.PortalId); if (alias == null) { - alias = new PortalAliasInfo - { - HTTPAlias = defaultAlias, - PortalID = this.PortalId, - IsPrimary = true, - }; + alias = new PortalAliasInfo(); + alias.HttpAlias = defaultAlias; + alias.PortalId = this.PortalId; + alias.IsPrimary = true; if (!(string.IsNullOrEmpty(language) && string.IsNullOrEmpty(skin))) { alias.CultureCode = language; alias.Skin = skin; } - PortalAliasController.Instance.AddPortalAlias(alias); + portalAliasService.AddPortalAlias(alias); } this.SetDefaultAlias(defaultAlias); this.ExecuteTest(settings, testFields, false); - alias = PortalAliasController.Instance.GetPortalAlias(defaultAlias, this.PortalId); + alias = portalAliasService.GetPortalAlias(defaultAlias, this.PortalId); if (alias != null) { - PortalAliasController.Instance.DeletePortalAlias(alias); + portalAliasService.DeletePortalAlias(alias); } } diff --git a/DNN_Platform.sln.DotSettings b/DNN_Platform.sln.DotSettings index 2304faded40..dff958f7407 100644 --- a/DNN_Platform.sln.DotSettings +++ b/DNN_Platform.sln.DotSettings @@ -142,4 +142,8 @@ </TypePattern> </Patterns> False - True \ No newline at end of file + True + True + True + True + True \ No newline at end of file From 763a68fb9b8a6cc5bd0dc6c633447c5b5f7acd1a Mon Sep 17 00:00:00 2001 From: Michael Santoro Date: Mon, 1 Mar 2021 13:24:27 -0700 Subject: [PATCH 28/53] remove extra line --- .../FolderProviders/AzureFolderProvider/AzureFolderProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs index 33d4fc66899..ac356444fae 100644 --- a/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs +++ b/DNN Platform/Providers/FolderProviders/AzureFolderProvider/AzureFolderProvider.cs @@ -282,7 +282,6 @@ public override void UpdateFile(IFolderInfo folder, string fileName, Stream cont { IFileInfo originalFile = FileManager.Instance.GetFile(folder, fileName); - base.UpdateFile(folder, fileName, content); if (originalFile != null && originalFile.FileName != fileName) From 1017dad96e87f28cd8376bdcda9d0f27adf97315 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Tue, 2 Mar 2021 13:20:23 -0600 Subject: [PATCH 29/53] Remove NuGet dependency from Instrumentation (#4533) The current state includes a circular dependency from DotNetNuke.Core to DotNetNuke.DependencyInjection to DotNetNuke.Instrumentation to DotNetNuke.Core. --- Build/Tools/NuGet/DotNetNuke.Instrumentation.nuspec | 3 --- 1 file changed, 3 deletions(-) diff --git a/Build/Tools/NuGet/DotNetNuke.Instrumentation.nuspec b/Build/Tools/NuGet/DotNetNuke.Instrumentation.nuspec index 361f4ead659..f6121e2367f 100644 --- a/Build/Tools/NuGet/DotNetNuke.Instrumentation.nuspec +++ b/Build/Tools/NuGet/DotNetNuke.Instrumentation.nuspec @@ -14,9 +14,6 @@ Provides references to enhanced logging and instrumentation available within DNN Platform for extension developers. Including access to Log4Net Copyright (c) .NET Foundation and Contributors, All Rights Reserved. - - - From ec762ba9e38817bd74aa9be1ae144b8bde5a6dee Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Tue, 2 Mar 2021 13:21:32 -0600 Subject: [PATCH 30/53] Update Compress Images GitHub Actions workflow (#4478) The Compress Images workflow isn't catching most of the images being committed. This is, in part, because it doesn't run with permissions to edit PRs on forks. This updates the configuration to open a new PR when a commit is merged, if there are images that can be compressed. It also adds a scheduled run, in case something gets missed. Based on https://github.com/calibreapp/image-actions#combined-workflow --- .github/workflows/image-actions.yml | 30 ++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/workflows/image-actions.yml b/.github/workflows/image-actions.yml index 100055f7e09..7a5ec4ce903 100644 --- a/.github/workflows/image-actions.yml +++ b/.github/workflows/image-actions.yml @@ -1,7 +1,23 @@ name: Compress images -on: pull_request +on: + pull_request: # PRs with image (but we can't push changes back to other forks) + paths: + - "**.jpg" + - "**.jpeg" + - "**.png" + - "**.webp" + push: + branches: + - development # merging PRs from other forks (will open a new PR) + worflow_dispatch: # on demand + schedule: + - cron: "0 0 * * 0" # every Sunday at midnight jobs: build: + if: | # Only run on main repo on and PRs that match the main repo. + github.repository == 'dnnsoftware/Dnn.Platform' && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) name: calibreapp/image-actions runs-on: ubuntu-latest steps: @@ -9,6 +25,18 @@ jobs: uses: actions/checkout@v2 - name: Compress Images + id: compress_images uses: calibreapp/image-actions@1.1.0 with: githubToken: ${{ secrets.GITHUB_TOKEN }} + compressOnly: ${{ github.event_name != 'pull_request' }} # For non-Pull Requests, run in compressOnly mode and we'll PR after. + + - name: Create Pull Request + if: | # If it's not a Pull Request then commit any changes as a new PR. + github.event_name != 'pull_request' && steps.compress_images.outputs.markdown != '' + uses: peter-evans/create-pull-request@v3 + with: + title: Auto Compress Images + branch-suffix: timestamp + commit-message: Compress Images + body: ${{ steps.compress_images.outputs.markdown }} From 5e0a90ba4cfa372831a5afd5e76b2bb33bec57ab Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 5 Mar 2021 14:50:49 -0600 Subject: [PATCH 31/53] Add Microsoft.SourceLink.GitHub to all packages --- .../DotNetNuke.Abstractions.csproj | 4 ++++ .../DotNetNuke.DependencyInjection.csproj | 4 ++++ .../DotNetNuke.Instrumentation.csproj | 21 +++++++++++++++- .../packages.config | 3 +++ .../DotNetNuke.Log4Net.csproj | 24 ++++++++++++++++++- .../DotNetNuke.Log4net/packages.config | 6 +++++ .../DotNetNuke.Web.Client.csproj | 21 +++++++++++++++- .../DotNetNuke.Web.Client/packages.config | 3 +++ .../DotNetNuke.Web.Mvc.csproj | 16 ++++++++++++- .../DotNetNuke.Web.Mvc/packages.config | 3 +++ .../DotNetNuke.Web.Razor.csproj | 16 ++++++++++++- .../DotNetNuke.Web.Razor/packages.config | 3 +++ .../DotNetNuke.Web/DotNetNuke.Web.csproj | 16 ++++++++++++- DNN Platform/DotNetNuke.Web/packages.config | 3 +++ .../DotNetNuke.WebUtility.vbproj | 21 +++++++++++++++- .../DotNetNuke.WebUtility/packages.config | 3 +++ .../HttpModules/DotNetNuke.HttpModules.csproj | 21 +++++++++++++++- DNN Platform/HttpModules/packages.config | 3 +++ .../Library/DotNetNuke.Library.csproj | 19 +++++++++++++++ DNN Platform/Library/packages.config | 3 +++ .../DotNetNuke.Modules.DigitalAssets.csproj | 16 ++++++++++++- .../Modules/DigitalAssets/packages.config | 3 +++ .../DnnExportImport/DnnExportImport.csproj | 21 +++++++++++++++- .../Modules/DnnExportImport/packages.config | 3 +++ .../DnnExportImportLibrary.csproj | 21 +++++++++++++++- .../DnnExportImportLibrary/packages.config | 3 +++ ...otNetNuke.Providers.FolderProviders.csproj | 16 ++++++++++++- .../Providers/FolderProviders/packages.config | 3 +++ .../DNN.Integration.Test.Framework.csproj | 12 ++++++++++ .../packages.config | 3 +++ .../DotNetNuke.Tests.Utilities.csproj | 12 ++++++++++ .../packages.config | 3 +++ .../Dnn.EditBar.Library.csproj | 19 +++++++++++++++ .../Dnn.EditBar.Library/packages.config | 3 +++ .../Dnn.EditBar.UI/Dnn.EditBar.UI.csproj | 19 +++++++++++++++ .../EditBar/Dnn.EditBar.UI/packages.config | 3 +++ .../Dnn.PersonaBar.Library.csproj | 19 +++++++++++++++ .../Dnn.PersonaBar.Library/packages.config | 3 +++ .../Dnn.PersonaBar.UI.csproj | 14 +++++++++++ .../Library/Dnn.PersonaBar.UI/packages.config | 3 +++ 40 files changed, 400 insertions(+), 12 deletions(-) create mode 100644 DNN Platform/DotNetNuke.Log4net/packages.config diff --git a/DNN Platform/DotNetNuke.Abstractions/DotNetNuke.Abstractions.csproj b/DNN Platform/DotNetNuke.Abstractions/DotNetNuke.Abstractions.csproj index 98abb056202..91e49477f1f 100644 --- a/DNN Platform/DotNetNuke.Abstractions/DotNetNuke.Abstractions.csproj +++ b/DNN Platform/DotNetNuke.Abstractions/DotNetNuke.Abstractions.csproj @@ -12,6 +12,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj b/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj index bdc81da8d48..cdafdb10dac 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj +++ b/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj @@ -14,6 +14,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj b/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj index bb606a9f3d0..c42c02586d2 100644 --- a/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj +++ b/DNN Platform/DotNetNuke.Instrumentation/DotNetNuke.Instrumentation.csproj @@ -1,7 +1,12 @@  + + + - true + true + + Debug @@ -89,4 +94,18 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Instrumentation/packages.config b/DNN Platform/DotNetNuke.Instrumentation/packages.config index e619441b462..05c281d39b4 100644 --- a/DNN Platform/DotNetNuke.Instrumentation/packages.config +++ b/DNN Platform/DotNetNuke.Instrumentation/packages.config @@ -1,4 +1,7 @@  + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj b/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj index 8e8c4b6bfa4..851442e7eef 100644 --- a/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj +++ b/DNN Platform/DotNetNuke.Log4net/DotNetNuke.Log4Net.csproj @@ -20,8 +20,13 @@ --> + + + - true + true + + {04F77171-0634-46E0-A95E-D7477C88712E} @@ -730,6 +735,9 @@ + + + $(MSBuildProjectDirectory)\..\.. @@ -741,4 +749,18 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Log4net/packages.config b/DNN Platform/DotNetNuke.Log4net/packages.config new file mode 100644 index 00000000000..f48bd46073a --- /dev/null +++ b/DNN Platform/DotNetNuke.Log4net/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj b/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj index 33b48665016..f26a71f1554 100644 --- a/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj +++ b/DNN Platform/DotNetNuke.Web.Client/DotNetNuke.Web.Client.csproj @@ -1,7 +1,12 @@  + + + - true + true + + Debug @@ -105,4 +110,18 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Client/packages.config b/DNN Platform/DotNetNuke.Web.Client/packages.config index e619441b462..05c281d39b4 100644 --- a/DNN Platform/DotNetNuke.Web.Client/packages.config +++ b/DNN Platform/DotNetNuke.Web.Client/packages.config @@ -1,4 +1,7 @@  + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj b/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj index 4d4875e754b..d4beb844e56 100644 --- a/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj +++ b/DNN Platform/DotNetNuke.Web.Mvc/DotNetNuke.Web.Mvc.csproj @@ -1,8 +1,13 @@  + + + - true + true + + Debug @@ -235,6 +240,15 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Mvc/packages.config b/DNN Platform/DotNetNuke.Web.Mvc/packages.config index c391de8c125..e7ab49530dc 100644 --- a/DNN Platform/DotNetNuke.Web.Mvc/packages.config +++ b/DNN Platform/DotNetNuke.Web.Mvc/packages.config @@ -6,6 +6,9 @@ + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj b/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj index 7551766c35c..e599f478459 100644 --- a/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj +++ b/DNN Platform/DotNetNuke.Web.Razor/DotNetNuke.Web.Razor.csproj @@ -1,7 +1,12 @@  + + + - true + true + + Debug @@ -155,5 +160,14 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Razor/packages.config b/DNN Platform/DotNetNuke.Web.Razor/packages.config index b0fa19d1c3c..41995962df6 100644 --- a/DNN Platform/DotNetNuke.Web.Razor/packages.config +++ b/DNN Platform/DotNetNuke.Web.Razor/packages.config @@ -5,8 +5,11 @@ + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web/DotNetNuke.Web.csproj b/DNN Platform/DotNetNuke.Web/DotNetNuke.Web.csproj index 7344f704f5a..0dfb40cf2af 100644 --- a/DNN Platform/DotNetNuke.Web/DotNetNuke.Web.csproj +++ b/DNN Platform/DotNetNuke.Web/DotNetNuke.Web.csproj @@ -1,7 +1,12 @@  + + + - true + true + + Debug @@ -455,5 +460,14 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web/packages.config b/DNN Platform/DotNetNuke.Web/packages.config index e4e585d7cf0..4a333ac4445 100644 --- a/DNN Platform/DotNetNuke.Web/packages.config +++ b/DNN Platform/DotNetNuke.Web/packages.config @@ -7,8 +7,11 @@ + + + diff --git a/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj b/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj index 6f2720e74d9..7bd1380f909 100644 --- a/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj +++ b/DNN Platform/DotNetNuke.WebUtility/DotNetNuke.WebUtility.vbproj @@ -1,7 +1,12 @@  + + + - true + true + + Local @@ -203,4 +208,18 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.WebUtility/packages.config b/DNN Platform/DotNetNuke.WebUtility/packages.config index e619441b462..05c281d39b4 100644 --- a/DNN Platform/DotNetNuke.WebUtility/packages.config +++ b/DNN Platform/DotNetNuke.WebUtility/packages.config @@ -1,4 +1,7 @@  + + + \ No newline at end of file diff --git a/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj b/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj index 7ca56a4b41c..ca28a9fc885 100644 --- a/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj +++ b/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj @@ -1,7 +1,12 @@  + + + - true + true + + 9.0.30729 @@ -151,4 +156,18 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/HttpModules/packages.config b/DNN Platform/HttpModules/packages.config index 93fa98c3e44..a207d534a2c 100644 --- a/DNN Platform/HttpModules/packages.config +++ b/DNN Platform/HttpModules/packages.config @@ -1,5 +1,8 @@  + + + \ No newline at end of file diff --git a/DNN Platform/Library/DotNetNuke.Library.csproj b/DNN Platform/Library/DotNetNuke.Library.csproj index 3caa4dbb567..3a6da40e353 100644 --- a/DNN Platform/Library/DotNetNuke.Library.csproj +++ b/DNN Platform/Library/DotNetNuke.Library.csproj @@ -1,7 +1,12 @@  + + + true + + Local @@ -1921,4 +1926,18 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/Library/packages.config b/DNN Platform/Library/packages.config index 5a52146735f..95c970c5a78 100644 --- a/DNN Platform/Library/packages.config +++ b/DNN Platform/Library/packages.config @@ -4,9 +4,12 @@ + + + diff --git a/DNN Platform/Modules/DigitalAssets/DotNetNuke.Modules.DigitalAssets.csproj b/DNN Platform/Modules/DigitalAssets/DotNetNuke.Modules.DigitalAssets.csproj index 73e56abc5dd..ac49bceb8ec 100644 --- a/DNN Platform/Modules/DigitalAssets/DotNetNuke.Modules.DigitalAssets.csproj +++ b/DNN Platform/Modules/DigitalAssets/DotNetNuke.Modules.DigitalAssets.csproj @@ -1,8 +1,13 @@  + + + - true + true + + Debug @@ -390,5 +395,14 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + \ No newline at end of file diff --git a/DNN Platform/Modules/DigitalAssets/packages.config b/DNN Platform/Modules/DigitalAssets/packages.config index ac97de4b706..9221e6fb08f 100644 --- a/DNN Platform/Modules/DigitalAssets/packages.config +++ b/DNN Platform/Modules/DigitalAssets/packages.config @@ -4,8 +4,11 @@ + + + \ No newline at end of file diff --git a/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj b/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj index baecef75046..6e5f980f5a7 100644 --- a/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj +++ b/DNN Platform/Modules/DnnExportImport/DnnExportImport.csproj @@ -1,8 +1,13 @@  + + + - true + true + + Debug @@ -179,6 +184,20 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + $(MSBuildProjectDirectory) + DotNetNuke.Build + true + CS0618 + true + + + - + + - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file diff --git a/Build/Cake/Extensions.cs b/Build/Cake/Extensions.cs deleted file mode 100644 index 08b93af823d..00000000000 --- a/Build/Cake/Extensions.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System.Linq; - -using Cake.Common.IO; -using Cake.Core; -using Cake.Core.Annotations; -using Cake.Core.IO; -using Dnn.CakeUtils; - -public static class Extensions -{ - [CakeMethodAlias] - public static FilePathCollection GetFilesByPatterns(this ICakeContext context, string[] includePatterns) - { - var res = new FilePathCollection(); - for (var i = 0; i < includePatterns.Length; i++) - { - var incl = context.GetFiles(includePatterns[i]); - var crt = res.Select(ii => ii.FullPath); - foreach (var include in incl) - { - if (!crt.Contains(include.FullPath)) - { - res.Add(include); - } - } - } - - return res; - } - - [CakeMethodAlias] - public static FilePathCollection GetFilesByPatterns( - this ICakeContext context, - string[] includePatterns, - string[] excludePatterns) - { - if (excludePatterns.Length == 0) - { - return GetFilesByPatterns(context, includePatterns); - } - - FilePathCollection excludeFiles = context.GetFiles(excludePatterns[0]); - for (var i = 1; i < excludePatterns.Length; i++) - { - excludeFiles.Add(context.GetFiles(excludePatterns[i])); - } - - var excludePaths = excludeFiles.Select(e => e.FullPath); - var res = new FilePathCollection(); - for (var i = 0; i < includePatterns.Length; i++) - { - var incl = context.GetFiles(includePatterns[i]); - var crt = res.Select(ii => ii.FullPath); - foreach (var include in incl) - { - if (!excludeFiles.Contains(include.FullPath) && !crt.Contains(include.FullPath)) - { - res.Add(include); - } - } - } - - return res; - } - - [CakeMethodAlias] - public static FilePathCollection GetFilesByPatterns( - this ICakeContext context, - string root, - string[] includePatterns) - { - root = root.EnsureEndsWith("/"); - var res = new FilePathCollection(); - for (var i = 0; i < includePatterns.Length; i++) - { - var incl = context.GetFiles( - root - + includePatterns[i] - .TrimStart('/')); - var crt = res.Select(ii => ii.FullPath); - foreach (var include in incl) - { - if (!crt.Contains(include.FullPath)) - { - res.Add(include); - } - } - } - - return res; - } - - [CakeMethodAlias] - public static FilePathCollection GetFilesByPatterns( - this ICakeContext context, - string root, - string[] includePatterns, - string[] excludePatterns) - { - if (excludePatterns.Length == 0) - { - return GetFilesByPatterns(context, includePatterns); - } - - root = root.EnsureEndsWith("/"); - FilePathCollection excludeFiles = context.GetFiles( - root - + excludePatterns[0] - .TrimStart('/')); - for (var i = 1; i < excludePatterns.Length; i++) - { - excludeFiles.Add( - context.GetFiles( - root - + excludePatterns[i] - .TrimStart('/'))); - } - - var excludePaths = excludeFiles.Select(e => e.FullPath); - var res = new FilePathCollection(); - for (var i = 0; i < includePatterns.Length; i++) - { - var incl = context.GetFiles( - root - + includePatterns[i] - .TrimStart('/')); - var crt = res.Select(ii => ii.FullPath); - foreach (var include in incl) - { - if (!excludeFiles.Contains(include.FullPath) && !crt.Contains(include.FullPath)) - { - res.Add(include); - } - } - } - - return res; - } -} diff --git a/Build/Cake/build.cs b/Build/Cake/build.cs deleted file mode 100644 index 74c5424516e..00000000000 --- a/Build/Cake/build.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using Cake.Common; -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Common.IO.Paths; -using Cake.Common.Tools.GitVersion; -using Cake.Core; -using Cake.Core.Diagnostics; -using Cake.Core.IO; -using Cake.FileHelpers; -using Cake.Frosting; -using Dnn.CakeUtils; -using Newtonsoft.Json; - -public class Context : FrostingContext -{ - public Context(ICakeContext context) - : base(context) - { - try - { - ////////////////////////////////////////////////////////////////////// - // ARGUMENTS - ////////////////////////////////////////////////////////////////////// - - this.target = context.Argument("target", "Default"); - context.Information($"Target: {target}"); - this.configuration = context.Argument("configuration", "Release"); - context.Information($"Configuration: {configuration}"); - - ////////////////////////////////////////////////////////////////////// - // PREPARATION - ////////////////////////////////////////////////////////////////////// - - // Define directories. - this.tempFolder = "./Temp/"; - this.tempDir = context.Directory(tempFolder); - context.Information($"TempDir: {tempDir}"); - - this.artifactsFolder = "./Artifacts/"; - this.artifactsDir = context.Directory(this.artifactsFolder); - context.Information($"ArtifactsDir: {artifactsDir}"); - - this.websiteFolder = "./Website/"; - this.websiteDir = context.Directory(this.websiteFolder); - context.Information($"WebsiteDir: {websiteDir}"); - - // Global information variables - this.isRunningInCI = false; - - this.dnnSolutionPath = "./DNN_Platform.sln"; - - this.sqlDataProviderExists = false; - - var settingsFile = "./settings.local.json"; - this.Settings = this.LoadSettings(context, settingsFile); - this.WriteSettings(context, settingsFile); - - this.buildId = context.EnvironmentVariable("BUILD_BUILDID") ?? "0"; - context.Information($"BuildId: {buildId}"); - this.buildNumber = ""; - this.productVersion = ""; - } - catch (Exception exc) - { - this.Error(exc); - throw; - } - } - - public string productVersion { get; set; } - - public string buildNumber { get; set; } - - public string buildId { get; set; } - - public bool sqlDataProviderExists { get; set; } - - public string dnnSolutionPath { get; set; } - - public bool isRunningInCI { get; set; } - - public ConvertableDirectoryPath websiteDir { get; set; } - - public string websiteFolder { get; set; } - - public ConvertableDirectoryPath artifactsDir { get; set; } - - public string artifactsFolder { get; set; } - - public ConvertableDirectoryPath tempDir { get; set; } - - public string tempFolder { get; set; } - - public string configuration { get; set; } - - public string target { get; set; } - - public PackagingPatterns packagingPatterns { get; set; } - - public LocalSettings Settings { get; set; } - - public GitVersion version { get; set; } - - public string GetBuildNumber() - { - return buildNumber; - } - - public string GetTwoDigitsVersionNumber(){ - var fullVer = GetBuildNumber().Split('-')[0]; // Gets rid of the -unstable, -beta, etc. - var numbers = fullVer.Split('.'); - for (int i=0; i < numbers.Length; i++) - { - if (numbers[i].Length < 2) - { - numbers[i] = "0" + numbers[i]; - } - } - return String.Join(".", numbers); - } - - public string GetProductVersion() - { - return productVersion; - } - - private void WriteSettings(ICakeContext context, string settingsFile) - { - using (var sw = new System.IO.StreamWriter(settingsFile)) - { - sw.WriteLine(JsonConvert.SerializeObject(this.Settings, Formatting.Indented)); - } - - context.Information(log => log($"Saved settings to {System.IO.Path.GetFullPath(settingsFile)}")); - context.Debug(log => log($"Settings: {JsonConvert.SerializeObject(this.Settings, Formatting.Indented).Replace("{", "{{")}")); - } - - private LocalSettings LoadSettings(ICakeContext context, string settingsFile) { - if (System.IO.File.Exists(settingsFile)) { - context.Information(log => log($"Loading settings from {System.IO.Path.GetFullPath(settingsFile)}")); - return JsonConvert.DeserializeObject(Utilities.ReadFile(settingsFile)); - } else { - context.Information(log => log($"Did not find settings file {System.IO.Path.GetFullPath(settingsFile)}")); - return new LocalSettings(); - } - } -} - -////////////////////////////////////////////////////////////////////// -// SETUP/TEARDOWN -////////////////////////////////////////////////////////////////////// - -public sealed class Lifetime : FrostingLifetime -{ - public override void Setup(Context context) - { - context.isRunningInCI = context.HasEnvironmentVariable("TF_BUILD"); - context.Information("Is Running in CI : {0}", context.isRunningInCI); - if (context.Settings.Version == "auto" && !context.isRunningInCI) - { - // Temporarily commit all changes to prevent checking in scripted changes like versioning. - Git(context, "add ."); - Git(context, "commit --allow-empty -m 'backup'"); - } - } - - public override void Teardown(Context context, ITeardownContext info) - { - if (context.Settings.Version == "auto" && !context.isRunningInCI) - { - // Undoes the script changes to all tracked files. - Git(context, "reset --hard"); - - // Undoes the setup commit keeping file states as before this build script ran. - Git(context, "reset HEAD^"); - } - } - - private static void Git(ICakeContext context, string arguments) - { - context.Information($"git ${arguments}"); - using (var process = context.StartAndReturnProcess("git", new ProcessSettings {Arguments = arguments})) - { - process.WaitForExit(); - } - } -} - -////////////////////////////////////////////////////////////////////// -// TASKS -////////////////////////////////////////////////////////////////////// - -public sealed class CleanWebsite : FrostingTask -{ - public override void Run(Context context) - { - context.CleanDirectory(context.websiteDir); - - } -} - -public sealed class CleanTemp : FrostingTask -{ - public override void Run(Context context) - { - context.CleanDirectory(context.tempDir); - - } -} - -public sealed class CleanArtifacts : FrostingTask -{ - public override void Run(Context context) - { - context.CleanDirectory(context.artifactsDir); - - } -} - -////////////////////////////////////////////////////////////////////// -// TASK TARGETS -////////////////////////////////////////////////////////////////////// - -[Dependency(typeof(CleanArtifacts))] -[Dependency(typeof(UpdateDnnManifests))] -[Dependency(typeof(CreateInstall))] -[Dependency(typeof(CreateUpgrade))] -[Dependency(typeof(CreateDeploy))] -[Dependency(typeof(CreateSymbols))] -public sealed class Default : FrostingTask -{ -} diff --git a/Build/Cake/ci.cs b/Build/Cake/ci.cs deleted file mode 100644 index 240c5e84e24..00000000000 --- a/Build/Cake/ci.cs +++ /dev/null @@ -1,31 +0,0 @@ -// This is the task CI will use to build release packages - -using Cake.Frosting; - -[Dependency(typeof(CleanArtifacts))] -[Dependency(typeof(UpdateDnnManifests))] -[Dependency(typeof(GenerateSecurityAnalyzerChecksums))] -[Dependency(typeof(SetPackageVersions))] -[Dependency(typeof(CreateInstall))] -[Dependency(typeof(CreateUpgrade))] -[Dependency(typeof(CreateDeploy))] -[Dependency(typeof(CreateSymbols))] -[Dependency(typeof(CreateNugetPackages))] -[Dependency(typeof(GeneratePackagesChecksums))] -public sealed class BuildAll : FrostingTask -{ - public override void Run(Context context) - { - RevertSqlDataProvider(context); - } - - private void RevertSqlDataProvider(Context context) - { - var fileName = context.GetTwoDigitsVersionNumber() + ".SqlDataProvider"; - var filePath = "./Dnn Platform/Website/Providers/DataProviders/SqlDataProvider/" + fileName; - if (!context.sqlDataProviderExists && System.IO.File.Exists(filePath)) - { - System.IO.File.Delete(filePath); - } - } -} diff --git a/Build/Cake/compiling.cs b/Build/Cake/compiling.cs deleted file mode 100644 index 61ebe17af7c..00000000000 --- a/Build/Cake/compiling.cs +++ /dev/null @@ -1,32 +0,0 @@ -// This tasks kicks off MS Build (just as in Visual Studio) - -using Cake.Common.Tools.MSBuild; -using Cake.Common.Tools.NuGet; -using Cake.Frosting; - -[Dependency(typeof(CleanWebsite))] -[Dependency(typeof(RestoreNuGetPackages))] -public sealed class Build : FrostingTask -{ - public override void Run(Context context) - { - context.MSBuild(context.dnnSolutionPath, settings => settings.WithTarget("Clean")); - - var buildSettings = new MSBuildSettings() - .SetConfiguration(context.configuration) - .SetPlatformTarget(PlatformTarget.MSIL) - .WithTarget("Rebuild") - .SetMaxCpuCount(4) - .WithProperty("SourceLinkCreate","true"); - context.MSBuild(context.dnnSolutionPath, buildSettings); - } -} - -public sealed class RestoreNuGetPackages : FrostingTask -{ - public override void Run(Context context) - { - context.NuGetRestore(context.dnnSolutionPath); - - } -} diff --git a/Build/Cake/create-database.cs b/Build/Cake/create-database.cs deleted file mode 100644 index 378e1a36f8b..00000000000 --- a/Build/Cake/create-database.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Common.Xml; -using Cake.Frosting; - -[Dependency(typeof(CleanArtifacts))] -[Dependency(typeof(UpdateDnnManifests))] -[Dependency(typeof(CreateInstall))] -[Dependency(typeof(CreateUpgrade))] -[Dependency(typeof(CreateDeploy))] -[Dependency(typeof(CreateSymbols))] -[Dependency(typeof(CreateDatabase))] -public sealed class BuildWithDatabase : FrostingTask -{ -} - -public sealed class CreateDatabase : FrostingTask -{ - private string connectionString = @"server=(localdb)\MSSQLLocalDB"; - - public override void Run(Context context) - { - var deleteScript = "if db_id('Dnn_Platform') is not null DROP DATABASE Dnn_Platform;"; - - context.Information("Dropping LocalDb: {0}", ExecuteSqlScript(context, deleteScript)); - - var createDbScript = string.Format(@" - CREATE DATABASE - [Dnn_Platform] - ON PRIMARY ( - NAME=Dnn_data, - FILENAME = '{0}\Dnn_Platform.mdf' - ) - LOG ON ( - NAME=Dnn_log, - FILENAME = '{0}\Dnn_Platform.ldf' - )", - context.tempDir - ); - var createDbStatus = ExecuteSqlScript(context, createDbScript); - context.Information("Created LocalDb: {0}", createDbStatus); - - if (createDbStatus) - { - connectionString = @"server=(localdb)\MSSQLLocalDB;Database=Dnn_Platform;Trusted_Connection=True;"; - - var schemaScriptName = context.XmlPeek("./Website/Install/DotNetNuke.install.config.resources", "/dotnetnuke/scripts/script[@name='Schema']"); - var dataScriptName = context.XmlPeek("./Website/Install/DotNetNuke.install.config.resources", "/dotnetnuke/scripts/script[@name='Data']"); - var schemaVersion = context.XmlPeek("./Website/Install/DotNetNuke.install.config.resources", "/dotnetnuke/version"); - - //##################################################################### - //run initial schema first - //##################################################################### - var fileContents = System.IO.File.ReadAllText("./Website/Providers/DataProviders/SqlDataProvider/" + schemaScriptName.ToString() + ".SqlDataProvider"); - - var sqlDelimiterRegex = new System.Text.RegularExpressions.Regex("(?<=(?:[^\\w]+|^))GO(?=(?: |\\t)*?(?:\\r?\\n|$))", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline); - string[] sqlStatements = sqlDelimiterRegex.Split(fileContents); - foreach (string statement in sqlStatements) - { - ExecuteSqlScript(context, statement); - } - context.Information("Initial Schema for v{0}", schemaVersion); - - //##################################################################### - //populate with data next - //##################################################################### - fileContents = System.IO.File.ReadAllText("./Website/Providers/DataProviders/SqlDataProvider/" + dataScriptName.ToString() + ".SqlDataProvider"); - - sqlStatements = sqlDelimiterRegex.Split(fileContents); - foreach (string statement in sqlStatements) - { - context.Information("Test Data: {1}", schemaVersion, ExecuteSqlScript(context, statement)); - } - - var createDummyPortalStatement = "INSERT [dbo].[dnn_Portals] ([ExpiryDate], [UserRegistration], [BannerAdvertising], [AdministratorId], [Currency], [HostFee], [HostSpace], [AdministratorRoleId], [RegisteredRoleId], [GUID], [PaymentProcessor], [ProcessorUserId], [ProcessorPassword], [SiteLogHistory], [DefaultLanguage], [TimezoneOffset], [HomeDirectory], [PageQuota], [UserQuota], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [PortalGroupID]) VALUES (NULL, 1, 0, 1, N'USD', 0.0000, 0, 0, 1, N'97debbc9-4643-4bd9-b0a0-b14170b38b0f', N'PayPal', NULL, NULL, 0, N'en-US', -8, N'Portals/0', 0, 0, -1, CAST(N'2015-02-05 14:49:37.873' AS DateTime), 1, CAST(N'2015-10-13 11:08:13.513' AS DateTime), -1)"; - - context.Information("Test Portal: {1}", schemaVersion, ExecuteSqlScript(context, createDummyPortalStatement)); - - //##################################################################### - //now get all other SqlDataProvider files and run those.... - //##################################################################### - var files = context.GetFiles("./Website/Providers/DataProviders/SqlDataProvider/*.SqlDataProvider"); - - var currentFileToProcess = string.Empty; - - foreach (var file in files) - { - currentFileToProcess = file.GetFilenameWithoutExtension().ToString(); - var fileBits = currentFileToProcess.Split('.'); - - int firstBit; - int secondBit; - int thirdBit; - - if (int.TryParse(fileBits[0], out firstBit) && int.TryParse(fileBits[1], out secondBit) && int.TryParse(fileBits[2], out thirdBit)) - { - var schemaVersionBits = schemaVersion.Split('.'); - - int schemaFirstBit = int.Parse(schemaVersionBits[0]); - int schemaSecondBit = int.Parse(schemaVersionBits[1]); - int schemaThirdBit = int.Parse(schemaVersionBits[2]); - - if ((firstBit == schemaFirstBit && (secondBit >= schemaSecondBit && thirdBit >= schemaThirdBit)) || firstBit > schemaFirstBit) - { - context.Information("Updated to v{0}", currentFileToProcess); - - fileContents = System.IO.File.ReadAllText(file.ToString()); - - sqlStatements = sqlDelimiterRegex.Split(fileContents); - foreach (string statement in sqlStatements) - { - var statementSuccess = ExecuteSqlScript(context, statement); - } - } - - } - } - - } - else - { - context.Information("An Error has occured. Please review and try again."); - } - } - - private bool ExecuteSqlScript(Context context, string ScriptStatement) - { - try - { - using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) - { - connection.Open(); - - var command = new System.Data.SqlClient.SqlCommand(ScriptStatement.Replace("{databaseOwner}", "dbo.").Replace("{objectQualifier}", "dnn_"), connection); - command.ExecuteNonQuery(); - - connection.Close(); - } - } - catch (Exception err) - { - context.Error(err); - - return false; - } - - return true; - } -} - - diff --git a/Build/Cake/database.cs b/Build/Cake/database.cs deleted file mode 100644 index 871a4cc4d8a..00000000000 --- a/Build/Cake/database.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Database tasks for your local DNN development site - -using System; -using System.Data.SqlClient; -using Cake.Common.Diagnostics; -using Cake.Frosting; -using Dnn.CakeUtils; - -public sealed class ResetDatabase : FrostingTask -{ - public override void Run(Context context) - { - - var script = ReplaceScriptVariables(context, LoadScript("db-connections-drop")); - ExecuteScript(context, script); - script = ReplaceScriptVariables(context, LoadScript("create-db")); - ExecuteScript(context, script); - if (context.Settings.DnnSqlUsername != "") - { - script = ReplaceScriptVariables(context, LoadScript("add-db-user")); - ExecuteScript(context, script); - } - } - - private const string ScriptsPath = @".\Build\Cake\sql\"; - - private static readonly string[] GoStatement = {"\r\nGO\r\n", "\nGO\n", "\nGO\r\n", "\r\nGO\n",}; - - private string LoadScript(string scriptName) - { - var script = scriptName + ".local.sql"; - if (!System.IO.File.Exists(ScriptsPath + script)) - { - script = scriptName + ".sql"; - } - - return Utilities.ReadFile(ScriptsPath + script); - } - - private string ReplaceScriptVariables(Context context, string script) - { - return script - .Replace("{DBName}", context.Settings.DnnDatabaseName) - .Replace("{DBPath}", context.Settings.DatabasePath) - .Replace("{DBLogin}", context.Settings.DnnSqlUsername); - } - - private bool ExecuteScript(Context context, string scriptStatement) - { - try - { - using (var connection = new SqlConnection(context.Settings.SaConnectionString)) - { - connection.Open(); - foreach (var cmd in scriptStatement.Split(GoStatement, StringSplitOptions.RemoveEmptyEntries)) - { - var command = new SqlCommand(cmd, connection); - command.ExecuteNonQuery(); - } - - connection.Close(); - } - } - catch (Exception err) - { - context.Error(err); - return false; - } - - return true; - } -} diff --git a/Build/Cake/devsite.cs b/Build/Cake/devsite.cs deleted file mode 100644 index ce7c545c60f..00000000000 --- a/Build/Cake/devsite.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Tasks to help you create and maintain a local DNN development site. -// Note these tasks depend on the correct settings in your settings file. - -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Common.Xml; -using Cake.FileHelpers; -using Cake.Frosting; -using Dnn.CakeUtils; - -[Dependency(typeof(SetVersion))] -[Dependency(typeof(UpdateDnnManifests))] -[Dependency(typeof(ResetDatabase))] -[Dependency(typeof(PreparePackaging))] -[Dependency(typeof(OtherPackages))] -public sealed class BuildToTempFolder : FrostingTask -{ -} - -[Dependency(typeof(BuildToTempFolder))] -[Dependency(typeof(CopyToDevSite))] -[Dependency(typeof(CopyWebConfigToDevSite))] -public sealed class ResetDevSite : FrostingTask -{ -} - -public sealed class CopyToDevSite : FrostingTask -{ - public override void Run(Context context) - { - context.CleanDirectory(context.Settings.WebsitePath); - var files = context.GetFilesByPatterns(context.websiteFolder, new string[] {"**/*"}, - context.packagingPatterns.installExclude); - files.Add(context.GetFilesByPatterns(context.websiteFolder, context.packagingPatterns.installInclude)); - context.Information("Copying {0} files to {1}", files.Count, context.Settings.WebsitePath); - context.CopyFiles(files, context.Settings.WebsitePath, true); - - } -} - -public sealed class CopyWebConfigToDevSite : FrostingTask -{ - public override void Run(Context context) - { - var conf = Utilities.ReadFile("./Website/web.config"); - var transFile = "./Build/Cake/webconfig-transform.local.xsl"; - if (!context.FileExists(transFile)) transFile = "./Build/Cake/webconfig-transform.xsl"; - var trans = Utilities.ReadFile(transFile); - trans = trans - .Replace("{ConnectionString}", context.Settings.DnnConnectionString) - .Replace("{DbOwner}", context.Settings.DbOwner) - .Replace("{ObjectQualifier}", context.Settings.ObjectQualifier); - var res = context.XmlTransform(trans, conf); - var webConfig = context.File(System.IO.Path.Combine(context.Settings.WebsitePath, "web.config")); - context.FileWriteText(webConfig, res); - - } -} diff --git a/Build/Cake/nuget.cs b/Build/Cake/nuget.cs deleted file mode 100644 index 43251e4e760..00000000000 --- a/Build/Cake/nuget.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Common.Tools.NuGet; -using Cake.Common.Tools.NuGet.Pack; -using Cake.Frosting; - -[Dependency(typeof(PreparePackaging))] -public sealed class CreateNugetPackages : FrostingTask -{ - public override void Run(Context context) - { - //look for solutions and start building them - var nuspecFiles = context.GetFiles("./Build/Tools/NuGet/*.nuspec"); - - context.Information("Found {0} nuspec files.", nuspecFiles.Count); - - //basic nuget package configuration - var nuGetPackSettings = new NuGetPackSettings - { - Version = context.GetBuildNumber(), - OutputDirectory = @"./Artifacts/", - IncludeReferencedProjects = true, - Symbols = true, - Properties = new Dictionary {{"Configuration", "Release"}} - }; - - //loop through each nuspec file and create the package - foreach (var spec in nuspecFiles) - { - var specPath = spec.ToString(); - - context.Information("Starting to pack: {0}", specPath); - context.NuGetPack(specPath, nuGetPackSettings); - } - } -} diff --git a/Build/Cake/packaging.cs b/Build/Cake/packaging.cs deleted file mode 100644 index 64b0ec35c52..00000000000 --- a/Build/Cake/packaging.cs +++ /dev/null @@ -1,236 +0,0 @@ -// The tasks create the various DNN release packages (Install, Upgrade, Deploy and Symbols) - -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Frosting; -using Dnn.CakeUtils; -using Newtonsoft.Json; - -public class PackagingPatterns -{ - public string[] installExclude { get; set; } - public string[] installInclude { get; set; } - public string[] upgradeExclude { get; set; } - public string[] symbolsInclude { get; set; } - public string[] symbolsExclude { get; set; } -} - - -[Dependency(typeof(CopyWebsite))] -[Dependency(typeof(Build))] -[Dependency(typeof(CopyWebConfig))] -[Dependency(typeof(CopyWebsiteBinFolder))] -public sealed class PreparePackaging : FrostingTask -{ - public override void Run(Context context) - { - context.packagingPatterns = - JsonConvert.DeserializeObject( - Utilities.ReadFile("./Build/Cake/packaging.json")); - // Various fixes - context.CopyFile("./DNN Platform/Components/DataAccessBlock/bin/Microsoft.ApplicationBlocks.Data.dll", - context.websiteFolder + "bin/Microsoft.ApplicationBlocks.Data.dll"); - context.CopyFiles("./DNN Platform/Components/Lucene.Net.Contrib/bin/Lucene.Net.Contrib.Analyzers.*", - context.websiteFolder + "bin/"); - context.CopyFile("./DNN Platform/Library/bin/PetaPoco.dll", context.websiteFolder + "bin/PetaPoco.dll"); - } -} - -[Dependency(typeof(CleanWebsite))] -[Dependency(typeof(GenerateSqlDataProvider))] -public sealed class CopyWebsite : FrostingTask -{ - public override void Run(Context context) - { - context.CopyFiles(context.GetFiles("./DNN Platform/Website/**/*"), context.websiteFolder, true); - } -} - -public sealed class CopyWebsiteBinFolder : FrostingTask -{ - public override void Run(Context context) - { - context.CopyFiles(context.GetFiles("./DNN Platform/Website/bin/**/*"), context.websiteFolder + "bin/", true); - } -} - -public sealed class CopyWebConfig : FrostingTask -{ - public override void Run(Context context) - { - context.CopyFile(context.websiteFolder + "release.config", context.websiteFolder + "web.config"); - } -} - -[Dependency(typeof(PreparePackaging))] -[Dependency(typeof(OtherPackages))] -public sealed class CreateInstall : FrostingTask -{ - public override void Run(Context context) - { - context.CreateDirectory(context.artifactsFolder); - var files = context.GetFilesByPatterns(context.websiteFolder, new string[] { "**/*" }, context.packagingPatterns.installExclude); - files.Add(context.GetFilesByPatterns(context.websiteFolder, context.packagingPatterns.installInclude)); - context.Information("Zipping {0} files for Install zip", files.Count); - var packageZip = string.Format(context.artifactsFolder + "DNN_Platform_{0}_Install.zip", context.GetBuildNumber()); - context.Zip(context.websiteFolder, packageZip, files); - } -} - -[Dependency(typeof(PreparePackaging))] -[Dependency(typeof(OtherPackages))] -[Dependency(typeof(CreateInstall))] // This is to ensure CreateUpgrade runs last and not in parallel, can be removed when we get to v10 where the telerik workaround is no longer needed -[Dependency(typeof(CreateSymbols))] // This is to ensure CreateUpgrade runs last and not in parallel, can be removed when we get to v10 where the telerik workaround is no longer needed -[Dependency(typeof(CreateDeploy))] // This is to ensure CreateUpgrade runs last and not in parallel, can be removed when we get to v10 where the telerik workaround is no longer needed -public sealed class CreateUpgrade : FrostingTask -{ - public override void Run(Context context) - { - this.RenameResourcesFor98xUpgrades(context); - context.CreateDirectory(context.artifactsFolder); - var excludes = new string[context.packagingPatterns.installExclude.Length + context.packagingPatterns.upgradeExclude.Length]; - context.packagingPatterns.installExclude.CopyTo(excludes, 0); - context.packagingPatterns.upgradeExclude.CopyTo(excludes, context.packagingPatterns.installExclude.Length); - var files = context.GetFilesByPatterns(context.websiteFolder, new string[] { "**/*" }, excludes); - files.Add(context.GetFiles("./Website/Install/Module/DNNCE_Website.Deprecated_*_Install.zip")); - context.Information("Zipping {0} files for Upgrade zip", files.Count); - var packageZip = string.Format(context.artifactsFolder + "DNN_Platform_{0}_Upgrade.zip", context.GetBuildNumber()); - context.Zip(context.websiteFolder, packageZip, files); - } - - [Obsolete( - "Workaround to support upgrades from 9.8.0 which may or may not still have Telerik installed." + - "This method is to be removed in v10.0.0 and we should also implement a solution to remove these .resources files" + - "from the available extensions to make sure people don't install them by mistake.")] - private void RenameResourcesFor98xUpgrades(Context context) - { - var telerikPackages = new string[] - { - $"{context.websiteFolder}Install/Module/DNNCE_DigitalAssetsManagement*.zip", - $"{context.websiteFolder}Install/Module/Telerik*.zip", - $"{context.websiteFolder}Install/Library/DNNCE_Web.Deprecated*.zip", - $"{context.websiteFolder}Install/Library/DNNCE_Website.Deprecated*.zip", - }; - - var filesToRename = context.GetFilesByPatterns(telerikPackages); - foreach (var fileToRename in filesToRename) - { - System.IO.File.Move(fileToRename.ToString(), fileToRename.ChangeExtension("resources").ToString()); - } - } -} - -[Dependency(typeof(PreparePackaging))] -[Dependency(typeof(OtherPackages))] -public sealed class CreateDeploy : FrostingTask -{ - public override void Run(Context context) - { - context.CreateDirectory(context.artifactsFolder); - var packageZip = string.Format(context.artifactsFolder + "DNN_Platform_{0}_Deploy.zip", context.GetBuildNumber()); - var deployFolder = "./DotNetNuke/"; - var deployDir = context.Directory(deployFolder); - System.IO.Directory.Move(context.websiteDir.Path.FullPath, deployDir.Path.FullPath); - var files = context.GetFilesByPatterns(deployFolder, new string[] { "**/*" }, context.packagingPatterns.installExclude); - files.Add(context.GetFilesByPatterns(deployFolder, context.packagingPatterns.installInclude)); - context.Zip("", packageZip, files); - Dnn.CakeUtils.Compression.AddFilesToZip(packageZip, "./Build/Deploy", context.GetFiles("./Build/Deploy/*"), true); - System.IO.Directory.Move(deployDir.Path.FullPath, context.websiteDir.Path.FullPath); - } -} - -[Dependency(typeof(PreparePackaging))] -[Dependency(typeof(OtherPackages))] -public sealed class CreateSymbols : FrostingTask -{ - public override void Run(Context context) - { - context.CreateDirectory(context.artifactsFolder); - var packageZip = string.Format(context.artifactsFolder + "DNN_Platform_{0}_Symbols.zip", context.GetBuildNumber()); - context.Zip("./Build/Symbols/", packageZip, context.GetFiles("./Build/Symbols/*")); - // Fix for WebUtility symbols missing from bin folder - context.CopyFiles(context.GetFiles("./DNN Platform/DotNetNuke.WebUtility/bin/DotNetNuke.WebUtility.*"), - context.websiteFolder + "bin/"); - var files = context.GetFilesByPatterns(context.websiteFolder, context.packagingPatterns.symbolsInclude, - context.packagingPatterns.symbolsExclude); - var resFile = Dnn.CakeUtils.Compression.ZipToBytes(context.websiteFolder.TrimEnd('/'), files); - Dnn.CakeUtils.Compression.AddBinaryFileToZip(packageZip, resFile, "Resources.zip", true); - } -} - -[Dependency(typeof(SetVersion))] -public sealed class GenerateSqlDataProvider : FrostingTask -{ - public override void Run(Context context) - { - var fileName = context.GetTwoDigitsVersionNumber().Substring(0, 8) + ".SqlDataProvider"; - var filePath = "./Dnn Platform/Website/Providers/DataProviders/SqlDataProvider/" + fileName; - if (System.IO.File.Exists(filePath)) - { - context.sqlDataProviderExists = true; - return; - } - - context.sqlDataProviderExists = false; - - using (System.IO.StreamWriter file = - new System.IO.StreamWriter(filePath, true)) - { - file.WriteLine("/************************************************************/"); - file.WriteLine("/***** SqlDataProvider *****/"); - file.WriteLine("/***** *****/"); - file.WriteLine("/***** *****/"); - file.WriteLine("/***** Note: To manually execute this script you must *****/"); - file.WriteLine("/***** perform a search and replace operation *****/"); - file.WriteLine("/***** for {databaseOwner} and {objectQualifier} *****/"); - file.WriteLine("/***** *****/"); - file.WriteLine("/************************************************************/"); - } - } -} - -[Dependency(typeof(CleanArtifacts))] -[Dependency(typeof(UpdateDnnManifests))] -[Dependency(typeof(CreateInstall))] -[Dependency(typeof(CreateUpgrade))] -[Dependency(typeof(CreateDeploy))] -[Dependency(typeof(CreateSymbols))] -public sealed class GeneratePackagesChecksums : FrostingTask -{ - public override void Run(Context context) - { - context.Information("Computing packages checksums..."); - - var sb = new StringBuilder(); - sb.AppendLine($"## MD5 Checksums") - .AppendLine($"| File | Checksum |") - .AppendLine($"|------------|----------|"); - - var files = context.GetFilesByPatterns(context.artifactsFolder, new string[] { "*.zip" }); - foreach (var file in files) - { - string hash; - var fileName = file.GetFilename(); - using (var md5 = MD5.Create()) - { - using (var stream = File.OpenRead(file.FullPath)) - { - var hashBytes = md5.ComputeHash(stream); - hash = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); - } - } - - sb.AppendLine($"| {fileName} | {hash} |"); - } - - sb.AppendLine(); - var filePath = Path.Combine(context.artifactsFolder, "checksums.md"); - File.WriteAllText(filePath, sb.ToString()); - - context.Information($"Saved checksums to {filePath}"); - } -} diff --git a/Build/Cake/settings.cs b/Build/Cake/settings.cs deleted file mode 100644 index 5965f316c04..00000000000 --- a/Build/Cake/settings.cs +++ /dev/null @@ -1,22 +0,0 @@ -// This file loads or creates the local settings file you can use to influence the build process -// and/or maintain a local DNN development site - -using Cake.Frosting; - -public class LocalSettings { - public string WebsitePath {get; set;} = ""; - public string WebsiteUrl {get; set;} = ""; - public string SaConnectionString {get; set;} = "server=(local);Trusted_Connection=True;"; - public string DnnConnectionString {get; set;} = ""; - public string DbOwner {get; set;} = "dbo"; - public string ObjectQualifier {get; set;} = ""; - public string DnnDatabaseName {get; set;} = "Dnn_Platform"; - public string DnnSqlUsername {get; set;} = ""; - public string DatabasePath {get; set;} = ""; - public string Version {get; set;} = "auto"; -} - -public sealed class CreateSettings : FrostingTask -{ - // Doesn't need to do anything as it's done automatically -} diff --git a/Build/Cake/testing.cs b/Build/Cake/testing.cs deleted file mode 100644 index 4879a5d5312..00000000000 --- a/Build/Cake/testing.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Cake.Common.Tools.NUnit; -using Cake.Frosting; - -[Dependency(typeof(Build))] -public sealed class RunUnitTests : FrostingTask -{ - public override void Run(Context context) - { - context.NUnit3("./src/**/bin/" + context.configuration + "/*.Test*.dll", new NUnit3Settings {NoResults = false}); - } -} diff --git a/Build/Cake/thirdparty.cs b/Build/Cake/thirdparty.cs deleted file mode 100644 index d4d6f588fc3..00000000000 --- a/Build/Cake/thirdparty.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Packaging of 3rd party stuff that is in our repository - -using System.Collections.Generic; -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Common.Xml; -using Cake.Frosting; -using Dnn.CakeUtils; -using Newtonsoft.Json; - -public class OtherPackage { - public string name {get; set;} - public string folder {get; set;} - public string destination {get; set;} - public string extension {get; set;} = "zip"; - public string[] excludes {get;set;} = new string[] {}; -} - -[Dependency(typeof(PackageNewtonsoft))] -public sealed class OtherPackages : FrostingTask -{ - public override void Run(Context context) - { - List otherPackages = - JsonConvert.DeserializeObject>( - Utilities.ReadFile("./Build/Cake/thirdparty.json")); - foreach (var op in otherPackages) - { - PackageOtherPackage(context, op); - } - } - - private void PackageOtherPackage(Context context, OtherPackage package) { - var srcFolder = "./" + package.folder; - var files = package.excludes.Length == 0 ? - context.GetFiles(srcFolder + "**/*") : - context.GetFilesByPatterns(srcFolder, new string[] {"**/*"}, package.excludes); - var version = "00.00.00"; - foreach (var dnn in context.GetFiles(srcFolder + "**/*.dnn")) { - version = context.XmlPeek(dnn, "dotnetnuke/packages/package/@version"); - } - context.CreateDirectory(package.destination); - var packageZip = - $"{context.websiteFolder}{package.destination}/{package.name}_{version}_Install.{package.extension}"; - context.Information("Packaging {0}", packageZip); - context.Zip(srcFolder, packageZip, files); - } -} - -public sealed class PackageNewtonsoft : FrostingTask -{ - public override void Run(Context context) - { - var version = "00.00.00"; - foreach (var assy in context.GetFiles(context.websiteFolder + "bin/Newtonsoft.Json.dll")) - { - version = System.Diagnostics.FileVersionInfo.GetVersionInfo(assy.FullPath).FileVersion; - } - - var packageZip = $"{context.websiteFolder}Install/Module/Newtonsoft.Json_{version}_Install.zip"; - context.Zip("./DNN Platform/Components/Newtonsoft", packageZip, context.GetFiles("./DNN Platform/Components/Newtonsoft/*")); - Dnn.CakeUtils.Compression.AddFilesToZip(packageZip, "Website", - context.GetFiles(context.websiteFolder + "bin/Newtonsoft.Json.dll"), true); - } -} diff --git a/Build/Cake/unit-tests.cs b/Build/Cake/unit-tests.cs deleted file mode 100644 index 6832e5cb91b..00000000000 --- a/Build/Cake/unit-tests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Linq; - -using Cake.Common.IO; -using Cake.Common.Tools.VSTest; -using Cake.Frosting; - -/// -/// Runs units tests on solution. Make sure to build the solution before running this task. -/// -public sealed class UnitTests : FrostingTask -{ - public override void Run(Context context) - { - var testAssemblies = context.GetFiles($@"**\bin\{context.configuration}\DotNetNuke.Tests.*.dll"); - testAssemblies += context.GetFiles($@"**\bin\{context.configuration}\Dnn.PersonaBar.*.Tests.dll"); - testAssemblies -= context.GetFiles(@"**\DotNetNuke.Tests.Utilities.dll"); - - // TODO: address issues to allow these tests to run - testAssemblies -= context.GetFiles(@"**\DotNetNuke.Tests.Integration.dll"); - testAssemblies -= context.GetFiles(@"**\DotNetNuke.Tests.Urls.dll"); - - var vsTestPath = context.GetFiles("tools/Microsoft.TestPlatform.16.8.0/tools/**/vstest.console.exe").First(); - context.VSTest( - testAssemblies, - new VSTestSettings - { - ToolPath = vsTestPath, - Logger = "trx", - Parallel = true, - EnableCodeCoverage = true, - TestAdapterPath = @"tools\NUnitTestAdapter.2.3.0\build" - }); - } -} - diff --git a/Build/Cake/version.cs b/Build/Cake/version.cs deleted file mode 100644 index 7743c930451..00000000000 --- a/Build/Cake/version.cs +++ /dev/null @@ -1,174 +0,0 @@ -// These tasks will set the right version for manifests and assemblies. Note you can -// control this by using custom settings - -using System; -using System.IO; -using System.Linq; -using System.Security.Cryptography; - -using Cake.Common.Diagnostics; -using Cake.Common.IO; -using Cake.Common.Tools.GitVersion; -using Cake.Core; -using Cake.Core.IO; -using Cake.FileHelpers; -using Cake.Frosting; -using Cake.XdtTransform; - -using Dnn.CakeUtils; - -using Newtonsoft.Json; - -using Path = System.IO.Path; - -[Dependency(typeof(SetVersion))] -public sealed class BuildServerSetVersion : FrostingTask -{ - public override void Run(Context context) - { - Console.WriteLine($"##vso[build.updatebuildnumber]{context.version.FullSemVer}.{context.buildId}"); - } -} - -public sealed class SetVersion : FrostingTask -{ - public override void Run(Context context) - { - if (context.Settings.Version == "auto") - { - context.version = context.GitVersion(); - context.buildNumber = context.version.LegacySemVerPadded; - } - else - { - context.version = new GitVersion(); - var assemblyInfo = new AssemblyInfo("SolutionInfo.cs"); - var requestedVersion = context.Settings.Version == "off" - ? assemblyInfo.GetVersion() - : new Version(context.Settings.Version); - context.version.Major = requestedVersion.Major; - context.version.Minor = requestedVersion.Minor; - context.version.Patch = requestedVersion.Build; - context.version.InformationalVersion = requestedVersion.ToString(3) + " Custom build"; - context.version.MajorMinorPatch = requestedVersion.ToString(3); - context.version.FullSemVer = requestedVersion.ToString(3); - if (requestedVersion.Revision != -1) - { - context.version.CommitsSinceVersionSource = requestedVersion.Revision; - context.version.InformationalVersion = requestedVersion.ToString(4) + " Custom build"; - } - - context.buildNumber = requestedVersion.ToString(3); - } - - context.Information(JsonConvert.SerializeObject(context.version)); - if (context.Settings.Version != "off") - { - Utilities.UpdateAssemblyInfoVersion( - new Version(context.version.Major, context.version.Minor, context.version.Patch, - context.version.CommitsSinceVersionSource ?? 0), - context.version.InformationalVersion, "SolutionInfo.cs"); - } - - context.Information("Informational Version : " + context.version.InformationalVersion); - context.productVersion = context.version.MajorMinorPatch; - context.Information("Product Version : " + context.productVersion); - context.Information("Build Number : " + context.buildNumber); - context.Information("The build Id is : " + context.buildId); - } -} - -[Dependency(typeof(SetVersion))] -[Dependency(typeof(SetPackageVersions))] -public sealed class UpdateDnnManifests : FrostingTask -{ - public override void Run(Context context) - { - var unversionedManifests = context.FileReadLines("./Build/Cake/unversionedManifests.txt"); - foreach (var file in context.GetFilesByPatterns(".", new[] {"**/*.dnn"}, unversionedManifests)) - { - if (context.Settings.Version == "off") return; - context.Information("Transforming: " + file); - var transformFile = context.File(Path.GetTempFileName()); - context.FileAppendText(transformFile, GetXdtTransformation(context)); - context.XdtTransformConfig(file, transformFile, file); - } - } - - public static string GetVersionString(Context context) - { - return $"{context.version.Major:00}.{context.version.Minor:00}.{context.version.Patch:00}"; - } - - public string GetXdtTransformation(Context context) - { - return $@" - - - - -"; - } -} - -[Dependency(typeof(SetVersion))] -public sealed class SetPackageVersions : FrostingTask -{ - public override void Run(Context context) - { - if (context.Settings.Version == "off") return; - var packages = context.GetFiles("./Dnn.AdminExperience/ClientSide/*.Web/package.json"); - packages.Add(context.GetFiles("./Dnn.AdminExperience/ClientSide/Dnn.React.Common/package.json")); - packages.Add(context.GetFiles("./Dnn.AdminExperience/ClientSide/*.Web/**/_exportables/package.json")); - packages.Add(context.GetFiles("./DNN Platform/Modules/ResourceManager/ResourceManager.Web/package.json")); - - // Set all package.json in Admin Experience to the current version and to consume the current (local) version of dnn-react-common. - foreach (var file in packages) - { - context.Information($"Updating {file} to version {context.version.FullSemVer}"); - context.ReplaceRegexInFiles(file.ToString(), @"""version"": "".*""", $@"""version"": ""{context.version.FullSemVer}"""); - context.ReplaceRegexInFiles(file.ToString(), @"""@dnnsoftware\/dnn-react-common"": "".*""", - $@"""@dnnsoftware/dnn-react-common"": ""{context.version.FullSemVer}"""); - } - } -} - -[Dependency(typeof(SetVersion))] -public sealed class GenerateSecurityAnalyzerChecksums : FrostingTask -{ - public override void Run(Context context) - { - context.Information("Generating default.aspx checksum..."); - var sourceFile = "./Dnn Platform/Website/Default.aspx"; - var destFile = "./Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Security/Resources/sums.resources"; - var hash = CalculateSha(sourceFile); - var content = $@" - -"; - File.WriteAllText(destFile, content); - } - - private static string CalculateSha(string filename) - { - using (var sha = SHA256.Create()) - { - using (var stream = File.OpenRead(filename)) - { - var hash = sha.ComputeHash(stream); - return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); - } - } - } - - public string GetXdtTransformation(Context context) - { - return $@" - - - - -"; - } -} diff --git a/Build/Context.cs b/Build/Context.cs new file mode 100644 index 00000000000..3f01c3916e9 --- /dev/null +++ b/Build/Context.cs @@ -0,0 +1,178 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build +{ + using System; + using System.IO; + + using Cake.Common; + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Common.IO.Paths; + using Cake.Common.Tools.GitVersion; + using Cake.Core; + using Cake.Frosting; + using Cake.Json; + + /// + public class Context : FrostingContext + { + /// Initializes a new instance of the class. + /// The base context. + public Context(ICakeContext context) + : base(context) + { + try + { + ////////////////////////////////////////////////////////////////////// + // ARGUMENTS + ////////////////////////////////////////////////////////////////////// + + this.Target = context.Argument("target", "Default"); + context.Information($"Target: {this.Target}"); + this.BuildConfiguration = context.Argument("configuration", "Release"); + context.Information($"Configuration: {this.BuildConfiguration}"); + + ////////////////////////////////////////////////////////////////////// + // PREPARATION + ////////////////////////////////////////////////////////////////////// + + // Define directories. + this.TempFolder = "./Temp/"; + this.TempDir = context.Directory(this.TempFolder); + context.Information($"TempDir: {this.TempDir}"); + + this.ArtifactsFolder = "./Artifacts/"; + this.ArtifactsDir = context.Directory(this.ArtifactsFolder); + context.Information($"ArtifactsDir: {this.ArtifactsDir}"); + + this.WebsiteFolder = "./Website/"; + this.WebsiteDir = context.Directory(this.WebsiteFolder); + context.Information($"WebsiteDir: {this.WebsiteDir}"); + + // Global information variables + this.IsRunningInCI = false; + + this.DnnSolutionPath = "./DNN_Platform.sln"; + + this.SqlDataProviderExists = false; + + const string settingsFile = "./settings.local.json"; + this.Settings = LoadSettings(context, settingsFile); + this.WriteSettings(context, settingsFile); + + this.BuildId = context.EnvironmentVariable("BUILD_BUILDID") ?? "0"; + context.Information($"BuildId: {this.BuildId}"); + this.BuildNumber = string.Empty; + this.ProductVersion = string.Empty; + } + catch (Exception exc) + { + this.Error(exc); + throw; + } + } + + /// Gets or sets the DNN version. + public string ProductVersion { get; set; } + + /// Gets or sets the DNN version in the build number format. + public string BuildNumber { get; set; } + + /// Gets or sets the build ID from the CI environment. + public string BuildId { get; set; } + + /// Gets or sets a value indicating whether the current version's SQL Data Provider file exists (e.g. 09.09.00.SqlDataProvider). + public bool SqlDataProviderExists { get; set; } + + /// Gets or sets the path to the DNN solution. + public string DnnSolutionPath { get; set; } + + /// Gets or sets a value indicating whether this build is running in a CI environment. + public bool IsRunningInCI { get; set; } + + /// Gets or sets the path to the website directory. + public ConvertableDirectoryPath WebsiteDir { get; set; } + + /// Gets or sets the relative path to the website directory. + public string WebsiteFolder { get; set; } + + /// Gets or sets the path to the artifacts directory. + public ConvertableDirectoryPath ArtifactsDir { get; set; } + + /// Gets or sets the relative path to the artifacts directory. + public string ArtifactsFolder { get; set; } + + /// Gets or sets the path to the temp directory. + public ConvertableDirectoryPath TempDir { get; set; } + + /// Gets or sets the relative path to the temp directory. + public string TempFolder { get; set; } + + /// Gets or sets the build configuration, e.g. Debug or Release. + public string BuildConfiguration { get; set; } + + /// Gets or sets the target. + public string Target { get; set; } + + /// Gets or sets the collection of glob patterns to include and exclude when packaging. + public PackagingPatterns PackagingPatterns { get; set; } + + /// Gets or sets the local dev site settings. + public LocalSettings Settings { get; set; } + + /// Gets or sets the resolved version information. + public GitVersion Version { get; set; } + + /// Gets the build number. + /// The version of the build. + public string GetBuildNumber() + { + return this.BuildNumber; + } + + /// Gets the build number with leading zeroes. + /// The version with leading zeroes. + public string GetTwoDigitsVersionNumber() + { + var fullVer = this.GetBuildNumber().Split('-')[0]; // Gets rid of the -unstable, -beta, etc. + var numbers = fullVer.Split('.'); + for (var i = 0; i < numbers.Length; i++) + { + if (numbers[i].Length < 2) + { + numbers[i] = "0" + numbers[i]; + } + } + + return string.Join(".", numbers); + } + + /// Gets the product version. + /// The version of DNN being built. + public string GetProductVersion() + { + return this.ProductVersion; + } + + private static LocalSettings LoadSettings(ICakeContext context, string settingsFile) + { + if (File.Exists(settingsFile)) + { + context.Information(log => log($"Loading settings from {Path.GetFullPath(settingsFile)}")); + return context.DeserializeJsonFromFile(settingsFile); + } + + context.Information(log => log($"Did not find settings file {Path.GetFullPath(settingsFile)}")); + return new LocalSettings(); + } + + private void WriteSettings(ICakeContext context, string settingsFile) + { + context.SerializeJsonToPrettyFile(settingsFile, this.Settings); + context.Information(log => log($"Saved settings to {Path.GetFullPath(settingsFile)}")); + context.Debug(log => log($"Settings: {context.SerializeJson(this.Settings).Replace("{", "{{")}")); + } + } +} diff --git a/Build/Lifetime.cs b/Build/Lifetime.cs new file mode 100644 index 00000000000..cb574da59eb --- /dev/null +++ b/Build/Lifetime.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Build +{ + using Cake.Common; + using Cake.Common.Diagnostics; + using Cake.Core; + using Cake.Core.IO; + using Cake.Frosting; + + /// + public sealed class Lifetime : FrostingLifetime + { + /// + public override void Setup(Context context) + { + context.IsRunningInCI = context.HasEnvironmentVariable("TF_BUILD"); + context.Information("Is Running in CI : {0}", context.IsRunningInCI); + if (context.Settings.Version == "auto" && !context.IsRunningInCI) + { + // Temporarily commit all changes to prevent checking in scripted changes like versioning. + Git(context, "add ."); + Git(context, "commit --allow-empty -m 'backup'"); + } + } + + /// + public override void Teardown(Context context, ITeardownContext info) + { + if (context.Settings.Version == "auto" && !context.IsRunningInCI) + { + // Undoes the script changes to all tracked files. + Git(context, "reset --hard"); + + // Undoes the setup commit keeping file states as before this build script ran. + Git(context, "reset HEAD^"); + } + } + + private static void Git(ICakeContext context, string arguments) + { + context.Information($"git ${arguments}"); + using (var process = context.StartAndReturnProcess("git", new ProcessSettings { Arguments = arguments, })) + { + process.WaitForExit(); + } + } + } +} diff --git a/Build/LocalSettings.cs b/Build/LocalSettings.cs new file mode 100644 index 00000000000..7149575b931 --- /dev/null +++ b/Build/LocalSettings.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build +{ + /// Settings about a local dev site. + public class LocalSettings + { + /// Gets or sets the path to the website. + public string WebsitePath { get; set; } = string.Empty; + + /// Gets or sets the URL for the website. + public string WebsiteUrl { get; set; } = string.Empty; + + /// Gets or sets the admin connection string for the database. + public string SaConnectionString { get; set; } = "server=(local);Trusted_Connection=True;"; + + /// Gets or sets the website connection string for the database. + public string DnnConnectionString { get; set; } = string.Empty; + + /// Gets or sets the default database schema. + public string DbOwner { get; set; } = "dbo"; + + /// Gets or sets the object prefix. + public string ObjectQualifier { get; set; } = string.Empty; + + /// Gets or sets the database name. + public string DnnDatabaseName { get; set; } = "Dnn_Platform"; + + /// Gets or sets the SQL username with access to the database. + public string DnnSqlUsername { get; set; } = string.Empty; + + /// Gets or sets the path to the database files. + public string DatabasePath { get; set; } = string.Empty; + + /// Gets or sets the version to use for the build. + public string Version { get; set; } = "auto"; + } +} diff --git a/Build/PackagingPatterns.cs b/Build/PackagingPatterns.cs new file mode 100644 index 00000000000..b05c5f1b0a2 --- /dev/null +++ b/Build/PackagingPatterns.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build +{ + /// The patterns of files to include and exclude from packaging. + public class PackagingPatterns + { + /// Gets or sets a set of files to exclude from the install package. + public string[] InstallExclude { get; set; } + + /// Gets or sets a set of files to include from the install package. + public string[] InstallInclude { get; set; } + + /// Gets or sets a set of files to exclude from the upgrade package. + public string[] UpgradeExclude { get; set; } + + /// Gets or sets a set of files to include from the symbols package. + public string[] SymbolsInclude { get; set; } + + /// Gets or sets a set of files to exclude from the symbols package. + public string[] SymbolsExclude { get; set; } + } +} diff --git a/Build/Program.cs b/Build/Program.cs index 218d950a713..cdf910bd566 100644 --- a/Build/Program.cs +++ b/Build/Program.cs @@ -1,21 +1,31 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build +{ + using System; -using Cake.AzurePipelines.Module; -using Cake.Frosting; + using Cake.AzurePipelines.Module; + using Cake.Frosting; -public class Program -{ - public static int Main(string[] args) + /// Runs the build process. + public class Program { - return new CakeHost() - .UseContext() - .UseLifetime() - .UseWorkingDirectory("..") - .UseModule() - .InstallTool(new Uri("nuget:?package=GitVersion.CommandLine&version=5.0.1")) - .InstallTool(new Uri("nuget:?package=Microsoft.TestPlatform&version=16.8.0")) - .InstallTool(new Uri("nuget:?package=NUnitTestAdapter&version=2.3.0")) - .InstallTool(new Uri("nuget:?package=NuGet.CommandLine&version=5.8.0")) - .Run(args); + /// Runs the build process. + /// The arguments from the command line. + /// A status code. + public static int Main(string[] args) + { + return new CakeHost() + .UseContext() + .UseLifetime() + .UseWorkingDirectory("..") + .UseModule() + .InstallTool(new Uri("nuget:?package=GitVersion.CommandLine&version=5.0.1")) + .InstallTool(new Uri("nuget:?package=Microsoft.TestPlatform&version=16.8.0")) + .InstallTool(new Uri("nuget:?package=NUnitTestAdapter&version=2.3.0")) + .InstallTool(new Uri("nuget:?package=NuGet.CommandLine&version=5.8.0")) + .Run(args); + } } } diff --git a/Build/Tasks/Build.cs b/Build/Tasks/Build.cs new file mode 100644 index 00000000000..db33735f3ca --- /dev/null +++ b/Build/Tasks/Build.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Tools.MSBuild; + using Cake.Frosting; + + using DotNetNuke.Build; + + /// A cake task to compile the platform. + [Dependency(typeof(CleanWebsite))] + [Dependency(typeof(RestoreNuGetPackages))] + public sealed class Build : FrostingTask + { + /// + public override void Run(Context context) + { + context.MSBuild(context.DnnSolutionPath, settings => settings.WithTarget("Clean")); + + var buildSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) + .SetPlatformTarget(PlatformTarget.MSIL) + .WithTarget("Rebuild") + .SetMaxCpuCount(4) + .WithProperty("SourceLinkCreate", "true"); + context.MSBuild(context.DnnSolutionPath, buildSettings); + } + } +} diff --git a/Build/Tasks/BuildAll.cs b/Build/Tasks/BuildAll.cs new file mode 100644 index 00000000000..7e39e9e6f95 --- /dev/null +++ b/Build/Tasks/BuildAll.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to compile the platform and create all of the packages. + /// This is the task run during CI. + [Dependency(typeof(CleanArtifacts))] + [Dependency(typeof(UpdateDnnManifests))] + [Dependency(typeof(GenerateSecurityAnalyzerChecksums))] + [Dependency(typeof(SetPackageVersions))] + [Dependency(typeof(CreateInstall))] + [Dependency(typeof(CreateUpgrade))] + [Dependency(typeof(CreateDeploy))] + [Dependency(typeof(CreateSymbols))] + [Dependency(typeof(CreateNugetPackages))] + [Dependency(typeof(GeneratePackagesChecksums))] + public sealed class BuildAll : FrostingTask + { + /// + public override void Run(Context context) + { + this.RevertSqlDataProvider(context); + } + + private void RevertSqlDataProvider(Context context) + { + var fileName = context.GetTwoDigitsVersionNumber() + ".SqlDataProvider"; + var filePath = "./Dnn Platform/Website/Providers/DataProviders/SqlDataProvider/" + fileName; + if (!context.SqlDataProviderExists && System.IO.File.Exists(filePath)) + { + System.IO.File.Delete(filePath); + } + } + } +} diff --git a/Build/Tasks/BuildServerSetVersion.cs b/Build/Tasks/BuildServerSetVersion.cs new file mode 100644 index 00000000000..d0ac4b28ba2 --- /dev/null +++ b/Build/Tasks/BuildServerSetVersion.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to update the build number in CI. + [Dependency(typeof(SetVersion))] + public sealed class BuildServerSetVersion : FrostingTask + { + /// + public override void Run(Context context) + { + Console.WriteLine($"##vso[build.updatebuildnumber]{context.Version.FullSemVer}.{context.BuildId}"); + } + } +} diff --git a/Build/Tasks/BuildToTempFolder.cs b/Build/Tasks/BuildToTempFolder.cs new file mode 100644 index 00000000000..ae1133b5aa8 --- /dev/null +++ b/Build/Tasks/BuildToTempFolder.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to build the platform. + [Dependency(typeof(SetVersion))] + [Dependency(typeof(UpdateDnnManifests))] + [Dependency(typeof(ResetDatabase))] + [Dependency(typeof(PreparePackaging))] + [Dependency(typeof(OtherPackages))] + public sealed class BuildToTempFolder : FrostingTask + { + } +} diff --git a/Build/Tasks/BuildWithDatabase.cs b/Build/Tasks/BuildWithDatabase.cs new file mode 100644 index 00000000000..367cd96ecb1 --- /dev/null +++ b/Build/Tasks/BuildWithDatabase.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to compile the platform and create a localdb database. + [Dependency(typeof(CleanArtifacts))] + [Dependency(typeof(UpdateDnnManifests))] + [Dependency(typeof(CreateInstall))] + [Dependency(typeof(CreateUpgrade))] + [Dependency(typeof(CreateDeploy))] + [Dependency(typeof(CreateSymbols))] + [Dependency(typeof(CreateDatabase))] + public sealed class BuildWithDatabase : FrostingTask + { + } +} diff --git a/Build/Tasks/CleanArtifacts.cs b/Build/Tasks/CleanArtifacts.cs new file mode 100644 index 00000000000..6c2b4dcac3a --- /dev/null +++ b/Build/Tasks/CleanArtifacts.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + using DotNetNuke.Build; + + /// A cake task to clean the artifacts directory. + public sealed class CleanArtifacts : FrostingTask + { + /// + public override void Run(Context context) + { + context.CleanDirectory(context.ArtifactsDir); + } + } +} diff --git a/Build/Tasks/CleanTemp.cs b/Build/Tasks/CleanTemp.cs new file mode 100644 index 00000000000..18a3c829e17 --- /dev/null +++ b/Build/Tasks/CleanTemp.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + using DotNetNuke.Build; + + /// A cake task to clean the temp directory. + public sealed class CleanTemp : FrostingTask + { + /// + public override void Run(Context context) + { + context.CleanDirectory(context.TempDir); + } + } +} diff --git a/Build/Tasks/CleanWebsite.cs b/Build/Tasks/CleanWebsite.cs new file mode 100644 index 00000000000..45744ff57f4 --- /dev/null +++ b/Build/Tasks/CleanWebsite.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + using DotNetNuke.Build; + + /// A cake task to clean the website directory. + public sealed class CleanWebsite : FrostingTask + { + /// + public override void Run(Context context) + { + context.CleanDirectory(context.WebsiteDir); + } + } +} diff --git a/Build/Tasks/CopyToDevSite.cs b/Build/Tasks/CopyToDevSite.cs new file mode 100644 index 00000000000..b7667f6c6b0 --- /dev/null +++ b/Build/Tasks/CopyToDevSite.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to copy the built website to the dev site's directory. + public sealed class CopyToDevSite : FrostingTask + { + /// + public override void Run(Context context) + { + context.CleanDirectory(context.Settings.WebsitePath); + var files = context.GetFilesByPatterns(context.WebsiteFolder, new[] { "**/*" }, context.PackagingPatterns.InstallExclude); + files.Add(context.GetFilesByPatterns(context.WebsiteFolder, context.PackagingPatterns.InstallInclude)); + context.Information("Copying {0} files to {1}", files.Count, context.Settings.WebsitePath); + context.CopyFiles(files, context.Settings.WebsitePath, true); + } + } +} diff --git a/Build/Tasks/CopyWebConfig.cs b/Build/Tasks/CopyWebConfig.cs new file mode 100644 index 00000000000..8ddffe455d3 --- /dev/null +++ b/Build/Tasks/CopyWebConfig.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + /// A cake task to copy the release.config to the web.config. + public sealed class CopyWebConfig : FrostingTask + { + /// + public override void Run(Context context) + { + context.CopyFile(context.WebsiteFolder + "release.config", context.WebsiteFolder + "web.config"); + } + } +} diff --git a/Build/Tasks/CopyWebConfigToDevSite.cs b/Build/Tasks/CopyWebConfigToDevSite.cs new file mode 100644 index 00000000000..fe6af0a11a9 --- /dev/null +++ b/Build/Tasks/CopyWebConfigToDevSite.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Common.Xml; + using Cake.FileHelpers; + using Cake.Frosting; + + /// A cake task to copy the web.config file to the local dev site with appropriate transformations. + public sealed class CopyWebConfigToDevSite : FrostingTask + { + /// + public override void Run(Context context) + { + var conf = context.FileReadText("./Website/web.config"); + var transFile = "./Build/Tasks/webconfig-transform.local.xsl"; + if (!context.FileExists(transFile)) + { + transFile = "./Build/Tasks/webconfig-transform.xsl"; + } + + var trans = context.FileReadText(transFile); + trans = trans.Replace("{ConnectionString}", context.Settings.DnnConnectionString) + .Replace("{DbOwner}", context.Settings.DbOwner) + .Replace("{ObjectQualifier}", context.Settings.ObjectQualifier); + var res = context.XmlTransform(trans, conf); + var webConfig = context.File(System.IO.Path.Combine(context.Settings.WebsitePath, "web.config")); + context.FileWriteText(webConfig, res); + } + } +} diff --git a/Build/Tasks/CopyWebsite.cs b/Build/Tasks/CopyWebsite.cs new file mode 100644 index 00000000000..016df4af832 --- /dev/null +++ b/Build/Tasks/CopyWebsite.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + /// A cake task to copy the built website folder. + [Dependency(typeof(CleanWebsite))] + [Dependency(typeof(GenerateSqlDataProvider))] + public sealed class CopyWebsite : FrostingTask + { + /// + public override void Run(Context context) + { + context.CopyFiles(context.GetFiles("./DNN Platform/Website/**/*"), context.WebsiteFolder, true); + } + } +} diff --git a/Build/Tasks/CopyWebsiteBinFolder.cs b/Build/Tasks/CopyWebsiteBinFolder.cs new file mode 100644 index 00000000000..6e3f6058f0c --- /dev/null +++ b/Build/Tasks/CopyWebsiteBinFolder.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + /// A cake task to copy files into the website's bin directory. + public sealed class CopyWebsiteBinFolder : FrostingTask + { + /// + public override void Run(Context context) + { + context.CopyFiles( + context.GetFiles("./DNN Platform/Website/bin/**/*"), + context.WebsiteFolder + "bin/", + true); + } + } +} diff --git a/Build/Tasks/CreateDatabase.cs b/Build/Tasks/CreateDatabase.cs new file mode 100644 index 00000000000..1947b1772e3 --- /dev/null +++ b/Build/Tasks/CreateDatabase.cs @@ -0,0 +1,171 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Common.Xml; + using Cake.Frosting; + + /// A cake task to crete a localdb database named Dnn_Platform. + public sealed class CreateDatabase : FrostingTask + { + private string connectionString = @"server=(localdb)\MSSQLLocalDB"; + + /// + public override void Run(Context context) + { + var deleteScript = "if db_id('Dnn_Platform') is not null DROP DATABASE Dnn_Platform;"; + + context.Information("Dropping LocalDb: {0}", this.ExecuteSqlScript(context, deleteScript)); + + var createDbScript = string.Format( + @" + CREATE DATABASE + [Dnn_Platform] + ON PRIMARY ( + NAME=Dnn_data, + FILENAME = '{0}\Dnn_Platform.mdf' + ) + LOG ON ( + NAME=Dnn_log, + FILENAME = '{0}\Dnn_Platform.ldf' + )", + context.TempDir); + var createDbStatus = this.ExecuteSqlScript(context, createDbScript); + context.Information("Created LocalDb: {0}", createDbStatus); + + if (createDbStatus) + { + this.connectionString = @"server=(localdb)\MSSQLLocalDB;Database=Dnn_Platform;Trusted_Connection=True;"; + + var schemaScriptName = context.XmlPeek( + "./Website/Install/DotNetNuke.install.config.resources", + "/dotnetnuke/scripts/script[@name='Schema']"); + var dataScriptName = context.XmlPeek( + "./Website/Install/DotNetNuke.install.config.resources", + "/dotnetnuke/scripts/script[@name='Data']"); + var schemaVersion = context.XmlPeek( + "./Website/Install/DotNetNuke.install.config.resources", + "/dotnetnuke/version"); + + // ##################################################################### + // run initial schema first + // ##################################################################### + var fileContents = System.IO.File.ReadAllText( + "./Website/Providers/DataProviders/SqlDataProvider/" + + schemaScriptName.ToString() + + ".SqlDataProvider"); + + var sqlDelimiterRegex = new System.Text.RegularExpressions.Regex( + "(?<=(?:[^\\w]+|^))GO(?=(?: |\\t)*?(?:\\r?\\n|$))", + System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline); + string[] sqlStatements = sqlDelimiterRegex.Split(fileContents); + foreach (string statement in sqlStatements) + { + this.ExecuteSqlScript(context, statement); + } + + context.Information("Initial Schema for v{0}", schemaVersion); + + // ##################################################################### + // populate with data next + // ##################################################################### + fileContents = System.IO.File.ReadAllText( + "./Website/Providers/DataProviders/SqlDataProvider/" + + dataScriptName.ToString() + + ".SqlDataProvider"); + + sqlStatements = sqlDelimiterRegex.Split(fileContents); + foreach (string statement in sqlStatements) + { + context.Information("Test Data: {1}", schemaVersion, this.ExecuteSqlScript(context, statement)); + } + + var createDummyPortalStatement = + "INSERT [dbo].[dnn_Portals] ([ExpiryDate], [UserRegistration], [BannerAdvertising], [AdministratorId], [Currency], [HostFee], [HostSpace], [AdministratorRoleId], [RegisteredRoleId], [GUID], [PaymentProcessor], [ProcessorUserId], [ProcessorPassword], [SiteLogHistory], [DefaultLanguage], [TimezoneOffset], [HomeDirectory], [PageQuota], [UserQuota], [CreatedByUserID], [CreatedOnDate], [LastModifiedByUserID], [LastModifiedOnDate], [PortalGroupID]) VALUES (NULL, 1, 0, 1, N'USD', 0.0000, 0, 0, 1, N'97debbc9-4643-4bd9-b0a0-b14170b38b0f', N'PayPal', NULL, NULL, 0, N'en-US', -8, N'Portals/0', 0, 0, -1, CAST(N'2015-02-05 14:49:37.873' AS DateTime), 1, CAST(N'2015-10-13 11:08:13.513' AS DateTime), -1)"; + + context.Information( + "Test Portal: {1}", + schemaVersion, + this.ExecuteSqlScript(context, createDummyPortalStatement)); + + // ##################################################################### + // now get all other SqlDataProvider files and run those.... + // ##################################################################### + var files = context.GetFiles("./Website/Providers/DataProviders/SqlDataProvider/*.SqlDataProvider"); + + var currentFileToProcess = string.Empty; + + foreach (var file in files) + { + currentFileToProcess = file.GetFilenameWithoutExtension() + .ToString(); + var fileBits = currentFileToProcess.Split('.'); + + int firstBit; + int secondBit; + int thirdBit; + + if (int.TryParse(fileBits[0], out firstBit) + && int.TryParse(fileBits[1], out secondBit) + && int.TryParse(fileBits[2], out thirdBit)) + { + var schemaVersionBits = schemaVersion.Split('.'); + + int schemaFirstBit = int.Parse(schemaVersionBits[0]); + int schemaSecondBit = int.Parse(schemaVersionBits[1]); + int schemaThirdBit = int.Parse(schemaVersionBits[2]); + + if ((firstBit == schemaFirstBit && (secondBit >= schemaSecondBit && thirdBit >= schemaThirdBit)) + || firstBit > schemaFirstBit) + { + context.Information("Updated to v{0}", currentFileToProcess); + + fileContents = System.IO.File.ReadAllText(file.ToString()); + + sqlStatements = sqlDelimiterRegex.Split(fileContents); + foreach (string statement in sqlStatements) + { + var statementSuccess = this.ExecuteSqlScript(context, statement); + } + } + } + } + } + else + { + context.Information("An Error has occured. Please review and try again."); + } + } + + private bool ExecuteSqlScript(Context context, string scriptStatement) + { + try + { + using (var connection = new System.Data.SqlClient.SqlConnection(this.connectionString)) + { + connection.Open(); + + var cmdText = scriptStatement.Replace("{databaseOwner}", "dbo.").Replace("{objectQualifier}", "dnn_"); + var command = new System.Data.SqlClient.SqlCommand(cmdText, connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + } + catch (Exception err) + { + context.Error(err); + + return false; + } + + return true; + } + } +} diff --git a/Build/Tasks/CreateDeploy.cs b/Build/Tasks/CreateDeploy.cs new file mode 100644 index 00000000000..266e512040a --- /dev/null +++ b/Build/Tasks/CreateDeploy.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.IO; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to crete the Deploy package. + [Dependency(typeof(PreparePackaging))] + [Dependency(typeof(OtherPackages))] + public sealed class CreateDeploy : FrostingTask + { + /// + public override void Run(Context context) + { + context.CreateDirectory(context.ArtifactsFolder); + var packageZip = $"{context.ArtifactsFolder}DNN_Platform_{context.GetBuildNumber()}_Deploy.zip"; + + const string deployFolder = "./DotNetNuke/"; + var deployDir = context.Directory(deployFolder); + Directory.Move(context.WebsiteDir.Path.FullPath, deployDir.Path.FullPath); + var files = context.GetFilesByPatterns(deployFolder, new[] { "**/*" }, context.PackagingPatterns.InstallExclude); + files.Add(context.GetFilesByPatterns(deployFolder, context.PackagingPatterns.InstallInclude)); + context.Zip(string.Empty, packageZip, files); + context.AddFilesToZip(packageZip, "./Build/Deploy", context.GetFiles("./Build/Deploy/*"), append: true); + Directory.Move(deployDir.Path.FullPath, context.WebsiteDir.Path.FullPath); + } + } +} diff --git a/Build/Tasks/CreateInstall.cs b/Build/Tasks/CreateInstall.cs new file mode 100644 index 00000000000..5e9cd80902a --- /dev/null +++ b/Build/Tasks/CreateInstall.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to create the Install package. + [Dependency(typeof(PreparePackaging))] + [Dependency(typeof(OtherPackages))] + public sealed class CreateInstall : FrostingTask + { + /// + public override void Run(Context context) + { + context.CreateDirectory(context.ArtifactsFolder); + var files = context.GetFilesByPatterns(context.WebsiteFolder, new[] { "**/*" }, context.PackagingPatterns.InstallExclude); + files.Add(context.GetFilesByPatterns(context.WebsiteFolder, context.PackagingPatterns.InstallInclude)); + context.Information("Zipping {0} files for Install zip", files.Count); + + var packageZip = $"{context.ArtifactsFolder}DNN_Platform_{context.GetBuildNumber()}_Install.zip"; + context.Zip(context.WebsiteFolder, packageZip, files); + } + } +} diff --git a/Build/Tasks/CreateNugetPackages.cs b/Build/Tasks/CreateNugetPackages.cs new file mode 100644 index 00000000000..21baad83432 --- /dev/null +++ b/Build/Tasks/CreateNugetPackages.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Common.Tools.NuGet; + using Cake.Common.Tools.NuGet.Pack; + using Cake.Frosting; + + using DotNetNuke.Build; + + /// A cake task to create the platform's NuGet packages. + [Dependency(typeof(PreparePackaging))] + public sealed class CreateNugetPackages : FrostingTask + { + /// + public override void Run(Context context) + { + // look for solutions and start building them + var nuspecFiles = context.GetFiles("./Build/Tools/NuGet/*.nuspec"); + + context.Information("Found {0} nuspec files.", nuspecFiles.Count); + + // basic nuget package configuration + var nuGetPackSettings = new NuGetPackSettings + { + Version = context.GetBuildNumber(), + OutputDirectory = @"./Artifacts/", + IncludeReferencedProjects = true, + Symbols = true, + Properties = new Dictionary { { "Configuration", "Release" } }, + }; + + // loop through each nuspec file and create the package + foreach (var spec in nuspecFiles) + { + var specPath = spec.ToString(); + + context.Information("Starting to pack: {0}", specPath); + context.NuGetPack(specPath, nuGetPackSettings); + } + } + } +} diff --git a/Build/Tasks/CreateSettings.cs b/Build/Tasks/CreateSettings.cs new file mode 100644 index 00000000000..69db8f30836 --- /dev/null +++ b/Build/Tasks/CreateSettings.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to create the settings.local.json file. + public sealed class CreateSettings : FrostingTask + { + // Doesn't need to do anything as it's done automatically + } +} diff --git a/Build/Tasks/CreateSymbols.cs b/Build/Tasks/CreateSymbols.cs new file mode 100644 index 00000000000..2fb92e75906 --- /dev/null +++ b/Build/Tasks/CreateSymbols.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to create the Symbols package. + [Dependency(typeof(PreparePackaging))] + [Dependency(typeof(OtherPackages))] + public sealed class CreateSymbols : FrostingTask + { + /// + public override void Run(Context context) + { + context.CreateDirectory(context.ArtifactsFolder); + var packageZip = $"{context.ArtifactsFolder}DNN_Platform_{context.GetBuildNumber()}_Symbols.zip"; + context.Zip("./Build/Symbols/", packageZip, context.GetFiles("./Build/Symbols/*")); + + // Fix for WebUtility symbols missing from bin folder + context.CopyFiles( + context.GetFiles("./DNN Platform/DotNetNuke.WebUtility/bin/DotNetNuke.WebUtility.*"), + context.WebsiteFolder + "bin/"); + var files = context.GetFilesByPatterns( + context.WebsiteFolder, + context.PackagingPatterns.SymbolsInclude, + context.PackagingPatterns.SymbolsExclude); + var resFile = context.ZipToBytes(context.WebsiteFolder.TrimEnd('/'), files); + context.AddBinaryFileToZip(packageZip, resFile, "Resources.zip", true); + } + } +} diff --git a/Build/Tasks/CreateUpgrade.cs b/Build/Tasks/CreateUpgrade.cs new file mode 100644 index 00000000000..3976db0f02e --- /dev/null +++ b/Build/Tasks/CreateUpgrade.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.IO; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to create the Upgrade package. + [Dependency(typeof(PreparePackaging))] + [Dependency(typeof(OtherPackages))] + [Dependency(typeof(CreateInstall))] // This is to ensure CreateUpgrade runs last and not in parallel, can be removed when we get to v10 where the telerik workaround is no longer needed + [Dependency(typeof(CreateSymbols))] // This is to ensure CreateUpgrade runs last and not in parallel, can be removed when we get to v10 where the telerik workaround is no longer needed + [Dependency(typeof(CreateDeploy))] // This is to ensure CreateUpgrade runs last and not in parallel, can be removed when we get to v10 where the telerik workaround is no longer needed + public sealed class CreateUpgrade : FrostingTask + { + /// + public override void Run(Context context) + { + this.RenameResourcesFor98xUpgrades(context); + context.CreateDirectory(context.ArtifactsFolder); + var excludes = new string[context.PackagingPatterns.InstallExclude.Length + context.PackagingPatterns.UpgradeExclude.Length]; + context.PackagingPatterns.InstallExclude.CopyTo(excludes, 0); + context.PackagingPatterns.UpgradeExclude.CopyTo(excludes, context.PackagingPatterns.InstallExclude.Length); + var files = context.GetFilesByPatterns(context.WebsiteFolder, new[] { "**/*" }, excludes); + files.Add(context.GetFiles("./Website/Install/Module/DNNCE_Website.Deprecated_*_Install.zip")); + context.Information("Zipping {0} files for Upgrade zip", files.Count); + + var packageZip = $"{context.ArtifactsFolder}DNN_Platform_{context.GetBuildNumber()}_Upgrade.zip"; + context.Zip(context.WebsiteFolder, packageZip, files); + } + + [Obsolete( + "Workaround to support upgrades from 9.8.0 which may or may not still have Telerik installed." + + "This method is to be removed in v10.0.0 and we should also implement a solution to remove these .resources files" + + "from the available extensions to make sure people don't install them by mistake.")] + private void RenameResourcesFor98xUpgrades(Context context) + { + var telerikPackages = new[] + { + $"{context.WebsiteFolder}Install/Module/DNNCE_DigitalAssetsManagement*.zip", + $"{context.WebsiteFolder}Install/Module/Telerik*.zip", + $"{context.WebsiteFolder}Install/Library/DNNCE_Web.Deprecated*.zip", + $"{context.WebsiteFolder}Install/Library/DNNCE_Website.Deprecated*.zip", + }; + + var filesToRename = context.GetFilesByPatterns(telerikPackages); + foreach (var fileToRename in filesToRename) + { + File.Move( + fileToRename.ToString(), + fileToRename.ChangeExtension("resources").ToString()); + } + } + } +} diff --git a/Build/Tasks/Default.cs b/Build/Tasks/Default.cs new file mode 100644 index 00000000000..74aedacfec3 --- /dev/null +++ b/Build/Tasks/Default.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to build the platform and create packages. + /// This is the default Cake target if no target is supplied. + [Dependency(typeof(CleanArtifacts))] + [Dependency(typeof(UpdateDnnManifests))] + [Dependency(typeof(CreateInstall))] + [Dependency(typeof(CreateUpgrade))] + [Dependency(typeof(CreateDeploy))] + [Dependency(typeof(CreateSymbols))] + public sealed class Default : FrostingTask + { + } +} diff --git a/Build/Tasks/GeneratePackagesChecksums.cs b/Build/Tasks/GeneratePackagesChecksums.cs new file mode 100644 index 00000000000..09a71c295b8 --- /dev/null +++ b/Build/Tasks/GeneratePackagesChecksums.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.IO; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + + using Cake.Common.Diagnostics; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to generate a checksums.md file with the artifact checksums. + [Dependency(typeof(CleanArtifacts))] + [Dependency(typeof(UpdateDnnManifests))] + [Dependency(typeof(CreateInstall))] + [Dependency(typeof(CreateUpgrade))] + [Dependency(typeof(CreateDeploy))] + [Dependency(typeof(CreateSymbols))] + public sealed class GeneratePackagesChecksums : FrostingTask + { + /// + public override void Run(Context context) + { + context.Information("Computing packages checksums..."); + + var sb = new StringBuilder(); + sb.AppendLine($"## MD5 Checksums") + .AppendLine($"| File | Checksum |") + .AppendLine($"|------------|----------|"); + + var files = context.GetFilesByPatterns(context.ArtifactsFolder, new[] { "*.zip" }); + foreach (var file in files) + { + string hash; + var fileName = file.GetFilename(); + using (var md5 = MD5.Create()) + { + using (var stream = File.OpenRead(file.FullPath)) + { + var hashBytes = md5.ComputeHash(stream); + hash = BitConverter.ToString(hashBytes) + .Replace("-", string.Empty) + .ToLowerInvariant(); + } + } + + sb.AppendLine($"| {fileName} | {hash} |"); + } + + sb.AppendLine(); + var filePath = Path.Combine(context.ArtifactsFolder, "checksums.md"); + File.WriteAllText(filePath, sb.ToString()); + + context.Information($"Saved checksums to {filePath}"); + } + } +} diff --git a/Build/Tasks/GenerateSecurityAnalyzerChecksums.cs b/Build/Tasks/GenerateSecurityAnalyzerChecksums.cs new file mode 100644 index 00000000000..877a565f7bd --- /dev/null +++ b/Build/Tasks/GenerateSecurityAnalyzerChecksums.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.IO; + using System.Linq; + using System.Security.Cryptography; + + using Cake.Common.Diagnostics; + using Cake.Frosting; + + /// A cake task to generate the Default.aspx checksum for the Security Analyzer. + [Dependency(typeof(SetVersion))] + public sealed class GenerateSecurityAnalyzerChecksums : FrostingTask + { + /// + public override void Run(Context context) + { + context.Information("Generating default.aspx checksum..."); + const string sourceFile = "./Dnn Platform/Website/Default.aspx"; + const string destFile = "./Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Security/Resources/sums.resources"; + var hash = CalculateSha(sourceFile); + var content = $@" + +"; + File.WriteAllText(destFile, content); + } + + private static string CalculateSha(string filename) + { + using (var sha = SHA256.Create()) + { + using (var stream = File.OpenRead(filename)) + { + var hash = sha.ComputeHash(stream); + return BitConverter.ToString(hash) + .Replace("-", string.Empty) + .ToLowerInvariant(); + } + } + } + } +} diff --git a/Build/Tasks/GenerateSqlDataProvider.cs b/Build/Tasks/GenerateSqlDataProvider.cs new file mode 100644 index 00000000000..6212713a43e --- /dev/null +++ b/Build/Tasks/GenerateSqlDataProvider.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.IO; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to generate a SQL Data Provider script if it doesn't exist. + [Dependency(typeof(SetVersion))] + public sealed class GenerateSqlDataProvider : FrostingTask + { + /// + public override void Run(Context context) + { + var fileName = context.GetTwoDigitsVersionNumber().Substring(0, 8) + ".SqlDataProvider"; + var filePath = "./Dnn Platform/Website/Providers/DataProviders/SqlDataProvider/" + fileName; + if (File.Exists(filePath)) + { + context.SqlDataProviderExists = true; + return; + } + + context.SqlDataProviderExists = false; + + using (var file = new StreamWriter(filePath, true)) + { + file.WriteLine("/************************************************************/"); + file.WriteLine("/***** SqlDataProvider *****/"); + file.WriteLine("/***** *****/"); + file.WriteLine("/***** *****/"); + file.WriteLine("/***** Note: To manually execute this script you must *****/"); + file.WriteLine("/***** perform a search and replace operation *****/"); + file.WriteLine("/***** for {databaseOwner} and {objectQualifier} *****/"); + file.WriteLine("/***** *****/"); + file.WriteLine("/************************************************************/"); + } + } + } +} diff --git a/Build/Tasks/OtherPackages.cs b/Build/Tasks/OtherPackages.cs new file mode 100644 index 00000000000..86815a3f454 --- /dev/null +++ b/Build/Tasks/OtherPackages.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Common.Xml; + using Cake.Frosting; + using Cake.Json; + + using Dnn.CakeUtils; + + /// A cake task to include other 3rd party packages. + [Dependency(typeof(PackageNewtonsoft))] + public sealed class OtherPackages : FrostingTask + { + /// + public override void Run(Context context) + { + var otherPackages = context.DeserializeJsonFromFile>("./Build/Tasks/thirdparty.json"); + foreach (var op in otherPackages) + { + PackageOtherPackage(context, op); + } + } + + private static void PackageOtherPackage(Context context, OtherPackage package) + { + var srcFolder = "./" + package.Folder; + var files = package.Excludes.Length == 0 + ? context.GetFiles(srcFolder + "**/*") + : context.GetFilesByPatterns(srcFolder, new[] { "**/*" }, package.Excludes); + var version = "00.00.00"; + foreach (var dnn in context.GetFiles(srcFolder + "**/*.dnn")) + { + version = context.XmlPeek(dnn, "dotnetnuke/packages/package/@version"); + } + + context.CreateDirectory(package.Destination); + + var packageZip = $"{context.WebsiteFolder}{package.Destination}/{package.Name}_{version}_Install.{package.Extension}"; + context.Information("Packaging {0}", packageZip); + context.Zip(srcFolder, packageZip, files); + } + + private class OtherPackage + { + public string Name { get; set; } + + public string Folder { get; set; } + + public string Destination { get; set; } + + public string Extension { get; set; } = "zip"; + + public string[] Excludes { get; set; } = Array.Empty(); + } + } +} diff --git a/Build/Tasks/PackageNewtonsoft.cs b/Build/Tasks/PackageNewtonsoft.cs new file mode 100644 index 00000000000..651cb5804a9 --- /dev/null +++ b/Build/Tasks/PackageNewtonsoft.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + + using Dnn.CakeUtils; + + /// A cake task to generate the Newtonsoft.Json package. + public sealed class PackageNewtonsoft : FrostingTask + { + /// + public override void Run(Context context) + { + var version = "00.00.00"; + foreach (var assy in context.GetFiles(context.WebsiteFolder + "bin/Newtonsoft.Json.dll")) + { + version = System.Diagnostics.FileVersionInfo.GetVersionInfo(assy.FullPath).FileVersion; + } + + var packageZip = $"{context.WebsiteFolder}Install/Module/Newtonsoft.Json_{version}_Install.zip"; + context.Zip( + "./DNN Platform/Components/Newtonsoft", + packageZip, + context.GetFiles("./DNN Platform/Components/Newtonsoft/*")); + context.AddFilesToZip( + packageZip, + "Website", + context.GetFiles(context.WebsiteFolder + "bin/Newtonsoft.Json.dll"), + true); + } + } +} diff --git a/Build/Tasks/PreparePackaging.cs b/Build/Tasks/PreparePackaging.cs new file mode 100644 index 00000000000..6b111ecaf2c --- /dev/null +++ b/Build/Tasks/PreparePackaging.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Frosting; + using Cake.Json; + + /// A cake task to prepare for packaging (by building the platform and copying files). + [Dependency(typeof(CopyWebsite))] + [Dependency(typeof(Build))] + [Dependency(typeof(CopyWebConfig))] + [Dependency(typeof(CopyWebsiteBinFolder))] + public sealed class PreparePackaging : FrostingTask + { + /// + public override void Run(Context context) + { + context.PackagingPatterns = context.DeserializeJsonFromFile("./Build/Tasks/packaging.json"); + + // Various fixes + context.CopyFile( + "./DNN Platform/Components/DataAccessBlock/bin/Microsoft.ApplicationBlocks.Data.dll", + context.WebsiteFolder + "bin/Microsoft.ApplicationBlocks.Data.dll"); + context.CopyFiles( + "./DNN Platform/Components/Lucene.Net.Contrib/bin/Lucene.Net.Contrib.Analyzers.*", + context.WebsiteFolder + "bin/"); + context.CopyFile( + "./DNN Platform/Library/bin/PetaPoco.dll", + context.WebsiteFolder + "bin/PetaPoco.dll"); + } + } +} diff --git a/Build/Tasks/ResetDatabase.cs b/Build/Tasks/ResetDatabase.cs new file mode 100644 index 00000000000..d23560e4f3f --- /dev/null +++ b/Build/Tasks/ResetDatabase.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Data.SqlClient; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Core; + using Cake.FileHelpers; + using Cake.Frosting; + + /// A cake task to reset the local dev database. + public sealed class ResetDatabase : FrostingTask + { + private const string ScriptsPath = @".\Build\Tasks\sql\"; + + private static readonly string[] GoStatement = { "\r\nGO\r\n", "\nGO\n", "\nGO\r\n", "\r\nGO\n", }; + + /// + public override void Run(Context context) + { + var script = ReplaceScriptVariables(context, LoadScript(context, "db-connections-drop")); + ExecuteScript(context, script); + script = ReplaceScriptVariables(context, LoadScript(context, "create-db")); + ExecuteScript(context, script); + if (context.Settings.DnnSqlUsername != string.Empty) + { + script = ReplaceScriptVariables(context, LoadScript(context, "add-db-user")); + ExecuteScript(context, script); + } + } + + private static string LoadScript(ICakeContext context, string scriptName) + { + var script = scriptName + ".local.sql"; + if (!System.IO.File.Exists(ScriptsPath + script)) + { + script = scriptName + ".sql"; + } + + return context.FileReadText(ScriptsPath + script); + } + + private static string ReplaceScriptVariables(Context context, string script) + { + return script.Replace("{DBName}", context.Settings.DnnDatabaseName) + .Replace("{DBPath}", context.Settings.DatabasePath) + .Replace("{DBLogin}", context.Settings.DnnSqlUsername); + } + + private static bool ExecuteScript(Context context, string scriptStatement) + { + try + { + using (var connection = new SqlConnection(context.Settings.SaConnectionString)) + { + connection.Open(); + foreach (var cmd in scriptStatement.Split(GoStatement, StringSplitOptions.RemoveEmptyEntries)) + { + var command = new SqlCommand(cmd, connection); + command.ExecuteNonQuery(); + } + + connection.Close(); + } + } + catch (Exception err) + { + context.Error(err); + return false; + } + + return true; + } + } +} diff --git a/Build/Tasks/ResetDevSite.cs b/Build/Tasks/ResetDevSite.cs new file mode 100644 index 00000000000..b338ad4b377 --- /dev/null +++ b/Build/Tasks/ResetDevSite.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Frosting; + + /// A cake task to reset a local dev site. + [Dependency(typeof(BuildToTempFolder))] + [Dependency(typeof(CopyToDevSite))] + [Dependency(typeof(CopyWebConfigToDevSite))] + public sealed class ResetDevSite : FrostingTask + { + } +} diff --git a/Build/Tasks/RestoreNuGetPackages.cs b/Build/Tasks/RestoreNuGetPackages.cs new file mode 100644 index 00000000000..f9b1efe1aa5 --- /dev/null +++ b/Build/Tasks/RestoreNuGetPackages.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using Cake.Common.Tools.NuGet; + using Cake.Frosting; + + /// A cake task to restore the NuGet packages for the solution. + public sealed class RestoreNuGetPackages : FrostingTask + { + /// + public override void Run(Context context) + { + context.NuGetRestore(context.DnnSolutionPath); + } + } +} diff --git a/Build/Tasks/RunUnitTests.cs b/Build/Tasks/RunUnitTests.cs new file mode 100644 index 00000000000..e090871360e --- /dev/null +++ b/Build/Tasks/RunUnitTests.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Tools.NUnit; + using Cake.Frosting; + + /// A cake task to run NUnit 3 tests. + /// This task is not used (NUnit 3 is not used by DNN), you probably want . + [Dependency(typeof(Build))] + public sealed class RunUnitTests : FrostingTask + { + /// + public override void Run(Context context) + { + context.NUnit3( + "./src/**/bin/" + context.BuildConfiguration + "/*.Test*.dll", + new NUnit3Settings { NoResults = false }); + } + } +} diff --git a/Build/Tasks/SetPackageVersions.cs b/Build/Tasks/SetPackageVersions.cs new file mode 100644 index 00000000000..ac6f4fbe21b --- /dev/null +++ b/Build/Tasks/SetPackageVersions.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.FileHelpers; + using Cake.Frosting; + + /// A cake task to set the version of client-side packages. + [Dependency(typeof(SetVersion))] + public sealed class SetPackageVersions : FrostingTask + { + /// + public override void Run(Context context) + { + if (context.Settings.Version == "off") + { + return; + } + + var packages = context.GetFiles("./Dnn.AdminExperience/ClientSide/*.Web/package.json"); + packages.Add(context.GetFiles("./Dnn.AdminExperience/ClientSide/Dnn.React.Common/package.json")); + packages.Add(context.GetFiles("./Dnn.AdminExperience/ClientSide/*.Web/**/_exportables/package.json")); + packages.Add(context.GetFiles("./DNN Platform/Modules/ResourceManager/ResourceManager.Web/package.json")); + + // Set all package.json in Admin Experience to the current version and to consume the current (local) version of dnn-react-common. + foreach (var file in packages) + { + context.Information($"Updating {file} to version {context.Version.FullSemVer}"); + context.ReplaceRegexInFiles( + file.ToString(), + @"""version"": "".*""", + $@"""version"": ""{context.Version.FullSemVer}"""); + context.ReplaceRegexInFiles( + file.ToString(), + @"""@dnnsoftware\/dnn-react-common"": "".*""", + $@"""@dnnsoftware/dnn-react-common"": ""{context.Version.FullSemVer}"""); + } + } + } +} diff --git a/Build/Tasks/SetVersion.cs b/Build/Tasks/SetVersion.cs new file mode 100644 index 00000000000..2006a646ad5 --- /dev/null +++ b/Build/Tasks/SetVersion.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.Tools.GitVersion; + using Cake.Frosting; + + using Dnn.CakeUtils; + + using Newtonsoft.Json; + + /// A cake task to calculate the version. + public sealed class SetVersion : FrostingTask + { + /// + public override void Run(Context context) + { + if (context.Settings.Version == "auto") + { + context.Version = context.GitVersion(); + context.BuildNumber = context.Version.LegacySemVerPadded; + } + else + { + context.Version = new GitVersion(); + var assemblyInfo = new AssemblyInfo("SolutionInfo.cs"); + var requestedVersion = context.Settings.Version == "off" + ? assemblyInfo.GetVersion() + : new Version(context.Settings.Version); + context.Version.Major = requestedVersion.Major; + context.Version.Minor = requestedVersion.Minor; + context.Version.Patch = requestedVersion.Build; + context.Version.InformationalVersion = requestedVersion.ToString(3) + " Custom build"; + context.Version.MajorMinorPatch = requestedVersion.ToString(3); + context.Version.FullSemVer = requestedVersion.ToString(3); + if (requestedVersion.Revision != -1) + { + context.Version.CommitsSinceVersionSource = requestedVersion.Revision; + context.Version.InformationalVersion = requestedVersion.ToString(4) + " Custom build"; + } + + context.BuildNumber = requestedVersion.ToString(3); + } + + context.Information(JsonConvert.SerializeObject(context.Version)); + if (context.Settings.Version != "off") + { + context.UpdateAssemblyInfoVersion( + new Version( + context.Version.Major, + context.Version.Minor, + context.Version.Patch, + context.Version.CommitsSinceVersionSource ?? 0), + context.Version.InformationalVersion, + "SolutionInfo.cs"); + } + + context.Information("Informational Version : " + context.Version.InformationalVersion); + context.ProductVersion = context.Version.MajorMinorPatch; + context.Information("Product Version : " + context.ProductVersion); + context.Information("Build Number : " + context.BuildNumber); + context.Information("The build Id is : " + context.BuildId); + } + } +} diff --git a/Build/Tasks/UnitTests.cs b/Build/Tasks/UnitTests.cs new file mode 100644 index 00000000000..60f40837477 --- /dev/null +++ b/Build/Tasks/UnitTests.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Linq; + + using Cake.Common.IO; + using Cake.Common.Tools.VSTest; + using Cake.Frosting; + + /// + /// Runs units tests on solution. Make sure to build the solution before running this task. + /// + public sealed class UnitTests : FrostingTask + { + /// + public override void Run(Context context) + { + var testAssemblies = context.GetFiles($@"**\bin\{context.BuildConfiguration}\DotNetNuke.Tests.*.dll"); + testAssemblies += context.GetFiles($@"**\bin\{context.BuildConfiguration}\Dnn.PersonaBar.*.Tests.dll"); + testAssemblies -= context.GetFiles(@"**\DotNetNuke.Tests.Utilities.dll"); + + // TODO: address issues to allow these tests to run + testAssemblies -= context.GetFiles(@"**\DotNetNuke.Tests.Integration.dll"); + testAssemblies -= context.GetFiles(@"**\DotNetNuke.Tests.Urls.dll"); + + var vsTestPath = context.GetFiles("tools/Microsoft.TestPlatform.16.8.0/tools/**/vstest.console.exe") + .First(); + context.VSTest( + testAssemblies, + new VSTestSettings + { + ToolPath = vsTestPath, + Logger = "trx", + Parallel = true, + EnableCodeCoverage = true, + TestAdapterPath = @"tools\NUnitTestAdapter.2.3.0\build", + }); + } + } +} diff --git a/Build/Tasks/UpdateDnnManifests.cs b/Build/Tasks/UpdateDnnManifests.cs new file mode 100644 index 00000000000..1abc2bdbd34 --- /dev/null +++ b/Build/Tasks/UpdateDnnManifests.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.IO; + using System.Linq; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.FileHelpers; + using Cake.Frosting; + using Cake.XdtTransform; + + using Dnn.CakeUtils; + + /// A cake task to set the version attribute in all of the .dnn manifest files. + [Dependency(typeof(SetVersion))] + [Dependency(typeof(SetPackageVersions))] + public sealed class UpdateDnnManifests : FrostingTask + { + /// Gets the version from the context and formats it as a string. + /// The context. + /// A string in the format "09.09.00". + public static string GetVersionString(Context context) + { + return $"{context.Version.Major:00}.{context.Version.Minor:00}.{context.Version.Patch:00}"; + } + + /// + public override void Run(Context context) + { + var unversionedManifests = context.FileReadLines("./Build/Tasks/unversionedManifests.txt"); + foreach (var file in context.GetFilesByPatterns(".", new[] { "**/*.dnn" }, unversionedManifests)) + { + if (context.Settings.Version == "off") + { + return; + } + + context.Information("Transforming: " + file); + var transformFile = context.File(Path.GetTempFileName()); + context.FileAppendText(transformFile, this.GetXdtTransformation(context)); + context.XdtTransformConfig(file, transformFile, file); + } + } + + private string GetXdtTransformation(Context context) + { + return $@" + + + + +"; + } + } +} diff --git a/Build/Cake/packaging.json b/Build/Tasks/packaging.json similarity index 100% rename from Build/Cake/packaging.json rename to Build/Tasks/packaging.json diff --git a/Build/Cake/sql/add-db-user.sql b/Build/Tasks/sql/add-db-user.sql similarity index 100% rename from Build/Cake/sql/add-db-user.sql rename to Build/Tasks/sql/add-db-user.sql diff --git a/Build/Cake/sql/create-db.sql b/Build/Tasks/sql/create-db.sql similarity index 100% rename from Build/Cake/sql/create-db.sql rename to Build/Tasks/sql/create-db.sql diff --git a/Build/Cake/sql/db-connections-drop.sql b/Build/Tasks/sql/db-connections-drop.sql similarity index 100% rename from Build/Cake/sql/db-connections-drop.sql rename to Build/Tasks/sql/db-connections-drop.sql diff --git a/Build/Cake/thirdparty.json b/Build/Tasks/thirdparty.json similarity index 100% rename from Build/Cake/thirdparty.json rename to Build/Tasks/thirdparty.json diff --git a/Build/Cake/unversionedManifests.txt b/Build/Tasks/unversionedManifests.txt similarity index 100% rename from Build/Cake/unversionedManifests.txt rename to Build/Tasks/unversionedManifests.txt diff --git a/Build/Cake/webconfig-transform.xsl b/Build/Tasks/webconfig-transform.xsl similarity index 100% rename from Build/Cake/webconfig-transform.xsl rename to Build/Tasks/webconfig-transform.xsl diff --git a/DNN_Platform.sln.DotSettings b/DNN_Platform.sln.DotSettings index dff958f7407..13095b7d74e 100644 --- a/DNN_Platform.sln.DotSettings +++ b/DNN_Platform.sln.DotSettings @@ -146,4 +146,6 @@ True True True - True \ No newline at end of file + True + True + True From 8753b7cd6e71bdcaa2a60d784b61ebbbe14399c2 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Tue, 30 Mar 2021 14:58:18 -0500 Subject: [PATCH 43/53] Add package for MailKit --- Build/Tasks/OtherPackages.cs | 1 + Build/Tasks/PackageMailKit.cs | 69 +++++++++++++++++++++ Build/Tasks/packaging.json | 3 + Build/Tasks/unversionedManifests.txt | 1 + DNN Platform/Components/MailKit/License.txt | 21 +++++++ DNN Platform/Components/MailKit/MailKit.dnn | 45 ++++++++++++++ 6 files changed, 140 insertions(+) create mode 100644 Build/Tasks/PackageMailKit.cs create mode 100644 DNN Platform/Components/MailKit/License.txt create mode 100644 DNN Platform/Components/MailKit/MailKit.dnn diff --git a/Build/Tasks/OtherPackages.cs b/Build/Tasks/OtherPackages.cs index 86815a3f454..a2bfa75fdd2 100644 --- a/Build/Tasks/OtherPackages.cs +++ b/Build/Tasks/OtherPackages.cs @@ -17,6 +17,7 @@ namespace DotNetNuke.Build.Tasks /// A cake task to include other 3rd party packages. [Dependency(typeof(PackageNewtonsoft))] + [Dependency(typeof(PackageMailKit))] public sealed class OtherPackages : FrostingTask { /// diff --git a/Build/Tasks/PackageMailKit.cs b/Build/Tasks/PackageMailKit.cs new file mode 100644 index 00000000000..5fb6b4157ea --- /dev/null +++ b/Build/Tasks/PackageMailKit.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Build.Tasks +{ + using System; + using System.Diagnostics; + using System.Linq; + using System.Xml; + + using Cake.Common.Diagnostics; + using Cake.Common.IO; + using Cake.Frosting; + using Dnn.CakeUtils; + + /// A cake task to generate the MailKit package. + public sealed class PackageMailKit : FrostingTask + { + /// + public override void Run(Context context) + { + var binDir = context.WebsiteDir.Path.Combine("bin"); + var mailKitPath = binDir.CombineWithFilePath("MailKit.dll"); + var packageVersion = FileVersionInfo.GetVersionInfo(context.MakeAbsolute(mailKitPath).FullPath).FileVersion; + + var packageZip = context.WebsiteDir.Path.CombineWithFilePath($"Install/Library/MailKit_{packageVersion}_Install.zip"); + var packageDir = context.Directory("DNN Platform/Components/MailKit"); + + context.Information($"Creating {packageZip}"); + context.Zip( + packageDir.ToString(), + packageZip, + context.GetFilesByPatterns(packageDir, new[] { "*" }, new[] { "*.dnn" })); + + var manifestPath = context.GetFiles(packageDir.Path.CombineWithFilePath("*.dnn").ToString()).Single(); + context.Information($"Reading manifest from {manifestPath}"); + var manifest = new XmlDocument(); + manifest.LoadXml(context.ReadFile(manifestPath)); + var assemblies = + from XmlNode assemblyNode in manifest.SelectNodes("//assembly") + from XmlNode childNode in assemblyNode.ChildNodes + where childNode.LocalName.Equals("name") + select childNode; + + foreach (var assemblyNameNode in assemblies) + { + var assemblyPath = binDir.CombineWithFilePath(assemblyNameNode.InnerText); + context.Information($"Adding {assemblyPath} to {packageZip}"); + context.AddFilesToZip( + packageZip, + context.MakeAbsolute(context.WebsiteDir.Path), + context.GetFiles(assemblyPath.ToString()), + append: true); + + var versionNode = assemblyNameNode.ParentNode.ChildNodes.Cast() + .SingleOrDefault(childNode => childNode.LocalName.Equals("version")); + if (versionNode != null) + { + versionNode.InnerText = FileVersionInfo.GetVersionInfo(context.MakeAbsolute(assemblyPath).FullPath).FileVersion; + context.Information($"Set {assemblyPath} version to {versionNode.InnerText}"); + } + } + + manifest.SelectSingleNode("//package[@version]").Attributes["version"].Value = packageVersion; + + context.AddXmlFileToZip(packageZip, manifest, manifestPath.GetFilename().ToString(), append: true); + } + } +} diff --git a/Build/Tasks/packaging.json b/Build/Tasks/packaging.json index 99c4046a3b7..aa407956f1a 100644 --- a/Build/Tasks/packaging.json +++ b/Build/Tasks/packaging.json @@ -23,6 +23,9 @@ "/bin/System.IdentityModel.Tokens.Jwt.*", "/bin/Telerik.Web.UI.dll", "/bin/Telerik.Web.UI.Skins.dll", + "/bin/BouncyCastle.Crypto.dll", + "/bin/MailKit.dll", + "/bin/MimeKit.dll", "/Install/Module/DNNCE_Website.Deprecated_*_Install.zip" ], "installInclude": ["/Install/InstallWizard.aspx.cs"], diff --git a/Build/Tasks/unversionedManifests.txt b/Build/Tasks/unversionedManifests.txt index e7849bfdd95..c1174e1c4bc 100644 --- a/Build/Tasks/unversionedManifests.txt +++ b/Build/Tasks/unversionedManifests.txt @@ -1,3 +1,4 @@ +DNN Platform/Components/MailKit/*.dnn DNN Platform/Components/Microsoft.*/**/*.dnn DNN Platform/Components/Newtonsoft/*.dnn DNN Platform/JavaScript Libraries/**/*.dnn diff --git a/DNN Platform/Components/MailKit/License.txt b/DNN Platform/Components/MailKit/License.txt new file mode 100644 index 00000000000..7614a032f34 --- /dev/null +++ b/DNN Platform/Components/MailKit/License.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2012-2020 .NET Foundation and Contributors + +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/DNN Platform/Components/MailKit/MailKit.dnn b/DNN Platform/Components/MailKit/MailKit.dnn new file mode 100644 index 00000000000..abf742ba321 --- /dev/null +++ b/DNN Platform/Components/MailKit/MailKit.dnn @@ -0,0 +1,45 @@ + + + + MailKit Components + Libraries required for MailKit. + + + DNN + .NET Foundation + https://dnncommunity.org + info@dnncommunity.org + + License.txt + + This package includes MailKit assembly version 2.10.1. + Please go to http://www.mimekit.com/ to view release notes on this particular version. + + + + + bin + MailKit.dll + 2.10.1 + + + bin + MimeKit.dll + 2.10.1 + + + bin + BouncyCastle.Crypto.dll + 1.8.8 + + + bin + System.Buffers.dll + 4.5.1 + + + + + + + From 595ff738b9befa004eb05515c03255b8ccb8b3fe Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Wed, 31 Mar 2021 14:49:39 -0500 Subject: [PATCH 44/53] Enable binary logger --- .gitignore | 274 ++++++++++++++++++++++--------------------- Build/Tasks/Build.cs | 10 +- 2 files changed, 146 insertions(+), 138 deletions(-) diff --git a/.gitignore b/.gitignore index 158470826fb..64327b4d6ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,140 +1,142 @@ -################# -## Visual Studio -################# - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.sln.docstates -*.local.sln -*.sln.GhostDoc.xml - -## Ignore VS2015/Roslyn artifacts -*.sln.ide/ -.vs/ -.vscode/ - -## Ignore Webstorm artifacts -*.idea/ - -# Build results -[Tt]ools/* -!tools/packages.config -[Rr]elease -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.pch -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.eml -*.vspscc -.builds -*.dotCover -*.ldf -Artifacts/ -[Tt]emp -[Bb]uild/**/*.zip - - -# git merge artifacts -*.orig -*.gitmodules - -## TODO: If you have NuGet Package Restore enabled, uncomment this -[Pp]ackages/ - -# Visual Studio profiler -*.psess -*.vsp - -# ReSharper is a .NET coding add-in -_ReSharper* - -# Others -[Oo]bj -TestResults -*.Cache -ClientBin -stylecop.* -~$* -*.dbmdl -Generated_Code #added for RIA/Silverlight projects - -# OS artifacts -Thumbs.db -Desktop.ini - -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML - -# Node -node_modules/ - -############ -## DNN -############ - -# Ignore local settings -Build/**/*.local.* -*.local.* - -# Ignore temporary artifacts -/[Tt]emp/ -/[Ww]ebsite/ -DNN_*.zip -!DNN [Pp]latform/[Cc]omponents -!DNN [Pp]latform/[Cc]ontrols -DNN [Pp]latform/[Cc]omponents/[Cc]lient[Dd]ependency/[Ss]ource/[Bb]in -DNN [Pp]latform/[Cc]ontrols/[Cc]ountry[Ll]ist[Bb]ox/[Bb]in/* - -DNN [Pp]latform/*/[Bb]in -DNN [Pp]latform/Tests/*/[Bb]in/* -DNN [Pp]latform/Modules/*/[Bb]in/* -DNN [Pp]latform/Skins/*/[Bb]in/* -DNN [Pp]latform/Admin Modules/*/[Bb]in/* -DNN [Pp]latform/MVC Modules/*/[Bb]in/* -DNN [Pp]latform/[Pp]roviders/*/*/[Bb]in/* -DNN [Pp]latform/[Pp]roviders/*/*/*/[Bb]in/* -DNN [Pp]latform/Syndication/[Bb]in/* -DNN [Pp]latform/[Cc]onnectors/*/[Bb]in/* -DNN [Pp]latform/[Pp]roviders/*/[Bb]in/* - -DNN [Pp]latform/Modules/ResourceManager/**/scripts/*-bundle.* - -# ignore all other language resx files -*.de-DE.resx -*.es-ES.resx -*.fr-FR.resx -*.it-IT.resx -*.nl-NL.resx - -# but do track translations in the Install folder -!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.de-DE.resx -!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.es-ES.resx -!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.fr-FR.resx -!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.it-IT.resx -!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.nl-NL.resx - -# Add fips back -!DNN Platform/[Ww]ebsite/App_Data/FipsCompilanceAssemblies/Lucene.Net.dll - -yarn-error.log +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates +*.local.sln +*.sln.GhostDoc.xml + +## Ignore VS2015/Roslyn artifacts +*.sln.ide/ +.vs/ +.vscode/ + +## Ignore Webstorm artifacts +*.idea/ + +# Build results +[Tt]ools/* +!tools/packages.config +[Rr]elease +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.eml +*.vspscc +.builds +*.dotCover +*.ldf +Artifacts/ +[Tt]emp +[Bb]uild/**/*.zip + + +# git merge artifacts +*.orig +*.gitmodules + +## TODO: If you have NuGet Package Restore enabled, uncomment this +[Pp]ackages/ + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Others +[Oo]bj +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# OS artifacts +Thumbs.db +Desktop.ini + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + +# Node +node_modules/ + +############ +## DNN +############ + +# Ignore local settings +Build/**/*.local.* +*.local.* + +# Ignore temporary artifacts +/[Tt]emp/ +/[Ww]ebsite/ +DNN_*.zip +!DNN [Pp]latform/[Cc]omponents +!DNN [Pp]latform/[Cc]ontrols +DNN [Pp]latform/[Cc]omponents/[Cc]lient[Dd]ependency/[Ss]ource/[Bb]in +DNN [Pp]latform/[Cc]ontrols/[Cc]ountry[Ll]ist[Bb]ox/[Bb]in/* + +DNN [Pp]latform/*/[Bb]in +DNN [Pp]latform/Tests/*/[Bb]in/* +DNN [Pp]latform/Modules/*/[Bb]in/* +DNN [Pp]latform/Skins/*/[Bb]in/* +DNN [Pp]latform/Admin Modules/*/[Bb]in/* +DNN [Pp]latform/MVC Modules/*/[Bb]in/* +DNN [Pp]latform/[Pp]roviders/*/*/[Bb]in/* +DNN [Pp]latform/[Pp]roviders/*/*/*/[Bb]in/* +DNN [Pp]latform/Syndication/[Bb]in/* +DNN [Pp]latform/[Cc]onnectors/*/[Bb]in/* +DNN [Pp]latform/[Pp]roviders/*/[Bb]in/* + +DNN [Pp]latform/Modules/ResourceManager/**/scripts/*-bundle.* + +# ignore all other language resx files +*.de-DE.resx +*.es-ES.resx +*.fr-FR.resx +*.it-IT.resx +*.nl-NL.resx + +# but do track translations in the Install folder +!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.de-DE.resx +!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.es-ES.resx +!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.fr-FR.resx +!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.it-IT.resx +!DNN Platform/[Ww]ebsite/[Ii]nstall/[Aa]pp_[Ll]ocal[Rr]esources/*.nl-NL.resx + +# Add fips back +!DNN Platform/[Ww]ebsite/App_Data/FipsCompilanceAssemblies/Lucene.Net.dll + +yarn-error.log /Build/bin/ /.dotnet/ /Build/Tools/ + +*.binlog diff --git a/Build/Tasks/Build.cs b/Build/Tasks/Build.cs index db33735f3ca..c8f702c4ef8 100644 --- a/Build/Tasks/Build.cs +++ b/Build/Tasks/Build.cs @@ -19,13 +19,19 @@ public sealed class Build : FrostingTask /// public override void Run(Context context) { - context.MSBuild(context.DnnSolutionPath, settings => settings.WithTarget("Clean")); + var cleanSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) + .WithTarget("Clean") + .EnableBinaryLogger("clean.binlog") + .SetNoConsoleLogger(context.IsRunningInCI); + context.MSBuild(context.DnnSolutionPath, cleanSettings); var buildSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .SetPlatformTarget(PlatformTarget.MSIL) .WithTarget("Rebuild") .SetMaxCpuCount(4) - .WithProperty("SourceLinkCreate", "true"); + .WithProperty("SourceLinkCreate", "true") + .EnableBinaryLogger("rebuild.binlog") + .SetNoConsoleLogger(context.IsRunningInCI); context.MSBuild(context.DnnSolutionPath, buildSettings); } } From d07dfe4b9b23adc4d8359c63099f98a9a8b35801 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Wed, 31 Mar 2021 15:51:10 -0500 Subject: [PATCH 45/53] Don't use hardcoded CPU count Zero indicates passing /m to MSBuild, allowing it to use up to the number of processors on the computer. See https://docs.microsoft.com/en-us/visualstudio/msbuild/building-multiple-projects-in-parallel-with-msbuild --- Build/Tasks/Build.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Build/Tasks/Build.cs b/Build/Tasks/Build.cs index c8f702c4ef8..670f5d4bb3c 100644 --- a/Build/Tasks/Build.cs +++ b/Build/Tasks/Build.cs @@ -21,6 +21,7 @@ public override void Run(Context context) { var cleanSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .WithTarget("Clean") + .SetMaxCpuCount(0) .EnableBinaryLogger("clean.binlog") .SetNoConsoleLogger(context.IsRunningInCI); context.MSBuild(context.DnnSolutionPath, cleanSettings); @@ -28,7 +29,7 @@ public override void Run(Context context) var buildSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .SetPlatformTarget(PlatformTarget.MSIL) .WithTarget("Rebuild") - .SetMaxCpuCount(4) + .SetMaxCpuCount(0) .WithProperty("SourceLinkCreate", "true") .EnableBinaryLogger("rebuild.binlog") .SetNoConsoleLogger(context.IsRunningInCI); From af0d359fc0fd6785645a3953eacb005debb70bdd Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Thu, 1 Apr 2021 09:01:10 -0500 Subject: [PATCH 46/53] Use Artifacts directory for logs --- .gitignore | 2 -- Build/Tasks/Build.cs | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 64327b4d6ce..1706e383e8e 100644 --- a/.gitignore +++ b/.gitignore @@ -138,5 +138,3 @@ yarn-error.log /Build/bin/ /.dotnet/ /Build/Tools/ - -*.binlog diff --git a/Build/Tasks/Build.cs b/Build/Tasks/Build.cs index 670f5d4bb3c..0e12e6cb9f3 100644 --- a/Build/Tasks/Build.cs +++ b/Build/Tasks/Build.cs @@ -22,7 +22,7 @@ public override void Run(Context context) var cleanSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .WithTarget("Clean") .SetMaxCpuCount(0) - .EnableBinaryLogger("clean.binlog") + .EnableBinaryLogger("Artifacts/clean.binlog") .SetNoConsoleLogger(context.IsRunningInCI); context.MSBuild(context.DnnSolutionPath, cleanSettings); @@ -31,7 +31,7 @@ public override void Run(Context context) .WithTarget("Rebuild") .SetMaxCpuCount(0) .WithProperty("SourceLinkCreate", "true") - .EnableBinaryLogger("rebuild.binlog") + .EnableBinaryLogger("Artifacts/rebuild.binlog") .SetNoConsoleLogger(context.IsRunningInCI); context.MSBuild(context.DnnSolutionPath, buildSettings); } From cbf0398311ea38e1e91b692d4142c7cd02db2a56 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Thu, 1 Apr 2021 09:59:40 -0500 Subject: [PATCH 47/53] Report MSBuild issues via Cake --- Build/Build.csproj | 3 +++ Build/Program.cs | 1 + Build/Tasks/Build.cs | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Build/Build.csproj b/Build/Build.csproj index 625fe1f4cc8..6ca86f74673 100644 --- a/Build/Build.csproj +++ b/Build/Build.csproj @@ -18,6 +18,9 @@ + + + diff --git a/Build/Program.cs b/Build/Program.cs index cdf910bd566..d054beaf6a5 100644 --- a/Build/Program.cs +++ b/Build/Program.cs @@ -25,6 +25,7 @@ public static int Main(string[] args) .InstallTool(new Uri("nuget:?package=Microsoft.TestPlatform&version=16.8.0")) .InstallTool(new Uri("nuget:?package=NUnitTestAdapter&version=2.3.0")) .InstallTool(new Uri("nuget:?package=NuGet.CommandLine&version=5.8.0")) + .InstallTool(new Uri("nuget:?package=Cake.Issues.MsBuild&version=0.9.1")) .Run(args); } } diff --git a/Build/Tasks/Build.cs b/Build/Tasks/Build.cs index 0e12e6cb9f3..5bd210eb243 100644 --- a/Build/Tasks/Build.cs +++ b/Build/Tasks/Build.cs @@ -6,8 +6,12 @@ namespace DotNetNuke.Build.Tasks using System; using System.Linq; + using Cake.Common.Build; + using Cake.Common.Build.AzurePipelines.Data; using Cake.Common.Tools.MSBuild; using Cake.Frosting; + using Cake.Issues; + using Cake.Issues.MsBuild; using DotNetNuke.Build; @@ -19,21 +23,49 @@ public sealed class Build : FrostingTask /// public override void Run(Context context) { + // TODO: when Cake.Issues.MsBuild is updated to support Binary Log version 9, can use .EnableBinaryLogger() instead of .WithLogger(…) + // TODO: also can remove the .InstallTool(…) call for Cake.Issues.MsBuild in Program.cs at that point + var cleanLog = context.ArtifactsDir.Path.CombineWithFilePath("clean.binlog"); var cleanSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .WithTarget("Clean") .SetMaxCpuCount(0) - .EnableBinaryLogger("Artifacts/clean.binlog") + .WithLogger(context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll").FullPath, "BinaryLogger", cleanLog.FullPath) .SetNoConsoleLogger(context.IsRunningInCI); context.MSBuild(context.DnnSolutionPath, cleanSettings); + var buildLog = context.ArtifactsDir.Path.CombineWithFilePath("rebuild.binlog"); var buildSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .SetPlatformTarget(PlatformTarget.MSIL) .WithTarget("Rebuild") .SetMaxCpuCount(0) .WithProperty("SourceLinkCreate", "true") - .EnableBinaryLogger("Artifacts/rebuild.binlog") + .WithLogger(context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll").FullPath, "BinaryLogger", buildLog.FullPath) .SetNoConsoleLogger(context.IsRunningInCI); context.MSBuild(context.DnnSolutionPath, buildSettings); + + // TODO: when Cake.Issues.Recipe is updated to support Frosting, we can switch to their more robust issue processing and reporting features + if (!context.IsRunningInCI) + { + return; + } + + var issueProviders = new[] + { + context.MsBuildIssuesFromFilePath(cleanLog, context.MsBuildBinaryLogFileFormat()), + context.MsBuildIssuesFromFilePath(buildLog, context.MsBuildBinaryLogFileFormat()), + }; + foreach (var issue in context.ReadIssues(issueProviders, context.Environment.WorkingDirectory)) + { + var messageData = new AzurePipelinesMessageData { SourcePath = issue.AffectedFileRelativePath?.FullPath, LineNumber = issue.Line, }; + if (issue.Priority == (int)IssuePriority.Error) + { + context.AzurePipelines().Commands.WriteError(issue.MessageText, messageData); + } + else + { + context.AzurePipelines().Commands.WriteWarning(issue.MessageText, messageData); + } + } } } } From b9452ad4fefde20a8c1f69ce056de65f8e73fe7c Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Thu, 1 Apr 2021 12:50:34 -0500 Subject: [PATCH 48/53] Add initial dependabot config --- .github/dependabot.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..39b29096b1b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "monthly" + + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "monthly" From 6c07700b28c0f8bdc94fc2687d042c7ca2414281 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Thu, 1 Apr 2021 13:20:58 -0500 Subject: [PATCH 49/53] Ensure build errors get reported --- Build/Tasks/Build.cs | 52 +++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/Build/Tasks/Build.cs b/Build/Tasks/Build.cs index 5bd210eb243..04ada2a6168 100644 --- a/Build/Tasks/Build.cs +++ b/Build/Tasks/Build.cs @@ -9,6 +9,7 @@ namespace DotNetNuke.Build.Tasks using Cake.Common.Build; using Cake.Common.Build.AzurePipelines.Data; using Cake.Common.Tools.MSBuild; + using Cake.Core.IO; using Cake.Frosting; using Cake.Issues; using Cake.Issues.MsBuild; @@ -26,37 +27,48 @@ public override void Run(Context context) // TODO: when Cake.Issues.MsBuild is updated to support Binary Log version 9, can use .EnableBinaryLogger() instead of .WithLogger(…) // TODO: also can remove the .InstallTool(…) call for Cake.Issues.MsBuild in Program.cs at that point var cleanLog = context.ArtifactsDir.Path.CombineWithFilePath("clean.binlog"); - var cleanSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) - .WithTarget("Clean") - .SetMaxCpuCount(0) - .WithLogger(context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll").FullPath, "BinaryLogger", cleanLog.FullPath) - .SetNoConsoleLogger(context.IsRunningInCI); - context.MSBuild(context.DnnSolutionPath, cleanSettings); - var buildLog = context.ArtifactsDir.Path.CombineWithFilePath("rebuild.binlog"); - var buildSettings = new MSBuildSettings().SetConfiguration(context.BuildConfiguration) - .SetPlatformTarget(PlatformTarget.MSIL) - .WithTarget("Rebuild") + try + { + var cleanSettings = CreateMsBuildSettings(context, cleanLog).WithTarget("Clean"); + context.MSBuild(context.DnnSolutionPath, cleanSettings); + + var buildSettings = CreateMsBuildSettings(context, buildLog) + .SetPlatformTarget(PlatformTarget.MSIL) + .WithTarget("Rebuild") + .WithProperty("SourceLinkCreate", "true"); + context.MSBuild(context.DnnSolutionPath, buildSettings); + } + finally + { + ReportBuildIssues(context, cleanLog, buildLog); + } + } + + private static MSBuildSettings CreateMsBuildSettings(Context context, FilePath binLogPath) + { + return new MSBuildSettings().SetConfiguration(context.BuildConfiguration) .SetMaxCpuCount(0) - .WithProperty("SourceLinkCreate", "true") - .WithLogger(context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll").FullPath, "BinaryLogger", buildLog.FullPath) + .WithLogger(context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll").FullPath, "BinaryLogger", binLogPath.FullPath) .SetNoConsoleLogger(context.IsRunningInCI); - context.MSBuild(context.DnnSolutionPath, buildSettings); + } - // TODO: when Cake.Issues.Recipe is updated to support Frosting, we can switch to their more robust issue processing and reporting features + private static void ReportBuildIssues(Context context, params FilePath[] logFilePaths) + { if (!context.IsRunningInCI) { return; } - var issueProviders = new[] - { - context.MsBuildIssuesFromFilePath(cleanLog, context.MsBuildBinaryLogFileFormat()), - context.MsBuildIssuesFromFilePath(buildLog, context.MsBuildBinaryLogFileFormat()), - }; + // TODO: when Cake.Issues.Recipe is updated to support Frosting, we can switch to their more robust issue processing and reporting features + var issueProviders = logFilePaths.Select(logFilePath => context.MsBuildIssuesFromFilePath(logFilePath, context.MsBuildBinaryLogFileFormat())); foreach (var issue in context.ReadIssues(issueProviders, context.Environment.WorkingDirectory)) { - var messageData = new AzurePipelinesMessageData { SourcePath = issue.AffectedFileRelativePath?.FullPath, LineNumber = issue.Line, }; + var messageData = new AzurePipelinesMessageData + { + SourcePath = issue.AffectedFileRelativePath?.FullPath, + LineNumber = issue.Line, + }; if (issue.Priority == (int)IssuePriority.Error) { context.AzurePipelines().Commands.WriteError(issue.MessageText, messageData); From 53bb9a68133ce3e9a1561a3a2ca2342fe93b0368 Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Mon, 5 Apr 2021 17:04:19 -0400 Subject: [PATCH 50/53] Fixed an issue that prevented MailKit configuration upon upgrades Config code (09.09.00.config) only runs if we have a matching 09.09.00.SqlDataProvider present. Some time ago we added generating an empty one to prevent these kind of issues in many upgrade areas during build. But it does not commit that file so it only fixes it for that release version and we are lacking a 09.09.00.SqlDataProvider in 09.09.01. For that reason the code that modifies the web.config file to add the MailKit provider does not fire when upgrade from <9.9.0 to 9.9.1 This PR solves this but in DNN10 it would be nice to look into the upgrade code so that it does not rely on xx.xx.xx.SqlDataProvider as the single source to know if there is any upgrade to do as we don't always have slq changes, it would be nice to look at multiple versioned files like config and IUpgradeable information to determine that. --- .../SqlDataProvider/09.09.00.SqlDataProvider | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.00.SqlDataProvider diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.00.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.00.SqlDataProvider new file mode 100644 index 00000000000..33a259d05fa --- /dev/null +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.09.00.SqlDataProvider @@ -0,0 +1,9 @@ +/************************************************************/ +/***** SqlDataProvider *****/ +/***** *****/ +/***** *****/ +/***** Note: To manually execute this script you must *****/ +/***** perform a search and replace operation *****/ +/***** for {databaseOwner} and {objectQualifier} *****/ +/***** *****/ +/************************************************************/ From 2abb4a4f44ab8e8add7d5fddeda4f19ba98b1f31 Mon Sep 17 00:00:00 2001 From: David Poindexter Date: Tue, 6 Apr 2021 21:37:04 -0400 Subject: [PATCH 51/53] Add capability to add existing modules from other sites in site group --- .../ItemListServiceController.cs | 43 +++++++---- .../Js/ExistingModuleDialog.js | 72 ++++++++++++++++++- .../ContentEditorManager/Js/ModuleDialog.js | 11 +++ .../Styles/ContentEditor.css | 15 ++++ 4 files changed, 124 insertions(+), 17 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web/InternalServices/ItemListServiceController.cs b/DNN Platform/DotNetNuke.Web/InternalServices/ItemListServiceController.cs index 142e092d3d0..46bb8c10aee 100644 --- a/DNN Platform/DotNetNuke.Web/InternalServices/ItemListServiceController.cs +++ b/DNN Platform/DotNetNuke.Web/InternalServices/ItemListServiceController.cs @@ -114,7 +114,7 @@ public HttpResponseMessage GetPagesInPortalGroup(int sortOrder = 0) var response = new { Success = true, - Tree = GetPagesInPortalGroupInternal(sortOrder), + Tree = this.GetPagesInPortalGroupInternal(sortOrder), IgnoreRoot = true, }; return this.Request.CreateResponse(HttpStatusCode.OK, response); @@ -146,6 +146,14 @@ public HttpResponseMessage GetPageDescendantsInPortalGroup(string parentId = nul Items = this.GetPageDescendantsInPortalGroupInternal(parentId, sortOrder, searchText, includeDisabled, includeAllTypes, includeActive, includeHostPages, roles), }; return this.Request.CreateResponse(HttpStatusCode.OK, response); + } + + [HttpGet] + public HttpResponseMessage GetPortalsInGroup(int sortOrder = 0) + { + var sites = GetPortalGroup(sortOrder); + var portalId = this.PortalSettings.PortalId; + return this.Request.CreateResponse(HttpStatusCode.OK, new { sites, portalId }); } [HttpGet] @@ -170,7 +178,7 @@ public HttpResponseMessage SearchPagesInPortalGroup(string searchText, int sortO var response = new { Success = true, - Tree = string.IsNullOrEmpty(searchText) ? GetPagesInPortalGroupInternal(sortOrder) + Tree = string.IsNullOrEmpty(searchText) ? this.GetPagesInPortalGroupInternal(sortOrder) : this.SearchPagesInPortalGroupInternal(searchText, sortOrder, includeDisabled, includeAllTypes, includeActive, includeHostPages, roles), IgnoreRoot = true, }; @@ -333,10 +341,10 @@ where string.IsNullOrEmpty(q) || t.Name.IndexOf(q, StringComparison.InvariantCul return this.Request.CreateResponse(HttpStatusCode.OK, terms); } - private static NTree GetPagesInPortalGroupInternal(int sortOrder) + private NTree GetPagesInPortalGroupInternal(int sortOrder) { var treeNode = new NTree { Data = new ItemDto { Key = RootKey } }; - var portals = GetPortalGroup(sortOrder); + var portals = this.GetPortalGroup(sortOrder); treeNode.Children = portals.Select(dto => new NTree { Data = dto }).ToList(); return treeNode; } @@ -383,9 +391,9 @@ private static void SortPagesRecursevely(IEnumerable tabs, NTree GetPortalGroup(int sortOrder) + private IEnumerable GetPortalGroup(int sortOrder) { - var mygroup = GetMyPortalGroup(); + var mygroup = this.GetMyPortalGroup(); var portals = mygroup.Select(p => new ItemDto { Key = PortalPrefix + p.PortalID.ToString(CultureInfo.InvariantCulture), @@ -409,15 +417,22 @@ private static IEnumerable ApplySort(IEnumerable items, int so } } - private static IEnumerable GetMyPortalGroup() + private IEnumerable GetMyPortalGroup() { - var groups = PortalGroupController.Instance.GetPortalGroups().ToArray(); - var mygroup = (from @group in groups - select PortalGroupController.Instance.GetPortalsByGroup(@group.PortalGroupId) - into portals - where portals.Any(x => x.PortalID == PortalSettings.Current.PortalId) - select portals.ToArray()).FirstOrDefault(); - return mygroup; + var groups = PortalGroupController.Instance.GetPortalGroups().ToArray(); + if (groups.Any()) + { + var mygroup = (from @group in groups + select PortalGroupController.Instance.GetPortalsByGroup(@group.PortalGroupId) + into portals + where portals.Any(x => x.PortalID == PortalSettings.Current.PortalId) + select portals.ToArray()).FirstOrDefault(); + return mygroup; + } + + var currentPortal = new List(); + currentPortal.Add(PortalController.Instance.GetPortal(this.PortalSettings.PortalId)); + return currentPortal; } private NTree GetPagesInternal(int portalId, int sortOrder, bool includeDisabled = false, diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js index 2aac8624d8d..8a8973f3fd7 100644 --- a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js @@ -133,7 +133,7 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager moduleId: '', serviceRoot: 'InternalServices', rootId: 'Root', - parameters: { includeAllTypes: "true" }, + parameters: { includeAllTypes: "true", portalId: options.portalId }, includeDisabled: true }, onSelectionChangedBackScript: selectPageProxyCallback @@ -144,11 +144,45 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager dnn.createDropDownList(id, defaultOptions, {}); }, - _createPagesDropdown: function () { + // _createSitesDropdown: function () { + // var handler = this; + // var resx = dnn.ContentEditorManagerResources; + // var label = document.createElement('A') + // var sitePickerOptions = { + // selectSiteCallback: $.proxy(handler._onSelectSiteChanged, handler), + // selectedSite: -1, + // selectedItemCss: 'selected-item', + // internalStateFieldId: 'AddExistingModule_SitePicker_State', + // selectItemDefaultText: resx.sitePicker_selectItemDefaultText, + // itemList: { + // sortAscendingButtonTitle: resx.sitePicker_sortAscendingButtonTitle, + // unsortedOrderButtonTooltip: resx.sitePicker_unsortedOrderButtonTooltip, + // sortAscendingButtonTooltip: resx.sitePicker_sortAscendingButtonTooltip, + // sortDescendingButtonTooltip: resx.sitePicker_sortDescendingButtonTooltip, + // selectedItemExpandTooltip: resx.sitePicker_selectedItemExpandTooltip, + // selectedItemCollapseTooltip: resx.sitePicker_selectedItemCollapseTooltip, + // searchInputPlaceHolder: resx.sitePicker_searchInputPlaceHolder, + // clearButtonTooltip: resx.sitePicker_clearButtonTooltip, + // searchButtonTooltip: resx.sitePicker_searchButtonTooltip, + // loadingResultText: resx.sitePicker_loadingResultText, + // resultsText: resx.sitePicker_resultsText, + // firstItem: null, + // disableUnspecifiedOrder: true + // }, + // services: { + // rootNodeName: resx.sitePicker_selectItemDefaultText + // } + // }; + + // // handler._createDropdown($('#AddExistingModule_Sites')[0], sitePickerOptions); + // }, + + _createPagesDropdown: function (portalId) { var handler = this; var resx = dnn.ContentEditorManagerResources; var pagePickerOptions = { selectPageCallback: $.proxy(handler._onSelectPageChanged, handler), + portalId: portalId, selectedFolder: -1, selectedItemCss: 'selected-item', internalStateFieldId: 'AddExistingModule_FolderPicker_State', @@ -200,6 +234,11 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager '
' + '
' + '
    ' + + '
  • ' + + '' + + '' + + '
  • ' + '
  • ' + '' + '
    ' + @@ -283,6 +322,14 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager this._dialogLayout.trigger('dialogopen'); }, + _loadSiteList: function() { + if (!this.getModuleDialog()._getItemListService().isLoading()) { + this.getModuleDialog()._getItemListService().request('GetPortalsInGroup', 'GET', { + sortOrder: 0 + }, $.proxy(this._renderSiteList, this)); + } + }, + _loadModuleList: function () { this._dialogLayout.find('li.dnnModuleItem').remove(); this._dialogLayout.find('div.dnnModuleDialog_ModuleListMessage').remove(); @@ -300,6 +347,24 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager } }, + _renderSiteList: function (data) { + var select = document.querySelector('#AddExistingModule_Sites'); + data.sites.forEach((siteInfo, index) => { + var portalId = parseInt(siteInfo.key.substr(2)); + var option = document.createElement('option'); + option.innerText = siteInfo.value; + option.value = portalId; + select.appendChild(option); + if(data.portalId == portalId) { + select.options[index].setAttribute('selected', ''); + } + }); + select.addEventListener('change', e => { + var portalId = parseInt(e.target.value); + this._createPagesDropdown(portalId); + }); + }, + _renderModuleList: function (data) { var container = this._dialogLayout.find(".dnnModuleList .listContainer.listAll ul"); @@ -399,8 +464,9 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager }, _initUI: function () { - this._createPagesDropdown(); + this._createPagesDropdown(undefined); this._dialogLayout.find('input[type="checkbox"]').dnnCheckbox(); + this._loadSiteList(); }, _closeButtonHandler: function () { diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ModuleDialog.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ModuleDialog.js index 6e39821cdc8..d93e337ac23 100644 --- a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ModuleDialog.js +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ModuleDialog.js @@ -1127,6 +1127,17 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager return this._serviceController; }, + _getItemListService: function () { + if (!this._itemListServiceController) { + this._itemListServiceController = new dnn.dnnModuleService({ + service: 'internalservices', + controller: 'itemlistservice' + }); + } + + return this._itemListServiceController; + }, + _getEditorService: function () { if (!this._editorServiceController) { this._editorServiceController = new dnn.dnnModuleService({ diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Styles/ContentEditor.css b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Styles/ContentEditor.css index 062e9cb2efb..2e7d31d7865 100644 --- a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Styles/ContentEditor.css +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Styles/ContentEditor.css @@ -429,6 +429,21 @@ .dnnModuleDialog .dnnModuleHeader .dnnCheckbox { margin-top: 7px; } +.dnnModuleDialog .dnnModuleHeader li.sites { + display: flex; + align-items: baseline; +} +.dnnModuleDialog .dnnModuleHeader li.sites select { + border: none; + margin: 0 7px; + font-family: 'Open Sans', Arial, Helvetica, sans-serif; + font-weight: 700; + line-height: 18px; +} +.dnnModuleDialog .dnnModuleHeader li.sites select option { + font-family: 'Open Sans', Arial, Helvetica, sans-serif; + font-weight: 700; +} .dnnModuleDialog .dnnDropDownList.page { display: inline-block; width: auto; From d52b5230cf2541a881015b51aeb5ef6dad747b6c Mon Sep 17 00:00:00 2001 From: David Poindexter Date: Tue, 6 Apr 2021 21:42:07 -0400 Subject: [PATCH 52/53] Remove unnecessary commented code --- .../Js/ExistingModuleDialog.js | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js index 8a8973f3fd7..dee88dc5cae 100644 --- a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/resources/ContentEditorManager/Js/ExistingModuleDialog.js @@ -144,39 +144,6 @@ if (typeof dnn.ContentEditorManager === "undefined" || dnn.ContentEditorManager dnn.createDropDownList(id, defaultOptions, {}); }, - // _createSitesDropdown: function () { - // var handler = this; - // var resx = dnn.ContentEditorManagerResources; - // var label = document.createElement('A') - // var sitePickerOptions = { - // selectSiteCallback: $.proxy(handler._onSelectSiteChanged, handler), - // selectedSite: -1, - // selectedItemCss: 'selected-item', - // internalStateFieldId: 'AddExistingModule_SitePicker_State', - // selectItemDefaultText: resx.sitePicker_selectItemDefaultText, - // itemList: { - // sortAscendingButtonTitle: resx.sitePicker_sortAscendingButtonTitle, - // unsortedOrderButtonTooltip: resx.sitePicker_unsortedOrderButtonTooltip, - // sortAscendingButtonTooltip: resx.sitePicker_sortAscendingButtonTooltip, - // sortDescendingButtonTooltip: resx.sitePicker_sortDescendingButtonTooltip, - // selectedItemExpandTooltip: resx.sitePicker_selectedItemExpandTooltip, - // selectedItemCollapseTooltip: resx.sitePicker_selectedItemCollapseTooltip, - // searchInputPlaceHolder: resx.sitePicker_searchInputPlaceHolder, - // clearButtonTooltip: resx.sitePicker_clearButtonTooltip, - // searchButtonTooltip: resx.sitePicker_searchButtonTooltip, - // loadingResultText: resx.sitePicker_loadingResultText, - // resultsText: resx.sitePicker_resultsText, - // firstItem: null, - // disableUnspecifiedOrder: true - // }, - // services: { - // rootNodeName: resx.sitePicker_selectItemDefaultText - // } - // }; - - // // handler._createDropdown($('#AddExistingModule_Sites')[0], sitePickerOptions); - // }, - _createPagesDropdown: function (portalId) { var handler = this; var resx = dnn.ContentEditorManagerResources; From 3fd4b17e0b9df3f25d0ce75c31413754a5e8c1ca Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Thu, 8 Apr 2021 10:06:10 -0500 Subject: [PATCH 53/53] Don't include System.Buffers in bin It's added via the MailKit package from #4575 Fixes #4525 --- Build/Tasks/packaging.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/Tasks/packaging.json b/Build/Tasks/packaging.json index aa407956f1a..2d159917fef 100644 --- a/Build/Tasks/packaging.json +++ b/Build/Tasks/packaging.json @@ -26,6 +26,7 @@ "/bin/BouncyCastle.Crypto.dll", "/bin/MailKit.dll", "/bin/MimeKit.dll", + "/bin/System.Buffers.dll", "/Install/Module/DNNCE_Website.Deprecated_*_Install.zip" ], "installInclude": ["/Install/InstallWizard.aspx.cs"],