From aed61d253b22027a54f145cf4845dc082da39125 Mon Sep 17 00:00:00 2001 From: Sacha Date: Tue, 9 Sep 2025 11:36:00 +0200 Subject: [PATCH 01/34] fix typo --- .../DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs b/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs index e63963b03e3..f145b303e92 100644 --- a/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs +++ b/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs @@ -187,7 +187,7 @@ protected override void Initialize(RequestContext requestContext) "~/DesktopModules/MVC/{0}/{1}/{2}.resx", moduleInfo.DesktopModule.FolderName, Localization.LocalResourceDirectory, - this.RouteData.Values["ControllerName"]); + this.RouteData.Values["controller"]); var moduleApplication = new ModuleApplication(requestContext, true) { From 3655bc7d2b05b74b6dfb537b7ac061ee6c2fd70e Mon Sep 17 00:00:00 2001 From: Sacha Date: Tue, 9 Sep 2025 11:42:58 +0200 Subject: [PATCH 02/34] performance improvement --- .../DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs index 5fee7b2d3e6..eeb9d8d784b 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs @@ -228,7 +228,7 @@ private SkinModel LoadSkin(DnnPageController page, string skinPath) } } */ - if (!TabPermissionController.CanAdminPage() && !success) + if (!success && !TabPermissionController.CanAdminPage()) { // only display the warning to non-administrators (administrators will see the errors) this.AddPageMessage(ctlSkin, Localization.GetString("ModuleLoadWarning.Error"), string.Format(Localization.GetString("ModuleLoadWarning.Text"), page.PortalSettings.Email), ModuleMessage.ModuleMessageType.YellowWarning); From bae3d24de5e06912edfa69d08b8605edf5a6df98 Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 13:42:20 +0200 Subject: [PATCH 03/34] cleanup --- .../Containers/SkinHelpers.Content.cs | 91 +------------------ .../Controllers/DnnPageController.cs | 47 ---------- .../JavascriptLibraries/MvcJavaScript.cs | 2 - .../Controllers/DefaultController.cs | 8 +- .../Modules/DDRMenu/Localisation/Localiser.cs | 2 +- 5 files changed, 6 insertions(+), 144 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Containers/SkinHelpers.Content.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Containers/SkinHelpers.Content.cs index 3d8409df8a0..e812f93199d 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Containers/SkinHelpers.Content.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Containers/SkinHelpers.Content.cs @@ -5,15 +5,13 @@ namespace DotNetNuke.Web.MvcPipeline.Containers { using System; - using System.IO; using System.Web; using System.Web.Mvc; - using System.Web.Mvc.Html; using DotNetNuke.Common; - using DotNetNuke.Entities.Portals; using DotNetNuke.Framework.JavaScriptLibraries; using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline; using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; using DotNetNuke.Web.MvcPipeline.Models; @@ -38,6 +36,7 @@ public static IHtmlString Content(this HtmlHelper htmlHelper) MvcJavaScript.RequestRegistration(CommonJs.DnnPlugins); if (model.EditMode && model.ModuleConfiguration.ModuleID > 0) { + // render module actions moduleContentPaneDiv.InnerHtml += htmlHelper.Control("ModuleActions", model.ModuleConfiguration); } @@ -57,90 +56,8 @@ public static IHtmlString Content(this HtmlHelper htmlHelper) var moduleDiv = new TagBuilder("div"); moduleDiv.AddCssClass(model.ModuleHost.CssClass); - - /* - if (model.ModuleConfiguration.ModuleControl.ControlSrc.StartsWith("DesktopModules/RazorModules")) - { - var controlFolder = Path.GetDirectoryName(model.ModuleConfiguration.ModuleControl.ControlSrc); - var controlFileNameWithoutExtension = Path.GetFileNameWithoutExtension(model.ModuleConfiguration.ModuleControl.ControlSrc); - var srcPhysicalPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, controlFolder, "_" + controlFileNameWithoutExtension + ".cshtml"); - var scriptFile = Path.Combine("~/" + controlFolder, "Views/", "_" + controlFileNameWithoutExtension + ".cshtml"); - if (File.Exists(srcPhysicalPath)) - { - try - { - moduleDiv.InnerHtml += htmlHelper.Partial(scriptFile, model.ModuleConfiguration); - } - catch (Exception ex2) - { - throw new Exception($"Error : {ex2.Message} ( razor : {scriptFile}, module : {model.ModuleConfiguration.ModuleID})", ex2); - } - } - else - { - throw new Exception($"Error : Razor file dous not exist ( razor : {scriptFile}, module : {model.ModuleConfiguration.ModuleID})"); - - // moduleDiv.InnerHtml += $"Error : {ex.Message} (Controller : {model.ControllerName}, Action : {model.ActionName}, module : {model.ModuleConfiguration.ModuleTitle}) {ex.StackTrace}"; - } - } - */ - - var controlFolder = Path.GetDirectoryName(model.ModuleConfiguration.ModuleControl.ControlSrc); - var controlFileNameWithoutExtension = Path.GetFileNameWithoutExtension(model.ModuleConfiguration.ModuleControl.ControlSrc); - var srcPhysicalPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, controlFolder, "Partials", controlFileNameWithoutExtension + ".cshtml"); - if (File.Exists(srcPhysicalPath)) - { - var scriptFile = Path.Combine("~/" + controlFolder, "Partials", controlFileNameWithoutExtension + ".cshtml").Replace("\\", "/"); - try - { - moduleDiv.InnerHtml += htmlHelper.Partial(scriptFile, model.ModuleConfiguration); - } - catch (Exception ex2) - { - throw new Exception($"Error : {ex2.Message} ( razor : {scriptFile}, module : {model.ModuleConfiguration.ModuleID})", ex2); - } - } - else - { - moduleDiv.InnerHtml += htmlHelper.Control(model.ModuleConfiguration); - } - - /* - try - { - // module - moduleDiv.InnerHtml += htmlHelper.Control(model.ModuleConfiguration); - } - catch (HttpException ex) - { - var scriptFolder = Path.GetDirectoryName(model.ModuleConfiguration.ModuleControl.ControlSrc); - var fileRoot = Path.GetFileNameWithoutExtension(model.ModuleConfiguration.ModuleControl.ControlSrc); - var srcPhysicalPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, scriptFolder, "_" + fileRoot + ".cshtml"); - var scriptFile = Path.Combine("~/" + scriptFolder, "Views/", "_" + fileRoot + ".cshtml"); - if (File.Exists(srcPhysicalPath)) - { - try - { - moduleDiv.InnerHtml += htmlHelper.Partial(scriptFile, model.ModuleConfiguration); - } - catch (Exception ex2) - { - throw new Exception($"Error : {ex2.Message} ( razor : {scriptFile}, module : {model.ModuleConfiguration.ModuleID})", ex2); - } - } - else - { - // moduleDiv.InnerHtml += $"Error : {ex.Message} (Controller : {model.ControllerName}, Action : {model.ActionName}, module : {model.ModuleConfiguration.ModuleTitle}) {ex.StackTrace}"; - throw new Exception($"Error : {ex.Message} (Controller : {model.ControllerName}, Action : {model.ActionName}, module : {model.ModuleConfiguration.ModuleID})", ex); - } - } - catch (Exception ex) - { - // moduleDiv.InnerHtml += $"Error : {ex.Message} (Controller : {model.ControllerName}, Action : {model.ActionName}, module : {model.ModuleConfiguration.ModuleTitle}) {ex.StackTrace}"; - throw new Exception($"Error : {ex.Message} (Controller : {model.ControllerName}, Action : {model.ActionName}, module : {model.ModuleConfiguration.ModuleID})", ex); - } - */ - + // render module control + moduleDiv.InnerHtml += htmlHelper.Control(model.ModuleConfiguration); moduleContentPaneDiv.InnerHtml += moduleDiv.ToString(); if (!string.IsNullOrEmpty(model.Footer)) { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/DnnPageController.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/DnnPageController.cs index 248d67bc965..83a1d0322fe 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/DnnPageController.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/DnnPageController.cs @@ -17,12 +17,6 @@ public abstract class DnnPageController : Controller, IMvcController /// Initializes a new instance of the class. protected DnnPageController() { - // this.ActionInvoker = new ResultCapturingActionInvoker(); - } - - public TabInfo ActivePage - { - get { return (this.PortalSettings == null) ? null : this.PortalSettings.ActiveTab; } } public PortalSettings PortalSettings @@ -32,46 +26,5 @@ public PortalSettings PortalSettings return PortalController.Instance.GetCurrentPortalSettings(); } } - - /* - public ActionResult ResultOfLastExecute - { - get - { - var actionInvoker = this.ActionInvoker as ResultCapturingActionInvoker; - return (actionInvoker != null) ? actionInvoker.ResultOfLastInvoke : null; - } - } - */ - /* - public new UserInfo User - { - get { return (this.PortalSettings == null) ? null : this.PortalSettings.UserInfo; } - } - - public new DnnUrlHelper Url { get; set; } - */ - public string LocalResourceFile { get; set; } - - public string LocalizeString(string key) - { - return Localization.GetString(key, this.LocalResourceFile); - } - - /// - protected override void Initialize(RequestContext requestContext) - { - base.Initialize(requestContext); - - // this.Url = new DnnUrlHelper(requestContext, this); - } - - public static void RegisterAjaxScript(ControllerContext context) - { - if (MvcServicesFrameworkInternal.Instance.IsAjaxScriptSupportRequired) - { - MvcServicesFrameworkInternal.Instance.RegisterAjaxScript(context); - } - } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/JavascriptLibraries/MvcJavaScript.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/JavascriptLibraries/MvcJavaScript.cs index 989f6da77e8..3070555ce68 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/JavascriptLibraries/MvcJavaScript.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/JavascriptLibraries/MvcJavaScript.cs @@ -169,12 +169,10 @@ public static void RegisterClientReference(ControllerContext page, ClientAPI.Cli break; } - // MvcClientResourceManager.RegisterScript(page, ClientAPI.ScriptPath + "MicrosoftAjax.js", 10); MvcClientResourceManager.RegisterScript(page, ClientAPI.ScriptPath + "mvc.js", 11); MvcClientResourceManager.RegisterScript(page, ClientAPI.ScriptPath + "dnn.js", 12); HttpContextSource.Current.Items.Add(LegacyPrefix + "dnn.js", true); - // page.ClientScript.RegisterClientScriptBlock(page.GetType(), "dnn.js", string.Empty); if (!ClientAPI.BrowserSupportsFunctionality(ClientAPI.ClientFunctionality.SingleCharDelimiters)) { MvcClientAPI.RegisterClientVariable("__scdoff", "1", true); diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/DefaultController.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/DefaultController.cs index c926b68eaf4..8f8a26629ba 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/DefaultController.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/DefaultController.cs @@ -23,17 +23,13 @@ namespace DotNetNuke.Web.MvcWebsite.Controllers using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Controllers; using DotNetNuke.Web.MvcPipeline.Exceptions; - using DotNetNuke.Web.MvcPipeline.Framework; using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; + using DotNetNuke.Web.MvcPipeline.ModelFactories; using DotNetNuke.Web.MvcPipeline.Models; using DotNetNuke.Web.MvcPipeline.UI.Utilities; public class DefaultController : DnnPageController { - private static readonly Regex HeaderTextRegex = new Regex( - "])+name=('|\")robots('|\")", - RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); - private readonly INavigationManager navigationManager; private readonly IContentSecurityPolicy contentSecurityPolicy; private readonly IPageModelFactory pageModelFactory; @@ -158,13 +154,11 @@ private void InitializePage(PageModel page) } } - // this.Response.Redirect(this.NavigationManager.NavigateURL(tab.TabID, Null.NullString, parameters.ToArray()), true); throw new MvcPageException("redirect to a specific tab based on name", this.navigationManager.NavigateURL(tab.TabID, Null.NullString, parameters.ToArray())); } else { // 404 Error - Redirect to ErrorPage - // Exceptions.ProcessHttpException(this.Request); throw new NotFoundException("redirect to a specific tab based on name - tab not found"); } } diff --git a/DNN Platform/Modules/DDRMenu/Localisation/Localiser.cs b/DNN Platform/Modules/DDRMenu/Localisation/Localiser.cs index 70240a863b6..f34be3b93b2 100644 --- a/DNN Platform/Modules/DDRMenu/Localisation/Localiser.cs +++ b/DNN Platform/Modules/DDRMenu/Localisation/Localiser.cs @@ -108,7 +108,7 @@ public void LocaliseNode(MenuNode node, int portalId) node.TabId = -1; } - node.Children.ForEach(this.LocaliseNode); + node.Children.ForEach(n => this.LocaliseNode(n, portalId)); } private TabInfo LocaliseTab(TabInfo tab, int portalId) From 3f96a34e194013c92f931ec22e9447d1478baa92 Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 13:42:53 +0200 Subject: [PATCH 04/34] cleanup --- .../ContainerModelFactory.cs | 60 +-------- .../IContainerModelFactory.cs | 2 +- .../IPageModelFactory.cs | 2 +- .../IPaneModelFactory.cs | 2 +- .../ISkinModelFactory.cs | 2 +- .../PageModelFactory.cs | 87 ++++++------ .../PaneModelFactory.cs | 126 ++---------------- .../SkinModelFactory.cs | 71 +++------- 8 files changed, 82 insertions(+), 270 deletions(-) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/ContainerModelFactory.cs (76%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/IContainerModelFactory.cs (90%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/IPageModelFactory.cs (88%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/IPaneModelFactory.cs (91%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/ISkinModelFactory.cs (88%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/PageModelFactory.cs (66%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/PaneModelFactory.cs (69%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/{Framework => ModelFactories}/SkinModelFactory.cs (90%) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/ContainerModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/ContainerModelFactory.cs similarity index 76% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/ContainerModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/ContainerModelFactory.cs index 167cf9e9148..3719ddd581c 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/ContainerModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/ContainerModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using System; @@ -30,64 +30,18 @@ public ContainerModel CreateContainerModel(ModuleInfo configuration, PortalSetti private ContainerModel ProcessModule(ContainerModel container, PortalSettings portalSettings) { - /* - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"Container.ProcessModule Start (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleID: {this.ModuleConfiguration.ModuleDefinition.DesktopModuleID}): Module FriendlyName: '{this.ModuleConfiguration.ModuleDefinition.FriendlyName}')"); - } - */ // Process Content Pane Attributes container = this.ProcessContentPane(container, portalSettings); - // always add the actions menu as the first item in the content pane. - /* - if (this.InjectActionMenu && !ModuleHost.IsViewMode(this.ModuleConfiguration, this.PortalSettings) && this.Request.QueryString["dnnprintmode"] != "true") - { - MvcJavaScript.RequestRegistration(CommonJs.DnnPlugins); - this.ContentPane.Controls.Add(this.LoadControl(this.PortalSettings.DefaultModuleActionMenu)); - - // register admin.css - MvcClientResourceManager.RegisterAdminStylesheet(this.Page, Globals.HostPath + "admin.css"); - } - */ - // Process Module Header container = this.ProcessHeader(container); - // Try to load the module control - // container.moduleHost = new ModuleHostModel(this.ModuleConfiguration, this.ParentSkin, this); - // container.moduleHost.OnPreRender(); - - /* - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"Container.ProcessModule Info (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleID: {this.ModuleConfiguration.ModuleDefinition.DesktopModuleID}): ControlPane.Controls.Add(ModuleHost:{this.moduleHost.ID})"); - } - - this.ContentPane.Controls.Add(this.ModuleHost); - */ - // Process Module Footer container = this.ProcessFooter(container); - /* - // Process the Action Controls - if (this.ModuleHost != null && this.ModuleControl != null) - { - this.ProcessChildControls(this); - } - */ - // Add Module Stylesheets container = this.ProcessStylesheets(container, container.ModuleHost != null); - /* - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"Container.ProcessModule End (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleID: {this.ModuleConfiguration.ModuleDefinition.DesktopModuleID}): Module FriendlyName: '{this.ModuleConfiguration.ModuleDefinition.FriendlyName}')"); - } - */ - return container; } @@ -100,12 +54,12 @@ private ContainerModel ProcessContentPane(ContainerModel container, PortalSettin container = this.SetBorder(container); // display visual indicator if module is only visible to administrators - string viewRoles = container.ModuleConfiguration.InheritViewPermissions + var viewRoles = container.ModuleConfiguration.InheritViewPermissions ? TabPermissionController.GetTabPermissions(container.ModuleConfiguration.TabID, container.ModuleConfiguration.PortalID).ToString("VIEW") : container.ModuleConfiguration.ModulePermissions.ToString("VIEW"); - string pageEditRoles = TabPermissionController.GetTabPermissions(container.ModuleConfiguration.TabID, container.ModuleConfiguration.PortalID).ToString("EDIT"); - string moduleEditRoles = container.ModuleConfiguration.ModulePermissions.ToString("EDIT"); + var pageEditRoles = TabPermissionController.GetTabPermissions(container.ModuleConfiguration.TabID, container.ModuleConfiguration.PortalID).ToString("EDIT"); + var moduleEditRoles = container.ModuleConfiguration.ModulePermissions.ToString("EDIT"); viewRoles = viewRoles.Replace(";", string.Empty).Trim().ToLowerInvariant(); pageEditRoles = pageEditRoles.Replace(";", string.Empty).Trim().ToLowerInvariant(); @@ -195,10 +149,10 @@ private ContainerModel ProcessStylesheets(ContainerModel container, bool include // process the base class module properties if (includeModuleCss) { - string controlSrc = container.ModuleConfiguration.ModuleControl.ControlSrc; - string folderName = container.ModuleConfiguration.DesktopModule.FolderName; + var controlSrc = container.ModuleConfiguration.ModuleControl.ControlSrc; + var folderName = container.ModuleConfiguration.DesktopModule.FolderName; - string stylesheet = string.Empty; + var stylesheet = string.Empty; if (string.IsNullOrEmpty(folderName) == false) { if (controlSrc.EndsWith(".mvc")) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IContainerModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IContainerModelFactory.cs similarity index 90% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IContainerModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IContainerModelFactory.cs index 59e155483d1..2a59e03e4b8 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IContainerModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IContainerModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using DotNetNuke.Entities.Modules; using DotNetNuke.Entities.Portals; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IPageModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IPageModelFactory.cs similarity index 88% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IPageModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IPageModelFactory.cs index 2b764cd76c7..8053207baf3 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IPageModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IPageModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using DotNetNuke.Web.MvcPipeline.Controllers; using DotNetNuke.Web.MvcPipeline.Models; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IPaneModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IPaneModelFactory.cs similarity index 91% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IPaneModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IPaneModelFactory.cs index c2f3dbe9a70..46be767d049 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/IPaneModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/IPaneModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using DotNetNuke.Entities.Modules; using DotNetNuke.Entities.Portals; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/ISkinModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/ISkinModelFactory.cs similarity index 88% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/ISkinModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/ISkinModelFactory.cs index be29eaf77ca..3183943c37a 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/ISkinModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/ISkinModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using DotNetNuke.Web.MvcPipeline.Controllers; using DotNetNuke.Web.MvcPipeline.Models; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/PageModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PageModelFactory.cs similarity index 66% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/PageModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PageModelFactory.cs index a4fb00ead9b..af66d157f6c 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/PageModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PageModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using System; using System.IO; @@ -40,6 +40,7 @@ public class PageModelFactory : IPageModelFactory private readonly IModuleControlPipeline moduleControlPipeline; private readonly IApplicationInfo applicationInfo; private readonly ISkinModelFactory skinModelFactory; + private readonly IHostSettings hostSettings; public PageModelFactory( IContentSecurityPolicy contentSecurityPolicy, @@ -47,7 +48,8 @@ public PageModelFactory( IPortalController portalController, IModuleControlPipeline moduleControlPipeline, IApplicationInfo applicationInfo, - ISkinModelFactory skinModelFactory) + ISkinModelFactory skinModelFactory, + IHostSettings hostSettings) { this.contentSecurityPolicy = contentSecurityPolicy; this.navigationManager = navigationManager; @@ -55,43 +57,44 @@ public PageModelFactory( this.moduleControlPipeline = moduleControlPipeline; this.applicationInfo = applicationInfo; this.skinModelFactory = skinModelFactory; + this.hostSettings = hostSettings; } - public PageModel CreatePageModel(DnnPageController page) + public PageModel CreatePageModel(DnnPageController controller) { - var ctl = page.Request.QueryString["ctl"] != null ? page.Request.QueryString["ctl"] : string.Empty; + var ctl = controller.Request.QueryString["ctl"] != null ? controller.Request.QueryString["ctl"] : string.Empty; var pageModel = new PageModel { IsEditMode = Globals.IsEditMode(), AntiForgery = AntiForgery.GetHtml().ToHtmlString(), - PortalId = page.PortalSettings.PortalId, - TabId = page.PortalSettings.ActiveTab.TabID, + PortalId = controller.PortalSettings.PortalId, + TabId = controller.PortalSettings.ActiveTab.TabID, Language = Thread.CurrentThread.CurrentCulture.Name, ContentSecurityPolicy = this.contentSecurityPolicy, NavigationManager = this.navigationManager, - FavIconLink = FavIcon.GetHeaderLink(page.PortalSettings.PortalId), + FavIconLink = FavIcon.GetHeaderLink(hostSettings, controller.PortalSettings.PortalId), }; - if (page.PortalSettings.ActiveTab.PageHeadText != Null.NullString && !Globals.IsAdminControl()) + if (controller.PortalSettings.ActiveTab.PageHeadText != Null.NullString && !Globals.IsAdminControl()) { - pageModel.PageHeadText = page.PortalSettings.ActiveTab.PageHeadText; + pageModel.PageHeadText = controller.PortalSettings.ActiveTab.PageHeadText; } - if (!string.IsNullOrEmpty(page.PortalSettings.PageHeadText)) + if (!string.IsNullOrEmpty(controller.PortalSettings.PageHeadText)) { - pageModel.PortalHeadText = page.PortalSettings.PageHeadText; + pageModel.PortalHeadText = controller.PortalSettings.PageHeadText; } // set page title if (UrlUtils.InPopUp()) { - var strTitle = new StringBuilder(page.PortalSettings.PortalName); - var slaveModule = DotNetNuke.UI.UIUtilities.GetSlaveModule(page.PortalSettings.ActiveTab.TabID); + var strTitle = new StringBuilder(controller.PortalSettings.PortalName); + var slaveModule = DotNetNuke.UI.UIUtilities.GetSlaveModule(controller.PortalSettings.ActiveTab.TabID); // Skip is popup is just a tab (no slave module) if (slaveModule.DesktopModuleID != Null.NullInteger) { var control = this.moduleControlPipeline.CreateModuleControl(slaveModule) as IModuleControl; - string extension = Path.GetExtension(slaveModule.ModuleControl.ControlSrc.ToLowerInvariant()); + var extension = Path.GetExtension(slaveModule.ModuleControl.ControlSrc.ToLowerInvariant()); switch (extension) { case ".mvc": @@ -116,12 +119,12 @@ public PageModel CreatePageModel(DnnPageController page) var title = Localization.LocalizeControlTitle(control); - strTitle.Append(string.Concat(" > ", page.PortalSettings.ActiveTab.LocalizedTabName)); + strTitle.Append(string.Concat(" > ", controller.PortalSettings.ActiveTab.LocalizedTabName)); strTitle.Append(string.Concat(" > ", title)); } else { - strTitle.Append(string.Concat(" > ", page.PortalSettings.ActiveTab.LocalizedTabName)); + strTitle.Append(string.Concat(" > ", controller.PortalSettings.ActiveTab.LocalizedTabName)); } // Set to page @@ -130,15 +133,15 @@ public PageModel CreatePageModel(DnnPageController page) else { // If tab is named, use that title, otherwise build it out via breadcrumbs - if (!string.IsNullOrEmpty(page.PortalSettings.ActiveTab.Title)) + if (!string.IsNullOrEmpty(controller.PortalSettings.ActiveTab.Title)) { - pageModel.Title = page.PortalSettings.ActiveTab.Title; + pageModel.Title = controller.PortalSettings.ActiveTab.Title; } else { // Elected for SB over true concatenation here due to potential for long nesting depth - var strTitle = new StringBuilder(page.PortalSettings.PortalName); - foreach (TabInfo tab in page.PortalSettings.ActiveTab.BreadCrumbs) + var strTitle = new StringBuilder(controller.PortalSettings.PortalName); + foreach (TabInfo tab in controller.PortalSettings.ActiveTab.BreadCrumbs) { strTitle.Append(string.Concat(" > ", tab.TabName)); } @@ -150,9 +153,9 @@ public PageModel CreatePageModel(DnnPageController page) // set the background image if there is one selected if (!UrlUtils.InPopUp()) { - if (!string.IsNullOrEmpty(page.PortalSettings.BackgroundFile)) + if (!string.IsNullOrEmpty(controller.PortalSettings.BackgroundFile)) { - var fileInfo = this.GetBackgroundFileInfo(page.PortalSettings); + var fileInfo = this.GetBackgroundFileInfo(controller.PortalSettings); pageModel.BackgroundUrl = FileManager.Instance.GetUrl(fileInfo); // ((HtmlGenericControl)this.FindControl("Body")).Attributes["style"] = string.Concat("background-image: url('", url, "')"); @@ -161,39 +164,39 @@ public PageModel CreatePageModel(DnnPageController page) // META Refresh // Only autorefresh the page if we are in VIEW-mode and if we aren't displaying some module's subcontrol. - if (page.PortalSettings.ActiveTab.RefreshInterval > 0 && Personalization.GetUserMode() == PortalSettings.Mode.View && string.IsNullOrEmpty(ctl)) + if (controller.PortalSettings.ActiveTab.RefreshInterval > 0 && Personalization.GetUserMode() == PortalSettings.Mode.View && string.IsNullOrEmpty(ctl)) { - pageModel.MetaRefresh = page.PortalSettings.ActiveTab.RefreshInterval.ToString(); + pageModel.MetaRefresh = controller.PortalSettings.ActiveTab.RefreshInterval.ToString(); } // META description - if (!string.IsNullOrEmpty(page.PortalSettings.ActiveTab.Description)) + if (!string.IsNullOrEmpty(controller.PortalSettings.ActiveTab.Description)) { - pageModel.Description = page.PortalSettings.ActiveTab.Description; + pageModel.Description = controller.PortalSettings.ActiveTab.Description; } else { - pageModel.Description = page.PortalSettings.Description; + pageModel.Description = controller.PortalSettings.Description; } // META keywords - if (!string.IsNullOrEmpty(page.PortalSettings.ActiveTab.KeyWords)) + if (!string.IsNullOrEmpty(controller.PortalSettings.ActiveTab.KeyWords)) { - pageModel.KeyWords = page.PortalSettings.ActiveTab.KeyWords; + pageModel.KeyWords = controller.PortalSettings.ActiveTab.KeyWords; } else { - pageModel.KeyWords = page.PortalSettings.KeyWords; + pageModel.KeyWords = controller.PortalSettings.KeyWords; } // META copyright - if (!string.IsNullOrEmpty(page.PortalSettings.FooterText)) + if (!string.IsNullOrEmpty(controller.PortalSettings.FooterText)) { - pageModel.Copyright = page.PortalSettings.FooterText.Replace("[year]", DateTime.Now.Year.ToString()); + pageModel.Copyright = controller.PortalSettings.FooterText.Replace("[year]", DateTime.Now.Year.ToString()); } else { - pageModel.Copyright = string.Concat("Copyright (c) ", DateTime.Now.Year, " by ", page.PortalSettings.PortalName); + pageModel.Copyright = string.Concat("Copyright (c) ", DateTime.Now.Year, " by ", controller.PortalSettings.PortalName); } // META generator @@ -201,13 +204,13 @@ public PageModel CreatePageModel(DnnPageController page) // META Robots - hide it inside popups and if PageHeadText of current tab already contains a robots meta tag if (!UrlUtils.InPopUp() && - !(HeaderTextRegex.IsMatch(page.PortalSettings.ActiveTab.PageHeadText) || - HeaderTextRegex.IsMatch(page.PortalSettings.PageHeadText))) + !(HeaderTextRegex.IsMatch(controller.PortalSettings.ActiveTab.PageHeadText) || + HeaderTextRegex.IsMatch(controller.PortalSettings.PageHeadText))) { var allowIndex = true; - if ((page.PortalSettings.ActiveTab.TabSettings.ContainsKey("AllowIndex") && - bool.TryParse(page.PortalSettings.ActiveTab.TabSettings["AllowIndex"].ToString(), out allowIndex) && - !allowIndex) || ctl == "Login" || ctl == "Register") + if (controller.PortalSettings.ActiveTab.TabSettings.ContainsKey("AllowIndex") && + bool.TryParse(controller.PortalSettings.ActiveTab.TabSettings["AllowIndex"].ToString(), out allowIndex) && + !allowIndex || ctl == "Login" || ctl == "Register") { pageModel.MetaRobots = "NOINDEX, NOFOLLOW"; } @@ -220,21 +223,21 @@ public PageModel CreatePageModel(DnnPageController page) // NonProduction Label Injection if (this.applicationInfo.Status != Abstractions.Application.ReleaseMode.Stable && Host.DisplayBetaNotice && !UrlUtils.InPopUp()) { - string versionString = + var versionString = $" ({this.applicationInfo.Status} Version: {this.applicationInfo.Version})"; pageModel.Title += versionString; } - pageModel.Skin = this.skinModelFactory.CreateSkinModel(page); + pageModel.Skin = this.skinModelFactory.CreateSkinModel(controller); return pageModel; } private IFileInfo GetBackgroundFileInfo(PortalSettings portalSettings) { - string cacheKey = string.Format(Common.Utilities.DataCache.PortalCacheKey, portalSettings.PortalId, "BackgroundFile"); + var cacheKey = string.Format(DataCache.PortalCacheKey, portalSettings.PortalId, "BackgroundFile"); var file = CBO.GetCachedObject( - new CacheItemArgs(cacheKey, Common.Utilities.DataCache.PortalCacheTimeOut, Common.Utilities.DataCache.PortalCachePriority, portalSettings.PortalId, portalSettings.BackgroundFile), + new CacheItemArgs(cacheKey, DataCache.PortalCacheTimeOut, DataCache.PortalCachePriority, portalSettings.PortalId, portalSettings.BackgroundFile), this.GetBackgroundFileInfoCallBack); return file; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/PaneModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs similarity index 69% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/PaneModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs index aa3b9ab7496..7d233e9e708 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/PaneModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using System; using System.IO; @@ -40,8 +40,8 @@ public PaneModel InjectModule(PaneModel pane, ModuleInfo module, PortalSettings // this.PaneControl.Controls.Add(this.containerWrapperControl); // inject module classes - string classFormatString = "DnnModule DnnModule-{0} DnnModule-{1}"; - string sanitizedModuleName = Null.NullString; + var classFormatString = "DnnModule DnnModule-{0} DnnModule-{1}"; + var sanitizedModuleName = Null.NullString; if (!string.IsNullOrEmpty(module.DesktopModule.ModuleName)) { @@ -62,79 +62,10 @@ public PaneModel InjectModule(PaneModel pane, ModuleInfo module, PortalSettings } // Load container control - ContainerModel container = this.LoadModuleContainer(module, portalSettings); + var container = this.LoadModuleContainer(module, portalSettings); // Add Container to Dictionary pane.Containers.Add(container.ID, container); - - // hide anything of type ActionsMenu - as we're injecting our own menu now. - /* - container.InjectActionMenu = container.Controls.OfType().Count() == 0; - if (!container.InjectActionMenu) - { - foreach (var actionControl in container.Controls.OfType()) - { - if (actionControl is ActionsMenu) - { - Control control = actionControl as Control; - if (control != null) - { - control.Visible = false; - container.InjectActionMenu = true; - } - } - } - } - - if (Globals.IsLayoutMode() && Globals.IsAdminControl() == false) - { - // provide Drag-N-Drop capabilities - var dragDropContainer = new Panel(); - Control title = container.FindControl("dnnTitle"); - - // Assume that the title control is named dnnTitle. If this becomes an issue we could loop through the controls looking for the title type of skin object - dragDropContainer.ID = container.ID + "_DD"; - this.containerWrapperControl.Controls.Add(dragDropContainer); - - // inject the container into the page pane - this triggers the Pre_Init() event for the user control - dragDropContainer.Controls.Add(container); - - if (title != null) - { - if (title.Controls.Count > 0) - { - title = title.Controls[0]; - } - } - - // enable drag and drop - if (title != null) - { - // The title ID is actually the first child so we need to make sure at least one child exists - DNNClientAPI.EnableContainerDragAndDrop(title, dragDropContainer, module.ModuleID); - ClientAPI.RegisterPostBackEventHandler(this.PaneControl, "MoveToPane", this.ModuleMoveToPanePostBack, false); - } - } - else - { - this.containerWrapperControl.Controls.Add(container); - if (Globals.IsAdminControl()) - { - this.containerWrapperControl.Attributes["class"] += " DnnModule-Admin"; - } - } - */ - - // Attach Module to Container - // container.SetModuleConfiguration(module); - - // display collapsible page panes - /* - if (this.PaneControl.Visible == false) - { - this.PaneControl.Visible = true; - } - */ } catch (ThreadAbortException) { @@ -160,12 +91,6 @@ public PaneModel InjectModule(PaneModel pane, ModuleInfo module, PortalSettings public PaneModel ProcessPane(PaneModel pane) { - /* - // remove excess skin non-validating attributes - this.PaneControl.Attributes.Remove("ContainerType"); - this.PaneControl.Attributes.Remove("ContainerName"); - this.PaneControl.Attributes.Remove("ContainerSrc"); - */ if (Globals.IsLayoutMode()) { /* @@ -189,20 +114,8 @@ public PaneModel ProcessPane(PaneModel pane) } else { - /* - if (this.PaneControl.Visible == false && TabPermissionController.CanAddContentToPage()) - { - this.PaneControl.Visible = true; - }*/ if (this.CanCollapsePane(pane)) { - // This pane has no controls so set the width to 0 - /* - if (this.PaneControl.Attributes["style"] != null) - { - this.PaneControl.Attributes.Remove("style"); - } - */ pane.CssClass += " DNNEmptyPane"; } @@ -211,7 +124,6 @@ public PaneModel ProcessPane(PaneModel pane) { pane.CssClass += " dnnSortable"; - // this call also checks for permission } } @@ -224,33 +136,13 @@ private bool CanCollapsePane(PaneModel pane) // This preserves the integrity of the HTML syntax so we don't have to set // the visiblity of a pane to false. Setting the visibility of a pane to // false where there are colspans and rowspans can render the skin incorrectly. - bool canCollapsePane = true; + var canCollapsePane = true; if (pane.Containers.Count > 0) { canCollapsePane = false; } - /* - else if (this.PaneControl.Controls.Count == 1) - { - // Pane contains 1 control - canCollapsePane = false; - var literal = this.PaneControl.Controls[0] as LiteralControl; - if (literal != null) - { - // Check if the literal control is just whitespace - if so we can collapse panes - if (string.IsNullOrEmpty(HtmlUtils.StripWhiteSpace(literal.Text, false))) - { - canCollapsePane = true; - } - } - } - else if (this.PaneControl.Controls.Count > 1) - { - // Pane contains more than 1 control - canCollapsePane = false; - } - */ + return canCollapsePane; } @@ -261,14 +153,14 @@ private bool IsVesionableModule(ModuleInfo moduleInfo) return false; } - object controller = DotNetNuke.Framework.Reflection.CreateObject(moduleInfo.DesktopModule.BusinessControllerClass, string.Empty); + var controller = DotNetNuke.Framework.Reflection.CreateObject(moduleInfo.DesktopModule.BusinessControllerClass, string.Empty); return controller is IVersionable; } private ContainerModel LoadContainerFromCookie(HttpRequest request, PortalSettings portalSettings) { ContainerModel container = null; - HttpCookie cookie = request.Cookies["_ContainerSrc" + portalSettings.PortalId]; + var cookie = request.Cookies["_ContainerSrc" + portalSettings.PortalId]; if (cookie != null) { if (!string.IsNullOrEmpty(cookie.Value)) @@ -387,7 +279,7 @@ private ContainerModel LoadContainerByPath(string containerPath, ModuleInfo modu try { - string containerSrc = containerPath; + var containerSrc = containerPath; if (containerPath.IndexOf(Globals.ApplicationPath, StringComparison.InvariantCultureIgnoreCase) != -1) { containerPath = containerPath.Remove(0, Globals.ApplicationPath.Length); diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/SkinModelFactory.cs similarity index 90% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/SkinModelFactory.cs index eeb9d8d784b..8cbc72fd9ce 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Framework/SkinModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/SkinModelFactory.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.Framework +namespace DotNetNuke.Web.MvcPipeline.ModelFactories { using System; using System.IO; @@ -54,7 +54,7 @@ public SkinModelFactory(INavigationManager navigationManager, IPaneModelFactory public SkinModel CreateSkinModel(DnnPageController page) { SkinModel skin = null; - string skinSource = Null.NullString; + var skinSource = Null.NullString; if (page.PortalSettings.EnablePopUps && UrlUtils.InPopUp()) { @@ -79,11 +79,6 @@ public SkinModel CreateSkinModel(DnnPageController page) // set skin path page.PortalSettings.ActiveTab.SkinPath = SkinController.FormatSkinPath(skinSource); - - // set skin id to an explicit short name to reduce page payload and make it standards compliant - /* - skin.ID = "dnn"; - */ } else { @@ -97,7 +92,7 @@ public SkinModel CreateSkinModel(DnnPageController page) // load user skin ( based on cookie ) if (skin == null) { - HttpCookie skinCookie = page.Request.Cookies["_SkinSrc" + page.PortalSettings.PortalId]; + var skinCookie = page.Request.Cookies["_SkinSrc" + page.PortalSettings.PortalId]; if (skinCookie != null) { if (!string.IsNullOrEmpty(skinCookie.Value)) @@ -112,7 +107,6 @@ public SkinModel CreateSkinModel(DnnPageController page) if (skin == null) { // DNN-6170 ensure skin value is culture specific - // skinSource = Globals.IsAdminSkin() ? SkinController.FormatSkinSrc(page.page.PortalSettings.DefaultAdminSkin, page.page.PortalSettings) : page.page.PortalSettings.ActiveTab.SkinSrc; skinSource = Globals.IsAdminSkin() ? PortalController.GetPortalSetting("DefaultAdminSkin", page.PortalSettings.PortalId, Host.DefaultPortalSkin, page.PortalSettings.CultureCode) : page.PortalSettings.ActiveTab.SkinSrc; if (!string.IsNullOrEmpty(skinSource)) { @@ -130,11 +124,6 @@ public SkinModel CreateSkinModel(DnnPageController page) // set skin path page.PortalSettings.ActiveTab.SkinPath = SkinController.FormatSkinPath(skinSource); - - // set skin id to an explicit short name to reduce page payload and make it standards compliant - /* - skin.ID = "dnn"; - */ } if (page.PortalSettings.ActiveTab.DisableLink) @@ -181,32 +170,20 @@ private SkinModel LoadSkin(DnnPageController page, string skinPath) SkinModel ctlSkin = null; try { - string skinSrc = skinPath; + var skinSrc = skinPath; if (skinPath.IndexOf(Globals.ApplicationPath, StringComparison.OrdinalIgnoreCase) != -1) { skinPath = skinPath.Remove(0, Globals.ApplicationPath.Length); } - /* - ctlSkin = ControlUtilities.LoadControl(page, skinPath); - */ ctlSkin = new SkinModel(); - ctlSkin.SkinSrc = skinSrc; - // call databind so that any server logic in the skin is executed - /* - ctlSkin.DataBind(); - */ - // Load the Panes this.LoadPanes(page.PortalSettings); // Load the Module Control(s) - bool success = Globals.IsAdminControl() ? this.ProcessSlaveModule(page.PortalSettings, ctlSkin) : this.ProcessMasterModules(page.PortalSettings, ctlSkin); - /* - this.ProcessMasterModules(); - */ + var success = Globals.IsAdminControl() ? this.ProcessSlaveModule(page.PortalSettings, ctlSkin) : this.ProcessMasterModules(page.PortalSettings, ctlSkin); // Load the Control Panel this.InjectControlPanel(ctlSkin, page.Request); @@ -235,8 +212,6 @@ private SkinModel LoadSkin(DnnPageController page, string skinPath) } /* - this.InvokeSkinEvents(SkinEventType.OnSkinInit); - if (HttpContext.Current != null && HttpContext.Current.Items.Contains(OnInitMessage)) { var messageType = ModuleMessage.ModuleMessageType.YellowWarning; @@ -255,10 +230,9 @@ private SkinModel LoadSkin(DnnPageController page, string skinPath) // Process the Panes attributes foreach (var key in ctlSkin.Panes.Keys) { - /*ctlSkin.Panes[key] =*/ this.paneModelFactory.ProcessPane(ctlSkin.Panes[key]); + this.paneModelFactory.ProcessPane(ctlSkin.Panes[key]); } - // this.InvokeSkinEvents(SkinEventType.OnSkinPreRender); var isSpecialPageMode = UrlUtils.InPopUp() || page.Request.QueryString["dnnprintmode"] == "true"; if (TabPermissionController.CanAddContentToPage() && Globals.IsEditMode() && !isSpecialPageMode) { @@ -286,17 +260,6 @@ private SkinModel LoadSkin(DnnPageController page, string skinPath) sb.AppendLine(" } (jQuery));"); var script = sb.ToString(); - /* - if (ScriptManager.GetCurrent(this.Page) != null) - { - // respect MS AJAX - ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "DragAndDrop", script, true); - } - else - { - this.Page.ClientScript.RegisterStartupScript(this.GetType(), "DragAndDrop", script, true); - } - */ MvcClientAPI.RegisterStartupScript("DragAndDrop", script); } } @@ -390,7 +353,7 @@ private void LoadPanes(PortalSettings portalSettings) private bool ProcessMasterModules(PortalSettings portalSettings, SkinModel skin) { - bool success = true; + var success = true; if (TabPermissionController.CanViewPage()) { // We need to ensure that Content Item exists since in old versions Content Items are not needed for tabs @@ -423,7 +386,7 @@ private bool ProcessMasterModules(PortalSettings portalSettings, SkinModel skin) // check portal expiry date if (!this.CheckExpired(portalSettings)) { - if ((portalSettings.ActiveTab.StartDate < DateTime.Now && portalSettings.ActiveTab.EndDate > DateTime.Now) || TabPermissionController.CanAdminPage() || Globals.IsLayoutMode()) + if (portalSettings.ActiveTab.StartDate < DateTime.Now && portalSettings.ActiveTab.EndDate > DateTime.Now || TabPermissionController.CanAdminPage() || Globals.IsLayoutMode()) { foreach (var objModule in PortalSettingsController.Instance().GetTabModules(portalSettings)) { @@ -452,7 +415,7 @@ private bool ProcessMasterModules(PortalSettings portalSettings, SkinModel skin) var redirectUrl = Globals.AccessDeniedURL(Localization.GetString("TabAccess.Error")); // Current locale will use default if did'nt find any - Locale currentLocale = LocaleController.Instance.GetCurrentLocale(portalSettings.PortalId); + var currentLocale = LocaleController.Instance.GetCurrentLocale(portalSettings.PortalId); if (portalSettings.ContentLocalizationEnabled && TabController.CurrentPage.CultureCode != currentLocale.Code) { @@ -541,7 +504,7 @@ private bool ProcessModule(PortalSettings portalSettings, SkinModel skin, Module // We need to ensure that Content Item exists since in old versions Content Items are not needed for modules this.EnsureContentItemForModule(module); - PaneModel pane = this.GetPane(skin, module); + var pane = this.GetPane(skin, module); if (pane != null) { @@ -562,7 +525,7 @@ private bool ProcessModule(PortalSettings portalSettings, SkinModel skin, Module private PaneModel GetPane(SkinModel skin, ModuleInfo module) { PaneModel pane; - bool found = skin.Panes.TryGetValue(module.PaneName.ToLowerInvariant(), out pane); + var found = skin.Panes.TryGetValue(module.PaneName.ToLowerInvariant(), out pane); if (!found) { @@ -581,7 +544,7 @@ private void HandleAccesDenied(bool v) private bool CheckExpired(PortalSettings portalSettings) { - bool blnExpired = false; + var blnExpired = false; if (portalSettings.ExpiryDate != Null.NullDate) { if (Convert.ToDateTime(portalSettings.ExpiryDate) < DateTime.Now && !Globals.IsHostTab(portalSettings.ActiveTab.TabID)) @@ -665,14 +628,14 @@ private void AddPageMessage(SkinModel skin, string heading, string message, Modu { if (!string.IsNullOrEmpty(message)) { - ModuleMessageModel moduleMessage = this.GetModuleMessage(heading, message, moduleMessageType, iconSrc); + var moduleMessage = this.GetModuleMessage(heading, message, moduleMessageType, iconSrc); skin.ModuleMessages.Insert(0, moduleMessage); } } private bool InjectModule(PortalSettings portalSettings, PaneModel pane, ModuleInfo module) { - bool bSuccess = true; + var bSuccess = true; // try to inject the module into the pane try @@ -707,9 +670,9 @@ private bool InjectModule(PortalSettings portalSettings, PaneModel pane, ModuleI private IFileInfo GetPageStylesheetFileInfo(string styleSheet, int portalId) { - string cacheKey = string.Format(Common.Utilities.DataCache.PortalCacheKey, portalId, "PageStylesheet" + styleSheet); + var cacheKey = string.Format(DataCache.PortalCacheKey, portalId, "PageStylesheet" + styleSheet); var file = CBO.GetCachedObject( - new CacheItemArgs(cacheKey, Common.Utilities.DataCache.PortalCacheTimeOut, Common.Utilities.DataCache.PortalCachePriority, styleSheet, portalId), + new CacheItemArgs(cacheKey, DataCache.PortalCacheTimeOut, DataCache.PortalCachePriority, styleSheet, portalId), this.GetPageStylesheetInfoCallBack); return file; @@ -731,7 +694,7 @@ private string GetCssVariablesStylesheet(int portalId, Abstractions.Portals.IPor DataCache.PortalCachePriority, portalStyles, homeSystemDirectory); - string filePath = CBO.GetCachedObject(cacheArgs, this.GetCssVariablesStylesheetCallback); + var filePath = CBO.GetCachedObject(cacheArgs, this.GetCssVariablesStylesheetCallback); return filePath; } From 82e169bc8d93ddb27546cc9f2c14458e514ed4c7 Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 13:46:59 +0200 Subject: [PATCH 05/34] Module Controls : new way to make modules compatible with mvc pipeline --- .../Controllers/ModuleViewControllerBase.cs | 22 +- .../DotNetNuke.Web.MvcPipeline.csproj | 2 +- .../DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs | 183 ++------- ...Base.cs => DefaultMvcModuleControlBase.cs} | 229 +++-------- .../ModuleControl/IMvcModuleControl.cs | 22 ++ .../ModuleControl/IResourcable.cs | 11 + .../ModuleControl/ModuleResources.cs | 13 + .../ModuleControl/ModuleScript.cs | 12 + .../ModuleControl/ModuleStyleSheet.cs | 12 + .../ModuleControl/MvcModuleControl.cs | 211 ++++++++++ .../MvcModuleControlExtensions.cs | 231 +++++++++++ .../ModuleControl/MvcModuleControlRenderer.cs | 75 ++++ .../ModuleControl/RazorModuleControlBase.cs | 33 ++ .../ModuleControl/SpaModuleControl.cs | 147 +++++++ .../Modules/ModuleHelpers.TextEditor.cs | 5 +- .../{ => Modules}/PermissionTriStateHelper.cs | 4 +- .../DotNetNuke.Web.MvcPipeline/Startup.cs | 2 +- .../Tokens/MvcCssPropertyAccess.cs | 53 +++ .../Tokens/MvcHtml5ModuleTokenReplace.cs | 74 ++++ .../Tokens/MvcHtmlTokenReplace.cs | 26 ++ .../Tokens/MvcJavaScriptPropertyAccess.cs | 92 +++++ .../Tokens/MvcRequestPropertyAccess.cs | 53 +++ .../UI/Utilities/MvcUtils.cs | 74 +++- .../Utils/ViewRenderer.cs | 368 ++++++++++++++++++ .../Controllers/PrivacyViewController.cs | 20 - .../Controllers/TermsViewController.cs | 20 - .../ModuleActionsControl.cs} | 119 +++--- .../Controls/PrivacyControl.cs | 26 ++ .../Controls/TermsControl.cs | 27 ++ .../Controllers/EditHTMLViewController.cs | 5 +- .../Controllers/HtmlModuleViewController.cs | 2 + .../HTML/Controllers/MyWorkViewController.cs | 2 + .../HTML/DotNetNuke.Modules.Html.csproj | 10 + DNN Platform/Modules/HTML/HtmlModule.ascx.cs | 2 + .../Modules/HTML/Mvc/EditHTMLControl.cs | 154 ++++++++ .../Modules/HTML/Mvc/HtmlModuleControl.cs | 25 +- .../Modules/HTML/Mvc/MyWorkControl.cs | 102 +++++ DNN Platform/Modules/HTML/MyWork.ascx.cs | 30 +- DNN Platform/Modules/HTML/MyWorkOld.ascx | 25 ++ DNN Platform/Modules/HTML/MyWorkOld.ascx.cs | 59 +++ .../Modules/HTML/MyWorkOld.ascx.designer.cs | 44 +++ .../Website/DotNetNuke.Website.csproj | 4 +- .../ModuleActions.cshtml} | 0 .../Invoke.cshtml => Default/Pricacy.cshtml} | 0 .../Invoke.cshtml => Default/Terms.cshtml} | 0 45 files changed, 2185 insertions(+), 445 deletions(-) rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{ModuleControlBase.cs => DefaultMvcModuleControlBase.cs} (56%) create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IMvcModuleControl.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs rename DNN Platform/DotNetNuke.Web.MvcPipeline/{ => Modules}/PermissionTriStateHelper.cs (98%) create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcCssPropertyAccess.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtml5ModuleTokenReplace.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtmlTokenReplace.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcJavaScriptPropertyAccess.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcRequestPropertyAccess.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs delete mode 100644 DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/PrivacyViewController.cs delete mode 100644 DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/TermsViewController.cs rename DNN Platform/DotNetNuke.Web.MvcWebsite/{Controllers/ModuleActionsViewController.cs => Controls/ModuleActionsControl.cs} (78%) create mode 100644 DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs create mode 100644 DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs create mode 100644 DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs create mode 100644 DNN Platform/Modules/HTML/MyWorkOld.ascx create mode 100644 DNN Platform/Modules/HTML/MyWorkOld.ascx.cs create mode 100644 DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs rename DNN Platform/Website/Views/{ModuleActionsView/Invoke.cshtml => Default/ModuleActions.cshtml} (100%) rename DNN Platform/Website/Views/{PrivacyView/Invoke.cshtml => Default/Pricacy.cshtml} (100%) rename DNN Platform/Website/Views/{TermsView/Invoke.cshtml => Default/Terms.cshtml} (100%) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/ModuleViewControllerBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/ModuleViewControllerBase.cs index d715ad2614d..dd0075f8a11 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/ModuleViewControllerBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Controllers/ModuleViewControllerBase.cs @@ -199,7 +199,7 @@ public string LocalResourceFile string fileRoot; if (string.IsNullOrEmpty(this.localResourceFile)) { - fileRoot = Path.Combine(this.ControlPath, Localization.LocalResourceDirectory + "/" + this.ID); + fileRoot = "~/DesktopModules/" + this.FolderName + "/" + Localization.LocalResourceDirectory + "/" + this.ResourceName; } else { @@ -215,8 +215,20 @@ public string LocalResourceFile } } - public abstract string ControlPath { get; } - public abstract string ID { get; } + public virtual string FolderName + { + get + { + return this.moduleContext.Configuration.DesktopModule.FolderName; + } + } + public virtual string ResourceName + { + get + { + return this.GetType().Name.Replace("ViewController", ""); + } + } public string EditUrl() { @@ -268,7 +280,7 @@ public virtual ActionResult Invoke(ControlViewModel input) { this.moduleContext = new ModuleInstanceContext(); var activeModule = ModuleController.Instance.GetModule(input.ModuleId, input.TabId, false); - + if (activeModule.ModuleControlId != input.ModuleControlId) { activeModule = activeModule.Clone(); @@ -294,6 +306,6 @@ protected ActionResult PartialView(ModuleInfo module, string viewName, object mo { return this.View(MvcUtils.GetControlViewName(module, viewName), model); } - + } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/DotNetNuke.Web.MvcPipeline.csproj b/DNN Platform/DotNetNuke.Web.MvcPipeline/DotNetNuke.Web.MvcPipeline.csproj index 5c0c5b1c956..b75b1cc79d1 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/DotNetNuke.Web.MvcPipeline.csproj +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/DotNetNuke.Web.MvcPipeline.csproj @@ -1,4 +1,4 @@ - + DotNetNuke.Web.MvcPipeline net48 diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs index 2d93074aa7c..c09bd52c4a9 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs @@ -5,181 +5,60 @@ namespace DotNetNuke.Web.MvcPipeline { using System; - using System.Net.Http; + using System.IO; + using System.Linq; using System.Web; using System.Web.Helpers; using System.Web.Mvc; - using System.Web.Mvc.Html; - using System.Web.Routing; - using DotNetNuke.Common.Utilities; using DotNetNuke.Entities.Modules; using DotNetNuke.Framework; - using DotNetNuke.Services.Localization; - using DotNetNuke.UI.Modules; - - // using DotNetNuke.Framework.Models; - using DotNetNuke.Collections; + using DotNetNuke.Framework.JavaScriptLibraries; + using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Framework; - using DotNetNuke.Web.MvcPipeline.Models; + using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; + using DotNetNuke.Web.MvcPipeline.ModuleControl; using DotNetNuke.Web.MvcPipeline.UI.Utilities; - using System.Linq; - using System.Reflection; - using System.IO; public static partial class HtmlHelpers { - - private const string ExcludedQueryStringParams = "tabid,mid,ctl,language,popup,action,controller"; - private const string ExcludedRouteValues = "mid,ctl,popup"; - - public static IHtmlString ViewComponent(this HtmlHelper htmlHelper, string controllerName, object model) - { - return htmlHelper.Action("Invoke", controllerName, model); - } - - public static IHtmlString Control(this HtmlHelper htmlHelper, string controlSrc, object model) - { - try - { - return htmlHelper.Action( - "Invoke", - MvcUtils.GetControlControllerName(controlSrc), - model); - } - catch (Exception ex) - { - throw new Exception($"{ex.Message} - {MvcUtils.GetControlControllerName(controlSrc)} - Invoke", ex); - } - } - public static IHtmlString Control(this HtmlHelper htmlHelper, string controlSrc, ModuleInfo module) { - string controllerName= string.Empty; - string actionName = string.Empty; - try + var moduleControl = MvcUtils.GetModuleControl(module, controlSrc); + // moduleControl.ViewContext = htmlHelper.ViewContext; + if (moduleControl is IResourcable) { - var area = module.DesktopModule.FolderName; - if (controlSrc.EndsWith(".mvc", System.StringComparison.OrdinalIgnoreCase)) + var resourcable = (IResourcable)moduleControl; + if (resourcable.ModuleResources.StyleSheets != null) { - var controlKey = module.ModuleControl.ControlKey; - var segments = controlSrc.Replace(".mvc", string.Empty).Split('/'); - - var localResourceFile = string.Format( - "~/DesktopModules/MVC/{0}/{1}/{2}.resx", - module.DesktopModule.FolderName, - Localization.LocalResourceDirectory, - segments[0]); - - RouteValueDictionary values = new RouteValueDictionary - { - { "mvcpage", true }, - { "ModuleId", module.ModuleID }, - { "TabId", module.TabID }, - { "ModuleControlId", module.ModuleControlId }, - { "PanaName", module.PaneName }, - { "ContainerSrc", module.ContainerSrc }, - { "ContainerPath", module.ContainerPath }, - { "IconFile", module.IconFile }, - { "area", area } - }; - - var queryString = htmlHelper.ViewContext.HttpContext.Request.QueryString; - - if (string.IsNullOrEmpty(controlKey)) + foreach (var styleSheet in resourcable.ModuleResources.StyleSheets) { - controlKey = queryString.GetValueOrDefault("ctl", string.Empty); + MvcClientResourceManager.RegisterStyleSheet(htmlHelper.ViewContext.Controller.ControllerContext, styleSheet.FilePath, styleSheet.Priority, styleSheet.HtmlAttributes); } - - var moduleId = Null.NullInteger; - if (queryString["moduleid"] != null) - { - int.TryParse(queryString["moduleid"], out moduleId); - } - - string routeNamespace = string.Empty; - string routeControllerName; - string routeActionName; - if (segments.Length == 3) - { - routeNamespace = segments[0]; - routeControllerName = segments[1]; - routeActionName = segments[2]; - } - else + } + if (resourcable.ModuleResources.Scripts != null) + { + foreach (var javaScript in resourcable.ModuleResources.Scripts) { - routeControllerName = segments[0]; - routeActionName = segments[1]; + MvcClientResourceManager.RegisterScript(htmlHelper.ViewContext.Controller.ControllerContext, javaScript.FilePath, javaScript.Priority, javaScript.HtmlAttributes); } - - if (moduleId != module.ModuleID && string.IsNullOrEmpty(controlKey)) - { - // Set default routeData for module that is not the "selected" module - actionName = routeActionName; - controllerName = routeControllerName; - - // routeData.Values.Add("controller", controllerName); - // routeData.Values.Add("action", actionName); - - if (!string.IsNullOrEmpty(routeNamespace)) - { - // routeData.DataTokens.Add("namespaces", new string[] { routeNamespace }); - } - } - else + } + if (resourcable.ModuleResources.Libraries != null) + { + foreach (var lib in resourcable.ModuleResources.Libraries) { - var control = ModuleControlController.GetModuleControlByControlKey(controlKey, module.ModuleDefID); - actionName = queryString.GetValueOrDefault("action", routeActionName); - controllerName = queryString.GetValueOrDefault("controller", routeControllerName); - - // values.Add("controller", controllerName); - // values.Add("action", actionName); - - foreach (var param in queryString.AllKeys) - { - if (!ExcludedQueryStringParams.Split(',').ToList().Contains(param.ToLowerInvariant())) - { - if (!values.ContainsKey(param)) - { - values.Add(param, queryString[param]); - } - } - } - - if (!string.IsNullOrEmpty(routeNamespace)) - { - // routeData.DataTokens.Add("namespaces", new string[] { routeNamespace }); - } + MvcJavaScript.RequestRegistration(lib); } - - return htmlHelper.Action( - actionName, - controllerName, - values); } - else + if (resourcable.ModuleResources.AjaxScript) { - controllerName= MvcUtils.GetControlControllerName(controlSrc); - actionName = "Invoke"; - return htmlHelper.Action( - actionName, - controllerName, - new - { - ModuleId = module.ModuleID, - TabId = module.TabID, - ModuleControlId = module.ModuleControlId, - PanaName = module.PaneName, - ContainerSrc = module.ContainerSrc, - ContainerPath = module.ContainerPath, - IconFile = module.IconFile, - area= area, - }); + ServicesFramework.Instance.RequestAjaxScriptSupport(); + } + if (resourcable.ModuleResources.AjaxAntiForgery) + { + ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); } } - catch (Exception ex) - { - throw new Exception($"{ex.Message} - {controlSrc} - {controllerName} - {actionName}", ex); - } + return moduleControl.Html(htmlHelper); } public static IHtmlString Control(this HtmlHelper htmlHelper, ModuleInfo module) @@ -204,10 +83,8 @@ public static IHtmlString RegisterAjaxScriptIfRequired(this HtmlHelper htmlHelpe public static IHtmlString AntiForgeryIfRequired(this HtmlHelper htmlHelper) { - // ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); // add also jquery if (ServicesFrameworkInternal.Instance.IsAjaxAntiForgerySupportRequired) { - // var antiForgery = AntiForgery.GetHtml().ToHtmlString(); return AntiForgery.GetHtml(); } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs similarity index 56% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleControlBase.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs index 830315f9d63..2e4ba96c233 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleControlBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs @@ -7,8 +7,10 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl using System; using System.Collections; using System.IO; + using System.Web; + using System.Web.Mvc; + using System.Web.Mvc.Html; using System.Web.UI; - using DotNetNuke.Common; using DotNetNuke.Entities.Modules; using DotNetNuke.Entities.Modules.Actions; @@ -17,8 +19,10 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl using DotNetNuke.Instrumentation; using DotNetNuke.Services.Localization; using DotNetNuke.UI.Modules; + using DotNetNuke.Web.Client; + using DotNetNuke.Web.Client.ClientResourceManagement; - public class ModuleControlBase : IModuleControl, IDisposable + public abstract class DefaultMvcModuleControlBase : IMvcModuleControl, IDisposable { /* protected static readonly Regex FileInfoRegex = new Regex( @@ -27,73 +31,69 @@ public class ModuleControlBase : IModuleControl, IDisposable TimeSpan.FromSeconds(1)); */ + + private readonly ILog tracelLogger = LoggerSource.Instance.GetLogger("DNN.Trace"); private readonly Lazy serviceScopeContainer = new Lazy(ServiceScopeContainer.GetRequestOrCreateScope); private string localResourceFile; private ModuleInstanceContext moduleContext; - /* - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Control ContainerControl + + //public ViewContext ViewContext { get; set; } + + public ModuleInfo ModuleConfiguration { get { - return Globals.FindControlRecursive(this, "ctr" + this.ModuleId); + return ModuleContext.Configuration; } } - */ - public bool IsHostMenu + public int TabId { get { - return Globals.IsHostTab(this.PortalSettings.ActiveTab.TabID); + return this.ModuleContext.TabId; } } - public PortalSettings PortalSettings + public int ModuleId { get { - return PortalController.Instance.GetCurrentPortalSettings(); + return this.ModuleContext.ModuleId; } } - /// - /// Gets a value indicating whether the EditMode property is used to determine whether the user is in the - /// Administrator role - /// Cache. - /// - public bool EditMode + public int TabModuleId { get { - return this.ModuleContext.EditMode; + return this.ModuleContext.TabModuleId; } } - public bool IsEditable + public bool IsHostMenu { get { - return this.ModuleContext.IsEditable; + return Globals.IsHostTab(this.PortalSettings.ActiveTab.TabID); } } - public int PortalId + public PortalSettings PortalSettings { get { - return this.ModuleContext.PortalId; + return PortalController.Instance.GetCurrentPortalSettings(); } } - public int TabId + public int PortalId { get { - return this.ModuleContext.TabId; + return this.ModuleContext.PortalId; } } @@ -131,27 +131,25 @@ public Hashtable Settings /// Gets the underlying base control for this ModuleControl. /// A String. - public Control Control + public Control Control { get; set; } + + /// Gets the Name for this control. + /// A String. + public virtual string ControlName { get { - return null; + return Path.GetFileNameWithoutExtension(this.ModuleConfiguration.ModuleControl.ControlSrc); } } - public string ID { get; set; } - /// Gets or Sets the Path for this control (used primarily for UserControls). /// A String. - public string ControlPath { get; set; } - - /// Gets the Name for this control. - /// A String. - public string ControlName + public virtual string ControlPath { get { - return this.GetType().Name.Replace("_", "."); + return Path.GetDirectoryName(this.ModuleConfiguration.ModuleControl.ControlSrc); } } @@ -168,52 +166,12 @@ public ModuleInstanceContext ModuleContext return this.moduleContext; } - } - - /* - // CONVERSION: Remove obsoleted methods (FYI some core modules use these, such as Links) - - /// - /// Gets the CacheDirectory property is used to return the location of the "Cache" - /// Directory for the Module. - /// - [Obsolete("Deprecated in DotNetNuke 7.0.0. Please use ModuleController.CacheDirectory(). Scheduled removal in v11.0.0.")] - public string CacheDirectory - { - get - { - return PortalController.Instance.GetCurrentPortalSettings().HomeDirectoryMapPath + "Cache"; - } - } - - /// - /// Gets the CacheFileName property is used to store the FileName for this Module's - /// Cache. - /// - [Obsolete("Deprecated in DotNetNuke 7.0.0. Please use ModuleController.CacheFileName(TabModuleID). Scheduled removal in v11.0.0.")] - public string CacheFileName - { - get + internal set { - string strCacheKey = "TabModule:"; - strCacheKey += this.TabModuleId + ":"; - strCacheKey += Thread.CurrentThread.CurrentUICulture.ToString(); - return PortalController.Instance.GetCurrentPortalSettings().HomeDirectoryMapPath + "Cache" + "\\" + Globals.CleanFileName(strCacheKey) + ".resources"; + this.moduleContext = value; } } - [Obsolete("Deprecated in DotNetNuke 7.0.0. Please use ModuleController.CacheKey(TabModuleID). Scheduled removal in v11.0.0.")] - public string CacheKey - { - get - { - string strCacheKey = "TabModule:"; - strCacheKey += this.TabModuleId + ":"; - strCacheKey += Thread.CurrentThread.CurrentUICulture.ToString(); - return strCacheKey; - } - } - */ public ModuleActionCollection Actions { @@ -241,44 +199,6 @@ public string HelpURL } } - public ModuleInfo ModuleConfiguration - { - get - { - return this.ModuleContext.Configuration; - } - - set - { - this.ModuleContext.Configuration = value; - } - } - - public int TabModuleId - { - get - { - return this.ModuleContext.TabModuleId; - } - - set - { - this.ModuleContext.TabModuleId = value; - } - } - - public int ModuleId - { - get - { - return this.ModuleContext.ModuleId; - } - - set - { - this.ModuleContext.ModuleId = value; - } - } /// Gets or sets the local resource file for this control. /// A String. @@ -289,7 +209,7 @@ public string LocalResourceFile string fileRoot; if (string.IsNullOrEmpty(this.localResourceFile)) { - fileRoot = Path.Combine(this.ControlPath, Localization.LocalResourceDirectory + "/" + this.ID); + fileRoot = Path.Combine(this.ControlPath, Localization.LocalResourceDirectory + "/" + this.ControlName); } else { @@ -314,14 +234,28 @@ public string LocalResourceFile /// protected IServiceProvider DependencyProvider => this.serviceScopeContainer.Value.ServiceScope.ServiceProvider; - public string EditUrl() + public string EditUrl(bool mvc = true) { - return this.ModuleContext.EditUrl(); + if (mvc) + { + return this.ModuleContext.EditUrl("mvcpage", "yes"); + } + else + { + return this.ModuleContext.EditUrl(); + } } - public string EditUrl(string controlKey) + public string EditUrl(string controlKey, bool mvc = true) { - return this.ModuleContext.EditUrl(controlKey); + if (mvc) + { + return this.ModuleContext.EditUrl(controlKey, "mvcpage", "yes"); + } + else + { + return this.ModuleContext.EditUrl(controlKey); + } } public string EditUrl(string keyName, string keyValue) @@ -359,59 +293,6 @@ public void Dispose() } } - /* - [DnnDeprecated(7, 0, 0, "Please use ModuleController.CacheFileName(TabModuleID)", RemovalVersion = 11)] - public partial string GetCacheFileName(int tabModuleId) - { - string strCacheKey = "TabModule:"; - strCacheKey += tabModuleId + ":"; - strCacheKey += Thread.CurrentThread.CurrentUICulture.ToString(); - return PortalController.Instance.GetCurrentPortalSettings().HomeDirectoryMapPath + "Cache" + "\\" + Globals.CleanFileName(strCacheKey) + ".resources"; - } - - [DnnDeprecated(7, 0, 0, "Please use ModuleController.CacheKey(TabModuleID)", RemovalVersion = 11)] - public partial string GetCacheKey(int tabModuleId) - { - string strCacheKey = "TabModule:"; - strCacheKey += tabModuleId + ":"; - strCacheKey += Thread.CurrentThread.CurrentUICulture.ToString(); - return strCacheKey; - } - - [DnnDeprecated(7, 0, 0, "Please use ModuleController.SynchronizeModule(ModuleId)", RemovalVersion = 11)] - public partial void SynchronizeModule() - { - ModuleController.SynchronizeModule(this.ModuleId); - } - */ - protected void OnInit() - { - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"PortalModuleBase.OnInit Start (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleId:{this.ModuleId}): {this.GetType()}"); - } - - // base.OnInit(e); - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"PortalModuleBase.OnInit End (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleId:{this.ModuleId}): {this.GetType()}"); - } - } - - protected void OnLoad() - { - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"PortalModuleBase.OnLoad Start (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleId:{this.ModuleId}): {this.GetType()}"); - } - - // base.OnLoad(e); - if (this.tracelLogger.IsDebugEnabled) - { - this.tracelLogger.Debug($"PortalModuleBase.OnLoad End (TabId:{this.PortalSettings.ActiveTab.TabID},ModuleId:{this.ModuleId}): {this.GetType()}"); - } - } - /// /// Helper method that can be used to add an ActionEventHandler to the Skin for this /// Module Control. @@ -436,5 +317,7 @@ protected string LocalizeSafeJsString(string key) { return Localization.GetSafeJSString(key, this.LocalResourceFile); } + + public abstract IHtmlString Html(HtmlHelper htmlHelper); } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IMvcModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IMvcModuleControl.cs new file mode 100644 index 00000000000..20b481f7ca6 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IMvcModuleControl.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using System.Web.UI; +using DotNetNuke.Entities.Modules; +using DotNetNuke.UI.Modules; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + public interface IMvcModuleControl : IModuleControl + { + //public ViewContext ViewContext { get; set; } + + /// Gets the control Html + IHtmlString Html(HtmlHelper htmlHelper); + + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs new file mode 100644 index 00000000000..a29ec846454 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs @@ -0,0 +1,11 @@ +// 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.Web.MvcPipeline.ModuleControl +{ + public interface IResourcable + { + ModuleResources ModuleResources {get;} + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs new file mode 100644 index 00000000000..a2d60825410 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + public class ModuleResources + { + public List StyleSheets { get; set; } = new List(); + public List Scripts { get; set; } = new List(); + public List Libraries { get; set; } = new List(); + public bool AjaxScript { get; set; } + public bool AjaxAntiForgery { get; set; } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs new file mode 100644 index 00000000000..1ba8b41abfc --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using DotNetNuke.Web.Client; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + public class ModuleScript + { + public string FilePath { get; set; } + public FileOrder.Js Priority { get; set; } = FileOrder.Js.DefaultPriority; + public IDictionary HtmlAttributes { get; set; } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs new file mode 100644 index 00000000000..bc03acd7763 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using DotNetNuke.Web.Client; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + public class ModuleStyleSheet + { + public string FilePath { get; set; } + public FileOrder.Css Priority { get; set; } = FileOrder.Css.DefaultPriority; + public IDictionary HtmlAttributes { get; set; } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs new file mode 100644 index 00000000000..401b3ee9817 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs @@ -0,0 +1,211 @@ +// 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.Web.MvcPipeline.ModuleControl +{ + using System; + using System.Collections; + using System.IO; + using System.Linq; + using System.Web; + using System.Web.Mvc; + using System.Web.Mvc.Html; + using System.Web.Routing; + using System.Web.UI; + + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Users; + using DotNetNuke.Instrumentation; + using DotNetNuke.Services.Localization; + using DotNetNuke.UI.Containers; + using DotNetNuke.UI.Modules; + using DotNetNuke.Collections; + + public class MvcModuleControl : DefaultMvcModuleControlBase + { + + private const string ExcludedQueryStringParams = "tabid,mid,ctl,language,popup,action,controller"; + private const string ExcludedRouteValues = "mid,ctl,popup"; + + /// Gets or sets the action name for the MVC route. + /// A String. + public string RouteActionName + { + get + { + var segments = GetSegments(); + if (segments.Length < 2) + { + return ""; + } + if (segments.Length == 3) + { + return segments[2]; + } + else + { + return segments[1]; + } + } + } + + /// Gets or sets the controller name for the MVC route. + /// A String. + public string RouteControllerName + { + get + { + var segments = GetSegments(); + if (segments.Length < 2) + { + return string.Empty; + } + return segments[1]; + } + } + + public string RouteNamespace + { + get + { + var segments = GetSegments(); + if (segments.Length < 1) + { + return string.Empty; + } + return segments[0]; + } + } + + public string[] GetSegments() + { + return this.ModuleConfiguration.ModuleControl.ControlSrc.Replace(".mvc", string.Empty).Split('/'); + } + + /// Gets the Name for this control. + /// A String. + public override string ControlName + { + get + { + return RouteActionName; + } + } + + /// Gets or Sets the Path for this control (used primarily for UserControls). + /// A String. + public override string ControlPath + { + get + { + return string.Format("~/DesktopModules/MVC/{0}", ModuleConfiguration.DesktopModule.FolderName); + } + } + + public override IHtmlString Html(HtmlHelper htmlHelper) + { + var module = this.ModuleConfiguration; + var controlSrc = module.ModuleControl.ControlSrc; + var area = module.DesktopModule.FolderName; + if (!controlSrc.EndsWith(".mvc", System.StringComparison.OrdinalIgnoreCase)) + { + throw new Exception("The controlSrc is not a MVC control: " + controlSrc); + } + + var segments = GetSegments(); + if (segments.Length < 2) + { + throw new Exception("The controlSrc is not a MVC control: " + controlSrc); + } + + string controllerName = string.Empty; + string actionName = string.Empty; + var controlKey = module.ModuleControl.ControlKey; + + /* + var localResourceFile = string.Format( + "~/DesktopModules/MVC/{0}/{1}/{2}.resx", + module.DesktopModule.FolderName, + Localization.LocalResourceDirectory, + RouteActionName); + */ + + RouteValueDictionary values = new RouteValueDictionary + { + { "mvcpage", true }, + { "ModuleId", module.ModuleID }, + { "TabId", module.TabID }, + { "ModuleControlId", module.ModuleControlId }, + { "PanaName", module.PaneName }, + { "ContainerSrc", module.ContainerSrc }, + { "ContainerPath", module.ContainerPath }, + { "IconFile", module.IconFile }, + { "area", area } + }; + + var queryString = htmlHelper.ViewContext.HttpContext.Request.QueryString; + + if (string.IsNullOrEmpty(controlKey)) + { + controlKey = queryString.GetValueOrDefault("ctl", string.Empty); + } + + var moduleId = Null.NullInteger; + if (queryString["moduleid"] != null) + { + int.TryParse(queryString["moduleid"], out moduleId); + } + + if (moduleId != module.ModuleID && string.IsNullOrEmpty(controlKey)) + { + // Set default routeData for module that is not the "selected" module + actionName = RouteActionName; + controllerName = RouteControllerName; + + // routeData.Values.Add("controller", controllerName); + // routeData.Values.Add("action", actionName); + + if (!string.IsNullOrEmpty(RouteNamespace)) + { + // routeData.DataTokens.Add("namespaces", new string[] { routeNamespace }); + } + } + else + { + var control = ModuleControlController.GetModuleControlByControlKey(controlKey, module.ModuleDefID); + actionName = queryString.GetValueOrDefault("action", RouteActionName); + controllerName = queryString.GetValueOrDefault("controller", RouteControllerName); + + // values.Add("controller", controllerName); + // values.Add("action", actionName); + + foreach (var param in queryString.AllKeys) + { + if (!ExcludedQueryStringParams.Split(',').ToList().Contains(param.ToLowerInvariant())) + { + if (!values.ContainsKey(param)) + { + values.Add(param, queryString[param]); + } + } + } + + if (!string.IsNullOrEmpty(RouteNamespace)) + { + // routeData.DataTokens.Add("namespaces", new string[] { routeNamespace }); + } + } + + return htmlHelper.Action( + actionName, + controllerName, + values); + + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs new file mode 100644 index 00000000000..8bd801acf78 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs @@ -0,0 +1,231 @@ +// 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.Web.MvcPipeline.ModuleControl +{ + using System; + using System.Collections.Generic; + using System.Web; + using System.Web.Mvc; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + + /// + /// Extension methods for IMvcModuleControl interface. + /// + public static class MvcModuleControlExtensions + { + /* + /// + /// Registers a JavaScript file for the module control. + /// + /// The module control instance. + /// The path to the JavaScript file. + /// The priority for loading the script. + public static void RegisterScript(this IMvcModuleControl moduleControl, string filePath, FileOrder.Js priority = FileOrder.Js.DefaultPriority) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException("File path cannot be null or empty.", nameof(filePath)); + } + + if (moduleControl.ViewContext != null) + { + MvcClientResourceManager.RegisterScript(moduleControl.ViewContext.Controller.ControllerContext, filePath, priority); + } + else if (moduleControl.Control != null) + { + ClientResourceManager.RegisterScript(moduleControl.Control.Page, filePath, priority); + } + } + + /// + /// Registers a CSS stylesheet for the module control. + /// + /// The module control instance. + /// The path to the CSS file. + /// The priority for loading the stylesheet. + public static void RegisterStyleSheet(this IMvcModuleControl moduleControl, string filePath, FileOrder.Css priority = FileOrder.Css.DefaultPriority) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException("File path cannot be null or empty.", nameof(filePath)); + } + + if (moduleControl.ViewContext != null) + { + MvcClientResourceManager.RegisterStyleSheet(moduleControl.ViewContext.Controller.ControllerContext, filePath, priority); + } + else if (moduleControl.Control != null) + { + ClientResourceManager.RegisterStyleSheet(moduleControl.Control.Page, filePath, priority); + } + } + */ + /// + /// Gets a localized string for the module control. + /// + /// The module control instance. + /// The resource key. + /// The localized string. + public static string LocalizeString(this IMvcModuleControl moduleControl, string key) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + if (string.IsNullOrEmpty(key)) + { + return string.Empty; + } + + return Localization.GetString(key, moduleControl.LocalResourceFile); + } + + /// + /// Gets a localized string formatted for safe JavaScript usage. + /// + /// The module control instance. + /// The resource key. + /// The JavaScript-safe localized string. + public static string LocalizeSafeJsString(this IMvcModuleControl moduleControl, string key) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + if (string.IsNullOrEmpty(key)) + { + return string.Empty; + } + + return Localization.GetSafeJSString(key, moduleControl.LocalResourceFile); + } + + /// + /// Gets an edit URL for the module. + /// + /// The module control instance. + /// The control key for the edit page. + /// The edit URL. + public static string EditUrl(this IMvcModuleControl moduleControl, string controlKey = "") + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + return string.IsNullOrEmpty(controlKey) + ? moduleControl.ModuleContext.EditUrl() + : moduleControl.ModuleContext.EditUrl(controlKey); + } + + /// + /// Gets an edit URL for the module with specific parameters. + /// + /// The module control instance. + /// The parameter key name. + /// The parameter key value. + /// The control key for the edit page. + /// The edit URL with parameters. + public static string EditUrl(this IMvcModuleControl moduleControl, string keyName, string keyValue, string controlKey = "") + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + return string.IsNullOrEmpty(controlKey) + ? moduleControl.ModuleContext.EditUrl(keyName, keyValue) + : moduleControl.ModuleContext.EditUrl(keyName, keyValue, controlKey); + } + + /// + /// Gets a module setting value with type conversion. + /// + /// The type to convert the setting to. + /// The module control instance. + /// The setting name. + /// The default value if setting is not found or conversion fails. + /// The setting value converted to the specified type. + public static T GetModuleSetting(this IMvcModuleControl moduleControl, string settingName, T defaultValue = default) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + if (string.IsNullOrEmpty(settingName)) + { + return defaultValue; + } + + var settings = moduleControl.ModuleContext.Settings; + if (settings == null || !settings.ContainsKey(settingName)) + { + return defaultValue; + } + + try + { + var settingValue = settings[settingName]?.ToString(); + if (string.IsNullOrEmpty(settingValue)) + { + return defaultValue; + } + + return (T)Convert.ChangeType(settingValue, typeof(T)); + } + catch (Exception) + { + return defaultValue; + } + } + + /// + /// Checks if the current user is in edit mode for the module. + /// + /// The module control instance. + /// True if in edit mode; otherwise, false. + public static bool EditMode(this IMvcModuleControl moduleControl) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + return moduleControl.ModuleContext.EditMode; + } + + /// + /// Checks if the module is editable by the current user. + /// + /// The module control instance. + /// True if editable; otherwise, false. + public static bool IsEditable(this IMvcModuleControl moduleControl) + { + if (moduleControl == null) + { + throw new ArgumentNullException(nameof(moduleControl)); + } + + return moduleControl.ModuleContext.IsEditable; + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs new file mode 100644 index 00000000000..f0d67458160 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.UI; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Framework; +using DotNetNuke.Framework.JavaScriptLibraries; +using DotNetNuke.UI.Modules; +using DotNetNuke.Web.Client.ClientResourceManagement; +using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; +using DotNetNuke.Web.MvcPipeline.Utils; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + public class MvcModuleControlRenderer where T : RazorModuleControlBase, new() + { + private readonly T moduleControl; + + public MvcModuleControlRenderer(Control control, ModuleInstanceContext moduleContext) + { + this.moduleControl = new T(); + moduleControl.ModuleContext = moduleContext; + moduleControl.Control = control; + } + + // Fix for CS0149: Replace the invalid constructor chaining syntax with a proper constructor call + public MvcModuleControlRenderer(PortalModuleBase control) + : this(control, control.ModuleContext) + { + } + + public string RenderToString() + { + var renderer = new ViewRenderer(); + return renderer.RenderViewToString(moduleControl.ViewName, moduleControl.ViewModel()); + } + + public T ModuleControl => this.moduleControl; + + public void RegisterResources(IResourcable resourcable) + { + if (resourcable.ModuleResources.StyleSheets != null) + { + foreach (var styleSheet in resourcable.ModuleResources.StyleSheets) + { + ClientResourceManager.RegisterStyleSheet(ModuleControl.Control.Page, styleSheet.FilePath, styleSheet.Priority, styleSheet.HtmlAttributes); + } + } + if (resourcable.ModuleResources.Scripts != null) + { + foreach (var javaScript in resourcable.ModuleResources.Scripts) + { + ClientResourceManager.RegisterScript(ModuleControl.Control.Page, javaScript.FilePath, javaScript.Priority, javaScript.HtmlAttributes); + } + } + if (resourcable.ModuleResources.Libraries != null) + { + foreach (var lib in resourcable.ModuleResources.Libraries) + { + JavaScript.RequestRegistration(lib); + } + } + if (resourcable.ModuleResources.AjaxScript) + { + ServicesFramework.Instance.RequestAjaxScriptSupport(); + } + if (resourcable.ModuleResources.AjaxAntiForgery) + { + ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); + } + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs new file mode 100644 index 00000000000..a976ce11571 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using System.Web.Mvc.Html; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + public abstract class RazorModuleControlBase : DefaultMvcModuleControlBase + { + + public abstract object ViewModel(); + + public override IHtmlString Html(HtmlHelper htmlHelper) + { + var model = this.ViewModel(); + return htmlHelper.Partial(this.ViewName, model); + } + + public virtual string ViewName + { + get + { + return "~/" + this.ControlPath.Replace('\\', '/') + "/Views/" + this.ControlName + ".cshtml"; + } + } + + public abstract object ViewModel(); + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs new file mode 100644 index 00000000000..421da678750 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs @@ -0,0 +1,147 @@ +// 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.Web.MvcPipeline.ModuleControl +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Web; + using System.Web.Mvc; + using System.Web.Mvc.Html; + using System.Web.Routing; + using System.Web.UI; + using DotNetNuke.Abstractions.Modules; + using DotNetNuke.Collections; + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Users; + using DotNetNuke.Framework; + using DotNetNuke.Instrumentation; + using DotNetNuke.Services.Cache; + using DotNetNuke.Services.Localization; + using DotNetNuke.UI.Containers; + using DotNetNuke.UI.Modules; + using DotNetNuke.UI.Modules.Html5; + using DotNetNuke.Web.Client; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.Tokens; + using Microsoft.Extensions.DependencyInjection; + + public class SpaModuleControl : DefaultMvcModuleControlBase, IResourcable + { + private readonly IBusinessControllerProvider businessControllerProvider; + + public SpaModuleControl() + { + this.businessControllerProvider = Globals.DependencyProvider.GetRequiredService(); + } + + public SpaModuleControl(IBusinessControllerProvider businessControllerProvider) + { + this.businessControllerProvider = businessControllerProvider; + } + + public string html5File + { + get + { + var controlSrc = ModuleConfiguration.ModuleControl.ControlSrc; + + return controlSrc; + } + } + + public ModuleResources ModuleResources + { + get + { + var resource = new ModuleResources() + { + AjaxScript = true + }; + + if (!string.IsNullOrEmpty(this.html5File)) + { + // Check if css file exists + var cssFile = Path.ChangeExtension(this.html5File, ".css"); + if (this.FileExists(cssFile)) + { + resource.StyleSheets.Add(new ModuleStyleSheet() + { + FilePath = "/" + cssFile, + Priority = FileOrder.Css.DefaultPriority, + }); + } + } + + if (!string.IsNullOrEmpty(this.html5File)) + { + // Check if js file exists + var jsFile = Path.ChangeExtension(this.html5File, ".js"); + if (this.FileExists(jsFile)) + { + resource.Scripts.Add(new ModuleScript() + { + FilePath = "/" + jsFile, + Priority = FileOrder.Js.DefaultPriority, + }); + } + } + return resource; + } + } + + public override IHtmlString Html(HtmlHelper htmlHelper) + { + var fileContent = string.Empty; + if (!string.IsNullOrEmpty(this.html5File)) + { + fileContent = this.GetFileContent(this.html5File); + var ModuleActions = new ModuleActionCollection(); + var tokenReplace = new MvcHtml5ModuleTokenReplace(htmlHelper.ViewContext, this.businessControllerProvider, this.html5File, this.ModuleContext, ModuleActions); + fileContent = tokenReplace.ReplaceEnvironmentTokens(fileContent); + } + + // Register for Services Framework + //ServicesFramework.Instance.RequestAjaxScriptSupport(); + return new HtmlString(HttpUtility.HtmlDecode(fileContent)); + } + + private static string GetFileContentInternal(string filepath) + { + using (var reader = new StreamReader(filepath)) + { + return reader.ReadToEnd(); + } + } + + private string GetFileContent(string filepath) + { + var cacheKey = string.Format(DataCache.SpaModulesContentHtmlFileCacheKey, filepath); + var absoluteFilePath = HttpContext.Current.Server.MapPath("/" + filepath); + var cacheItemArgs = new CacheItemArgs(cacheKey, DataCache.SpaModulesHtmlFileTimeOut, DataCache.SpaModulesHtmlFileCachePriority) + { + CacheDependency = new DNNCacheDependency(absoluteFilePath), + }; + return CBO.GetCachedObject(cacheItemArgs, c => GetFileContentInternal(absoluteFilePath)); + } + + private bool FileExists(string filepath) + { + var cacheKey = string.Format(DataCache.SpaModulesFileExistsCacheKey, filepath); + return CBO.GetCachedObject( + new CacheItemArgs( + cacheKey, + DataCache.SpaModulesHtmlFileTimeOut, + DataCache.SpaModulesHtmlFileCachePriority), + c => File.Exists(HttpContext.Current.Server.MapPath("/" + filepath))); + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/ModuleHelpers.TextEditor.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/ModuleHelpers.TextEditor.cs index f78b1b5105f..e67e0ba0dcd 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/ModuleHelpers.TextEditor.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/ModuleHelpers.TextEditor.cs @@ -126,7 +126,10 @@ private static void LoadAllSettings(ViewContext page, string id) // Set Current Mode to Module Instance currentEditorSettings.SettingMode = SettingsMode.ModuleInstance; */ - if (page.IsChildAction) + + if (!page.HttpContext.Request.IsAjaxRequest()) + + //if (page.IsChildAction) { MvcClientResourceManager.RegisterStyleSheet(page, Globals.ResolveUrl("~/Providers/HtmlEditorProviders/DNNConnect.CKE/css/CKEditorToolBars.css")); MvcClientResourceManager.RegisterStyleSheet(page, Globals.ResolveUrl("~/Providers/HtmlEditorProviders/DNNConnect.CKE/css/CKEditorOverride.css")); diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/PermissionTriStateHelper.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/PermissionTriStateHelper.cs similarity index 98% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/PermissionTriStateHelper.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/PermissionTriStateHelper.cs index 57d058d6e91..c43322bc872 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/PermissionTriStateHelper.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Modules/PermissionTriStateHelper.cs @@ -2,7 +2,7 @@ // 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.MvcPipeline +namespace DotNetNuke.Web.MvcPipeline.Modules { using System.Web.Mvc; @@ -104,7 +104,7 @@ public static string GetInitScript() LookupScriptValues(out grantImagePath, out denyImagePath, out nullImagePath, out lockImagePath, out grantAltText, out denyAltText, out nullAltText); - string script = + var script = string.Format( @"jQuery(document).ready( function() {{ diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Startup.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Startup.cs index 3926e6547d2..81dbecf2bc4 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Startup.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Startup.cs @@ -9,7 +9,7 @@ namespace DotNetNuke.Web.MvcPipeline using DotNetNuke.ContentSecurityPolicy; using DotNetNuke.DependencyInjection; using DotNetNuke.Web.Mvc.Extensions; - using DotNetNuke.Web.MvcPipeline.Framework; + using DotNetNuke.Web.MvcPipeline.ModelFactories; using DotNetNuke.Web.MvcPipeline.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcCssPropertyAccess.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcCssPropertyAccess.cs new file mode 100644 index 00000000000..540d2701b74 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcCssPropertyAccess.cs @@ -0,0 +1,53 @@ +// 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 + +// ReSharper disable once CheckNamespace +namespace DotNetNuke.Web.MvcPipeline.Tokens +{ + using System; + using System.Web.Mvc; + + using DotNetNuke.Entities.Users; + using DotNetNuke.Services.Tokens; + using DotNetNuke.Web.Client; + using DotNetNuke.Web.Client.ClientResourceManagement; + + /// Property Access implementation for CSS registration in MVC context. + public class MvcCssPropertyAccess : JsonPropertyAccess + { + private readonly ControllerContext controllerContext; + + /// Initializes a new instance of the class. + /// The controller context. + public MvcCssPropertyAccess(ControllerContext controllerContext) + { + this.controllerContext = controllerContext; + } + + /// + protected override string ProcessToken(StylesheetDto model, UserInfo accessingUser, Scope accessLevel) + { + if (string.IsNullOrEmpty(model.Path)) + { + throw new ArgumentException("The Css token must specify a path or property."); + } + + if (model.Priority == 0) + { + model.Priority = (int)FileOrder.Css.DefaultPriority; + } + + if (string.IsNullOrEmpty(model.Provider)) + { + MvcClientResourceManager.RegisterStyleSheet(this.controllerContext, model.Path, model.Priority); + } + else + { + MvcClientResourceManager.RegisterStyleSheet(this.controllerContext, model.Path, model.Priority, model.Provider); + } + + return string.Empty; + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtml5ModuleTokenReplace.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtml5ModuleTokenReplace.cs new file mode 100644 index 00000000000..356f9475ba0 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtml5ModuleTokenReplace.cs @@ -0,0 +1,74 @@ +// 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.Web.MvcPipeline.Tokens +{ + using System.Web.Mvc; + + using DotNetNuke.Abstractions.Modules; + using DotNetNuke.Common; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Services.Personalization; + using DotNetNuke.Services.Tokens; + using DotNetNuke.UI.Modules; + using DotNetNuke.UI.Modules.Html5; + + using Microsoft.Extensions.DependencyInjection; + + /// A for MVC HTML5 modules. + public class MvcHtml5ModuleTokenReplace : MvcHtmlTokenReplace + { + /// Initializes a new instance of the class. + /// The controller context in which the module is rendering. + /// The path to the module's HTML file. + /// The module context. + /// The module actions collection. + public MvcHtml5ModuleTokenReplace( + ControllerContext controllerContext, + string html5File, + ModuleInstanceContext moduleContext, + ModuleActionCollection moduleActions) + : this(controllerContext, null, html5File, moduleContext, moduleActions) + { + } + + /// Initializes a new instance of the class. + /// The controller context in which the module is rendering. + /// The business controller provider. + /// The path to the module's HTML file. + /// The module context. + /// The module actions collection. + public MvcHtml5ModuleTokenReplace( + ControllerContext controllerContext, + IBusinessControllerProvider businessControllerProvider, + string html5File, + ModuleInstanceContext moduleContext, + ModuleActionCollection moduleActions) + : base(controllerContext) + { + this.AccessingUser = moduleContext.PortalSettings.UserInfo; + this.DebugMessages = Personalization.GetUserMode() != Entities.Portals.PortalSettings.Mode.View; + this.ModuleId = moduleContext.ModuleId; + this.PortalSettings = moduleContext.PortalSettings; + + this.AddPropertySource("moduleaction", new ModuleActionsPropertyAccess(moduleContext, moduleActions)); + this.AddPropertySource("resx", new ModuleLocalizationPropertyAccess(moduleContext, html5File)); + this.AddPropertySource("modulecontext", new ModuleContextPropertyAccess(moduleContext)); + this.AddPropertySource("request", new MvcRequestPropertyAccess(controllerContext)); + + // DNN-7750 + businessControllerProvider ??= Globals.DependencyProvider.GetRequiredService(); + var customTokenProvider = businessControllerProvider.GetInstance(moduleContext); + if (customTokenProvider != null) + { + var tokens = customTokenProvider.GetTokens(controllerContext?.HttpContext?.Handler as System.Web.UI.Page, moduleContext); + foreach (var token in tokens) + { + this.AddPropertySource(token.Key, token.Value); + } + } + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtmlTokenReplace.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtmlTokenReplace.cs new file mode 100644 index 00000000000..719f5dd7b57 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcHtmlTokenReplace.cs @@ -0,0 +1,26 @@ +// 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.Web.MvcPipeline.Tokens +{ + using System.Web.Mvc; + + using DotNetNuke.Services.Tokens; + using DotNetNuke.UI.Modules.Html5; + + /// A for MVC HTML modules. + public class MvcHtmlTokenReplace : TokenReplace + { + /// Initializes a new instance of the class. + /// The controller context in which the module is rendering. + public MvcHtmlTokenReplace(ControllerContext controllerContext) + : base(Scope.DefaultSettings) + { + this.AddPropertySource("css", new MvcCssPropertyAccess(controllerContext)); + this.AddPropertySource("js", new MvcJavaScriptPropertyAccess(controllerContext)); + this.AddPropertySource("javascript", new MvcJavaScriptPropertyAccess(controllerContext)); + this.AddPropertySource("antiforgerytoken", new AntiForgeryTokenPropertyAccess()); + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcJavaScriptPropertyAccess.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcJavaScriptPropertyAccess.cs new file mode 100644 index 00000000000..00b5dfc75a2 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcJavaScriptPropertyAccess.cs @@ -0,0 +1,92 @@ +// 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 + +// ReSharper disable once CheckNamespace +namespace DotNetNuke.Web.MvcPipeline.Tokens +{ + using System; + using System.Web.Mvc; + + using DotNetNuke.Entities.Users; + using DotNetNuke.Framework.JavaScriptLibraries; + using DotNetNuke.Services.Tokens; + using DotNetNuke.Web.Client; + using DotNetNuke.Web.Client.ClientResourceManagement; + + /// Property Access implementation for JavaScript registration in MVC context. + public class MvcJavaScriptPropertyAccess : JsonPropertyAccess + { + private readonly ControllerContext controllerContext; + + /// Initializes a new instance of the class. + /// The controller context. + public MvcJavaScriptPropertyAccess(ControllerContext controllerContext) + { + this.controllerContext = controllerContext; + } + + /// + protected override string ProcessToken(JavaScriptDto model, UserInfo accessingUser, Scope accessLevel) + { + if (string.IsNullOrEmpty(model.JsName) && string.IsNullOrEmpty(model.Path)) + { + throw new ArgumentException("If the jsname property is not specified then the JavaScript token must specify a path."); + } + + if (model.Priority == 0) + { + model.Priority = (int)FileOrder.Js.DefaultPriority; + } + + if (string.IsNullOrEmpty(model.Path)) + { + RegisterInstalledLibrary(model); + } + else + { + MvcClientResourceManager.RegisterScript( + this.controllerContext, + model.Path, + model.Priority, + model.Provider ?? string.Empty, + model.JsName ?? string.Empty, + model.Version ?? string.Empty, + model.HtmlAttributes); + } + + return string.Empty; + } + + private static void RegisterInstalledLibrary(JavaScriptDto model) + { + Version version = null; + var specific = SpecificVersion.Latest; + if (!string.IsNullOrEmpty(model.Version)) + { + version = new Version(model.Version); + + if (!string.IsNullOrEmpty(model.Specific)) + { + switch (model.Specific) + { + case "Exact": + specific = SpecificVersion.Exact; + break; + case "LatestMajor": + specific = SpecificVersion.LatestMajor; + break; + case "LatestMinor": + specific = SpecificVersion.LatestMinor; + break; + default: + specific = SpecificVersion.Latest; + break; + } + } + } + + JavaScript.RequestRegistration(model.JsName, version, specific); + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcRequestPropertyAccess.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcRequestPropertyAccess.cs new file mode 100644 index 00000000000..e1caa8506a6 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Tokens/MvcRequestPropertyAccess.cs @@ -0,0 +1,53 @@ +// 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.Web.MvcPipeline.Tokens +{ + using System.Globalization; + using System.Web.Mvc; + + using DotNetNuke.Entities.Users; + using DotNetNuke.Services.Tokens; + + /// Replaces tokens related to the current HTTP request in MVC context. + public class MvcRequestPropertyAccess : IPropertyAccess + { + private readonly ControllerContext controllerContext; + + /// Initializes a new instance of the class. + /// The controller context. + public MvcRequestPropertyAccess(ControllerContext controllerContext) + { + this.controllerContext = controllerContext; + } + + /// + public virtual CacheLevel Cacheability + { + get { return CacheLevel.notCacheable; } + } + + /// + public string GetProperty(string propertyName, string format, CultureInfo formatProvider, UserInfo accessingUser, Scope accessLevel, ref bool propertyNotFound) + { + var request = this.controllerContext.HttpContext.Request; + + switch (propertyName.ToLowerInvariant()) + { + case "querystring": + return request.QueryString.ToString(); + case "applicationpath": + return request.ApplicationPath; + case "relativeapppath": + // RelativeAppPath is like ApplicationPath, but will always end with a forward slash (/) + return request.ApplicationPath.EndsWith("/") + ? request.ApplicationPath + : $"{request.ApplicationPath}/"; + } + + propertyNotFound = true; + return string.Empty; + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs index 0011d6ed503..fe7035d0808 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs @@ -1,8 +1,15 @@ namespace DotNetNuke.Web.MvcPipeline.UI.Utilities { + using System; + using System.Collections.Generic; using System.IO; - + using System.Runtime.InteropServices; + using System.Web.UI; + using DotNetNuke.Common; using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Framework; + using DotNetNuke.Web.MvcPipeline.ModuleControl; public class MvcUtils { @@ -33,5 +40,70 @@ public static string GetControlControllerName(string controlSrc) return Path.GetFileNameWithoutExtension(controlSrc) + "View"; } } + + static private IDictionary _moduleClasses = new Dictionary() { + { "ModuleActions", "DotNetNuke.Web.MvcWebsite.Controls.ModuleActionsControl, DotNetNuke.Web.MvcWebsite" }, + { "Admin/Portal/Terms.ascx", "DotNetNuke.Web.MvcWebsite.Controls.TermsControl, DotNetNuke.Web.MvcWebsite" }, + { "Admin/Portal/Privacy.ascx", "DotNetNuke.Web.MvcWebsite.Controls.PrivacyControl, DotNetNuke.Web.MvcWebsite" } + }; + + public static IMvcModuleControl GetModuleControl(ModuleInfo module) + { + return GetModuleControl(module, module.ModuleControl.ControlSrc); + } + + public static IMvcModuleControl GetModuleControl(ModuleInfo module, string controlSrc) + { + IMvcModuleControl control; + if (_moduleClasses.ContainsKey(controlSrc)) + { + var controlClass = _moduleClasses[controlSrc]; + try + { + var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); + control = controller as IMvcModuleControl; + } + catch (Exception ex) + { + throw new Exception("Could not create instance of " + controlClass, ex); + } + } + else + { + if (module.DesktopModule == null) + { + throw new Exception("No DesktopModule is not defined for the module " + module.ModuleTitle); + } + + if (controlSrc.EndsWith(".mvc", System.StringComparison.OrdinalIgnoreCase)) + { + control = new MvcModuleControl(); + } + else if (controlSrc.EndsWith(".html", System.StringComparison.OrdinalIgnoreCase)) + { + control = new SpaModuleControl(); + } + else + { + if (string.IsNullOrEmpty(module.DesktopModule.BusinessControllerClass)) + { + throw new Exception("The BusinessControllerClass is not defined for the module " + module.ModuleDefinition.FriendlyName); + } + var businessController = Reflection.CreateType(module.DesktopModule.BusinessControllerClass); + var controlClass = businessController.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(controlSrc) + "Control," + businessController.Assembly; + try + { + var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); + control = controller as IMvcModuleControl; + } + catch (Exception ex) + { + throw new Exception("Could not create instance of " + controlClass, ex); + } + } + } + control.ModuleContext.Configuration = module; + return control; + } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs new file mode 100644 index 00000000000..5d3937ac4c2 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs @@ -0,0 +1,368 @@ +using System; +using System.Web; +using System.Web.Mvc; +using System.IO; +using System.Web.Routing; + + +namespace DotNetNuke.Web.MvcPipeline.Utils +{ + /// + /// Class that renders MVC views to a string using the + /// standard MVC View Engine to render the view. + /// + /// Requires that ASP.NET HttpContext is present to + /// work, but works outside of the context of MVC + /// + public class ViewRenderer + { + /// + /// Required Controller Context + /// + protected ControllerContext Context { get; set; } + + /// + /// Initializes the ViewRenderer with a Context. + /// + /// + /// If you are running within the context of an ASP.NET MVC request pass in + /// the controller's context. + /// Only leave out the context if no context is otherwise available. + /// + public ViewRenderer(ControllerContext controllerContext = null) + { + // Create a known controller from HttpContext if no context is passed + if (controllerContext == null) + { + if (HttpContext.Current != null) + controllerContext = CreateController().ControllerContext; + else + throw new InvalidOperationException( + "ViewRenderer must run in the context of an ASP.NET " + + "Application and requires HttpContext.Current to be present."); + } + Context = controllerContext; + } + + /// + /// Renders a full MVC view to a string. Will render with the full MVC + /// View engine including running _ViewStart and merging into _Layout + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to render the view with + /// String of the rendered view or null on error + public string RenderViewToString(string viewPath, object model = null) + { + return RenderViewToStringInternal(viewPath, model, false); + } + + /// + /// Renders a full MVC view to a writer. Will render with the full MVC + /// View engine including running _ViewStart and merging into _Layout + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to render the view with + /// String of the rendered view or null on error + public void RenderView(string viewPath, object model, TextWriter writer) + { + RenderViewToWriterInternal(viewPath, writer, model, false); + } + + + /// + /// Renders a partial MVC view to string. Use this method to render + /// a partial view that doesn't merge with _Layout and doesn't fire + /// _ViewStart. + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// String of the rendered view or null on error + public string RenderPartialViewToString(string viewPath, object model = null) + { + return RenderViewToStringInternal(viewPath, model, true); + } + + /// + /// Renders a partial MVC view to given Writer. Use this method to render + /// a partial view that doesn't merge with _Layout and doesn't fire + /// _ViewStart. + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Writer to render the view to + public void RenderPartialView(string viewPath, object model, TextWriter writer) + { + RenderViewToWriterInternal(viewPath, writer, model, true); + } + + /// + /// Renders a full MVC view to a writer. Will render with the full MVC + /// View engine including running _ViewStart and merging into _Layout + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Active Controller context + /// String of the rendered view or null on error + public static string RenderView(string viewPath, object model = null, + ControllerContext controllerContext = null) + { + ViewRenderer renderer = new ViewRenderer(controllerContext); + return renderer.RenderViewToString(viewPath, model); + } + + /// + /// Renders a full MVC view to a writer. Will render with the full MVC + /// View engine including running _ViewStart and merging into _Layout + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Writer to render the view to + /// Active Controller context + /// String of the rendered view or null on error + public static void RenderView(string viewPath, TextWriter writer, object model, + ControllerContext controllerContext) + { + ViewRenderer renderer = new ViewRenderer(controllerContext); + renderer.RenderView(viewPath, model, writer); + } + + /// + /// Renders a full MVC view to a writer. Will render with the full MVC + /// View engine including running _ViewStart and merging into _Layout + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Active Controller context + /// optional out parameter that captures an error message instead of throwing + /// String of the rendered view or null on error + public static string RenderView(string viewPath, object model, + ControllerContext controllerContext, + out string errorMessage) + { + errorMessage = null; + try + { + ViewRenderer renderer = new ViewRenderer(controllerContext); + return renderer.RenderViewToString(viewPath, model); + } + catch (Exception ex) + { + errorMessage = ex.GetBaseException().Message; + } + return null; + } + + /// + /// Renders a full MVC view to a writer. Will render with the full MVC + /// View engine including running _ViewStart and merging into _Layout + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Active Controller context + /// Writer to render the view to + /// optional out parameter that captures an error message instead of throwing + /// String of the rendered view or null on error + public static void RenderView(string viewPath, object model, TextWriter writer, + ControllerContext controllerContext, + out string errorMessage) + { + errorMessage = null; + try + { + ViewRenderer renderer = new ViewRenderer(controllerContext); + renderer.RenderView(viewPath, model, writer); + } + catch (Exception ex) + { + errorMessage = ex.GetBaseException().Message; + } + } + + + /// + /// Renders a partial MVC view to string. Use this method to render + /// a partial view that doesn't merge with _Layout and doesn't fire + /// _ViewStart. + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Active controller context + /// String of the rendered view or null on error + public static string RenderPartialView(string viewPath, object model = null, + ControllerContext controllerContext = null) + { + ViewRenderer renderer = new ViewRenderer(controllerContext); + return renderer.RenderPartialViewToString(viewPath, model); + } + + /// + /// Renders a partial MVC view to string. Use this method to render + /// a partial view that doesn't merge with _Layout and doesn't fire + /// _ViewStart. + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// The model to pass to the viewRenderer + /// Active controller context + /// Text writer to render view to + /// optional output parameter to receive an error message on failure + public static void RenderPartialView(string viewPath, TextWriter writer, object model = null, + ControllerContext controllerContext = null) + { + ViewRenderer renderer = new ViewRenderer(controllerContext); + renderer.RenderPartialView(viewPath, model, writer); + } + + + /// + /// Internal method that handles rendering of either partial or + /// or full views. + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// Model to render the view with + /// Determines whether to render a full or partial view + /// Text writer to render view to + protected void RenderViewToWriterInternal(string viewPath, TextWriter writer, object model = null, bool partial = false) + { + // first find the ViewEngine for this view + ViewEngineResult viewEngineResult = null; + if (partial) + viewEngineResult = ViewEngines.Engines.FindPartialView(Context, viewPath); + else + viewEngineResult = ViewEngines.Engines.FindView(Context, viewPath, null); + + if (viewEngineResult == null) + throw new FileNotFoundException(); + + // get the view and attach the model to view data + var view = viewEngineResult.View; + Context.Controller.ViewData.Model = model; + + var ctx = new ViewContext(Context, view, + Context.Controller.ViewData, + Context.Controller.TempData, + writer); + view.Render(ctx, writer); + } + + /// + /// Internal method that handles rendering of either partial or + /// or full views. + /// + /// + /// The path to the view to render. Either in same controller, shared by + /// name or as fully qualified ~/ path including extension + /// + /// Model to render the view with + /// Determines whether to render a full or partial view + /// String of the rendered view + private string RenderViewToStringInternal(string viewPath, object model, + bool partial = false) + { + // first find the ViewEngine for this view + ViewEngineResult viewEngineResult = null; + if (partial) + viewEngineResult = ViewEngines.Engines.FindPartialView(Context, viewPath); + else + viewEngineResult = ViewEngines.Engines.FindView(Context, viewPath, null); + + if (viewEngineResult == null || viewEngineResult.View == null) + throw new FileNotFoundException("ViewCouldNotBeFound"); + + // get the view and attach the model to view data + var view = viewEngineResult.View; + Context.Controller.ViewData.Model = model; + + string result = null; + + using (var sw = new StringWriter()) + { + var ctx = new ViewContext(Context, view, + Context.Controller.ViewData, + Context.Controller.TempData, + sw); + view.Render(ctx, sw); + result = sw.ToString(); + } + + return result; + } + + + /// + /// Creates an instance of an MVC controller from scratch + /// when no existing ControllerContext is present + /// + /// Type of the controller to create + /// Controller for T + /// thrown if HttpContext not available + public static T CreateController(RouteData routeData = null, params object[] parameters) + where T : Controller, new() + { + // create a disconnected controller instance + T controller = (T) Activator.CreateInstance(typeof (T), parameters); + + // get context wrapper from HttpContext if available + HttpContextBase wrapper = null; + if (HttpContext.Current != null) + wrapper = new HttpContextWrapper(System.Web.HttpContext.Current); + else + throw new InvalidOperationException( + "Can't create Controller Context if no active HttpContext instance is available."); + + if (routeData == null) + routeData = new RouteData(); + + // add the controller routing if not existing + if (!routeData.Values.ContainsKey("controller") && !routeData.Values.ContainsKey("Controller")) + routeData.Values.Add("controller", controller.GetType().Name + .ToLower() + .Replace("controller", "")); + + controller.ControllerContext = new ControllerContext(wrapper, routeData, controller); + return controller; + } + + } + + /// + /// Empty MVC Controller instance used to + /// instantiate and provide a new ControllerContext + /// for the ViewRenderer + /// + public class EmptyController : Controller + { + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/PrivacyViewController.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/PrivacyViewController.cs deleted file mode 100644 index 0702fa530e2..00000000000 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/PrivacyViewController.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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.Web.MvcWebsite.Controllers -{ - using System.Web.Mvc; - - using DotNetNuke.Entities.Portals; - using DotNetNuke.Services.Localization; - - public class PrivacyViewController : Controller - { - public ActionResult Invoke() - { - var privacy = Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_PRIVACY"); - return this.View("Index", string.Empty, privacy); - } - } -} diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/TermsViewController.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/TermsViewController.cs deleted file mode 100644 index 9aca37156c3..00000000000 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/TermsViewController.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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.Web.MvcWebsite.Controllers -{ - using System.Web.Mvc; - - using DotNetNuke.Entities.Portals; - using DotNetNuke.Services.Localization; - - public class TermsViewController : Controller - { - public ActionResult Invoke() - { - var terms = Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_TERMS"); - return this.View("Index", string.Empty, terms); - } - } -} diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/ModuleActionsViewController.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs similarity index 78% rename from DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/ModuleActionsViewController.cs rename to DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs index 5c6ce7fdee4..6f0568b3b44 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controllers/ModuleActionsViewController.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs @@ -2,7 +2,7 @@ // 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.Web.MvcWebsite.Controllers +namespace DotNetNuke.Web.MvcWebsite.Controls { using System; using System.Collections.Generic; @@ -21,22 +21,26 @@ namespace DotNetNuke.Web.MvcWebsite.Controllers using DotNetNuke.Security.Permissions; using DotNetNuke.Services.Localization; using DotNetNuke.Services.Personalization; - using DotNetNuke.UI; - using DotNetNuke.UI.Modules; + //using DotNetNuke.UI.Modules; + //using DotNetNuke.UI; + using DotNetNuke.Web.Client; using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; + using DotNetNuke.Web.MvcPipeline.ModuleControl; using DotNetNuke.Web.MvcPipeline.Models; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.UI.Utilities; using DotNetNuke.Web.MvcWebsite.Models; - public class ModuleActionsViewController : Controller + public class ModuleActionsControl : RazorModuleControlBase, IResourcable { private readonly List validIDs = new List(); private ModuleAction actionRoot; private Dictionary actionScripts = new Dictionary(); - public ModuleInstanceContext ModuleContext { get; private set; } + //public ModuleInstanceContext ModuleContext { get; private set; } public bool EditMode { @@ -106,21 +110,9 @@ protected ModuleActionCollection Actions } } - [ChildActionOnly] - public ActionResult Invoke(ControlViewModel input) + public override object ViewModel() { - var moduleInfo = ModuleController.Instance.GetModule(input.ModuleId, input.TabId, false); - if (moduleInfo.ModuleControlId != input.ModuleControlId) - { - moduleInfo = moduleInfo.Clone(); - moduleInfo.ContainerPath = input.ContainerPath; - moduleInfo.ContainerSrc = input.ContainerSrc; - moduleInfo.ModuleControlId = input.ModuleControlId; - moduleInfo.PaneName = input.PanaName; - moduleInfo.IconFile = input.IconFile; - } - - this.ModuleContext = new ModuleInstanceContext(/*new FakeModuleControl()*/) { Configuration = moduleInfo }; + var moduleInfo = ModuleConfiguration; this.OnInit(); this.OnLoad(moduleInfo); @@ -143,54 +135,75 @@ public ActionResult Invoke(ControlViewModel input) ActionScripts = this.actionScripts, }; - return this.View(viewModel); + return viewModel; } protected string LocalizeString(string key) { return Localization.GetString(key, Localization.GlobalResourceFile); } + public ModuleResources ModuleResources + { + get + { + return new ModuleResources() + { + StyleSheets = new List() + { + new ModuleStyleSheet() + { + FilePath = "~/admin/menus/ModuleActions/ModuleActions.css", + Priority = FileOrder.Css.ModuleCss, + }, + new ModuleStyleSheet() + { + FilePath = "~/Resources/Shared/stylesheets/dnnicons/css/dnnicon.min.css", + Priority = FileOrder.Css.ModuleCss, + }, + }, + Scripts = new List() + { + new ModuleScript() + { + FilePath = "~/admin/menus/ModuleActions/ModuleActions.js", + }, + }, + Libraries = new List() + { + CommonJs.DnnPlugins, + }, + AjaxAntiForgery = true, + + }; + } + } protected void OnInit() { // base.OnInit(e); // this.ID = "ModuleActions"; // this.actionButton.Click += this.ActionButton_Click; - MvcJavaScript.RequestRegistration(CommonJs.DnnPlugins); + // MvcJavaScript.RequestRegistration(CommonJs.DnnPlugins); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/admin/menus/ModuleActions/ModuleActions.css", FileOrder.Css.ModuleCss); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/Resources/Shared/stylesheets/dnnicons/css/dnnicon.min.css", FileOrder.Css.ModuleCss); - MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/admin/menus/ModuleActions/ModuleActions.js"); + // this.RegisterStyleSheet("~/admin/menus/ModuleActions/ModuleActions.css", FileOrder.Css.ModuleCss); + //this.RegisterStyleSheet("~/Resources/Shared/stylesheets/dnnicons/css/dnnicon.min.css", FileOrder.Css.ModuleCss); + //this.RegisterScript("~/admin/menus/ModuleActions/ModuleActions.js"); - ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); + //ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); } protected void OnLoad(ModuleInfo moduleInfo) { // base.OnLoad(e); - this.ModuleContext = new ModuleInstanceContext() { Configuration = moduleInfo }; + var moduleActions = new ModuleActionCollection(); - var desktopModule = DesktopModuleController.GetDesktopModule(moduleInfo.DesktopModuleID, moduleInfo.PortalID); - if (!string.IsNullOrEmpty(desktopModule.BusinessControllerClass)) - { - var businessController = Reflection.CreateType(desktopModule.BusinessControllerClass); - var controlClass = businessController.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(moduleInfo.ModuleControl.ControlSrc) + "Control," + businessController.Assembly; - try - { - var controller = Reflection.CreateObject(controlClass, controlClass); - var control = controller as IModuleControl; - control.ModuleContext.Configuration = moduleInfo; + var moduleControl = MvcUtils.GetModuleControl(moduleInfo); - var actionable = controller as IActionable; - if (actionable != null) - { - moduleActions = actionable.ModuleActions; - } - } - catch (Exception) - { - } + var actionable = moduleControl as IActionable; + if (actionable != null) + { + moduleActions = actionable.ModuleActions; } this.ActionRoot.Actions.AddRange(this.Actions); @@ -213,12 +226,12 @@ protected void OnLoad(ModuleInfo moduleInfo) } */ moduleSpecificActions.Actions.Add(action); - - if (!UIUtilities.IsLegacyUI(this.ModuleContext.ModuleId, action.ControlKey, this.ModuleContext.PortalId) && action.Url.Contains("ctl")) + + if (!DotNetNuke.UI.UIUtilities.IsLegacyUI(this.ModuleContext.ModuleId, action.ControlKey, this.ModuleContext.PortalId) && action.Url.Contains("ctl")) { action.ClientScript = UrlUtils.PopUpUrl(action.Url, null, this.PortalSettings, true, false); } - + } } @@ -290,7 +303,7 @@ protected void OnLoad(ModuleInfo moduleInfo) if (string.IsNullOrEmpty(action.ClientScript) && !string.IsNullOrEmpty(action.Url) && action.Url.StartsWith("javascript:")) { - if (!UIUtilities.IsLegacyUI(this.ModuleContext.ModuleId, action.ControlKey, this.ModuleContext.PortalId)) + if (!DotNetNuke.UI.UIUtilities.IsLegacyUI(this.ModuleContext.ModuleId, action.ControlKey, this.ModuleContext.PortalId)) { action.ClientScript = UrlUtils.PopUpUrl(action.Url, null, this.PortalSettings, true, false); } @@ -332,5 +345,13 @@ protected void OnLoad(ModuleInfo moduleInfo) throw exc; } } + + public override string ViewName + { + get + { + return "ModuleActions"; + } + } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs new file mode 100644 index 00000000000..9767f837fbe --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs @@ -0,0 +1,26 @@ +// 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.Web.MvcWebsite.Controls +{ + using DotNetNuke.Entities.Portals; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + + public class PrivacyControl : RazorModuleControlBase + { + public override object ViewModel() + { + return Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_PRIVACY"); + } + + public override string ViewName + { + get + { + return "Terms"; + } + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs new file mode 100644 index 00000000000..270c0fc29f1 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs @@ -0,0 +1,27 @@ +// 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 + +using DotNetNuke.Web.MvcPipeline.ModuleControl; + +namespace DotNetNuke.Web.MvcWebsite.Controls +{ + using DotNetNuke.Entities.Portals; + using DotNetNuke.Services.Localization; + + public class TermsControl : RazorModuleControlBase + { + public override object ViewModel() + { + return Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_TERMS"); + } + + public override string ViewName + { + get + { + return "Terms"; + } + } + } +} diff --git a/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs b/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs index 9d526bdc254..daf270f6352 100644 --- a/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs +++ b/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs @@ -31,7 +31,7 @@ namespace DotNetNuke.Modules.Html.Controllers using DotNetNuke.Web.MvcPipeline.Controllers; using Microsoft.Extensions.DependencyInjection; - public partial class EditHTMLViewController : ModuleViewControllerBase + public class EditHTMLViewController : ModuleViewControllerBase { private readonly INavigationManager navigationManager; private readonly HtmlTextController htmlTextController; @@ -45,10 +45,11 @@ public EditHTMLViewController(IContentSecurityPolicy csp) this.contentSecurityPolicy = csp; } + /* public override string ControlPath => "~/DesktopModules/Html/"; public override string ID => "EditHTML"; - + */ protected override object ViewModel() { var model = new EditHtmlViewModel(); diff --git a/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs b/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs index a2d74e92d02..ca69e786269 100644 --- a/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs +++ b/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs @@ -41,9 +41,11 @@ public HtmlModuleViewController() this.htmlTextController = new HtmlTextController(this.navigationManager); } + /* public override string ControlPath => "~/DesktopModules/Html/"; public override string ID => "HtmlModule"; + */ protected override object ViewModel() { diff --git a/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs b/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs index 2f6440eeaab..afd57f56835 100644 --- a/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs +++ b/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs @@ -38,9 +38,11 @@ public MyWorkViewController() this.navigationManager = Globals.DependencyProvider.GetRequiredService(); } + /* public override string ControlPath => "~/DesktopModules/Html/"; public override string ID => "MyWork"; + */ protected override object ViewModel() { diff --git a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj index 28def3253f7..d00866a1854 100644 --- a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj +++ b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj @@ -182,8 +182,17 @@ + + + + MyWorkOld.ascx + ASPXCodeBehind + + + MyWorkOld.ascx + MyWork.ascx ASPXCodeBehind @@ -222,6 +231,7 @@ + diff --git a/DNN Platform/Modules/HTML/HtmlModule.ascx.cs b/DNN Platform/Modules/HTML/HtmlModule.ascx.cs index 3e87d745e81..b1e1275d647 100644 --- a/DNN Platform/Modules/HTML/HtmlModule.ascx.cs +++ b/DNN Platform/Modules/HTML/HtmlModule.ascx.cs @@ -22,6 +22,8 @@ namespace DotNetNuke.Modules.Html using DotNetNuke.Services.Localization; using DotNetNuke.Services.Personalization; using DotNetNuke.UI.WebControls; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.Utils; using Microsoft.Extensions.DependencyInjection; /// The HtmlModule Class provides the UI for displaying the Html. diff --git a/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs b/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs new file mode 100644 index 00000000000..ef9f648097e --- /dev/null +++ b/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs @@ -0,0 +1,154 @@ +// 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.Modules.Html +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net.NetworkInformation; + using System.Web; + using System.Web.Mvc; + + using DotNetNuke.Abstractions; + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.ContentSecurityPolicy; + using DotNetNuke.Entities.Content.Workflow; + using DotNetNuke.Entities.Content.Workflow.Entities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Settings; + using DotNetNuke.Framework.JavaScriptLibraries; + using DotNetNuke.Modules.Html; + using DotNetNuke.Modules.Html.Components; + using DotNetNuke.Modules.Html.Models; + using DotNetNuke.Security; + using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.Controllers; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using Microsoft.Extensions.DependencyInjection; + + public class EditHTMLControl : RazorModuleControlBase + { + private readonly INavigationManager navigationManager; + private readonly HtmlTextController htmlTextController; + private readonly IWorkflowManager workflowManager = WorkflowManager.Instance; + private readonly IContentSecurityPolicy contentSecurityPolicy; + + public EditHTMLControl(IContentSecurityPolicy csp) + { + this.navigationManager = Globals.DependencyProvider.GetRequiredService(); + this.htmlTextController = new HtmlTextController(this.navigationManager); + this.contentSecurityPolicy = csp; + } + + /* + public override string ControlPath => "~/DesktopModules/Html/"; + + public override string ID => "EditHTML"; + */ + public override object ViewModel() + { + var model = new EditHtmlViewModel(); + try + { + model.LocalResourceFile = this.LocalResourceFile; + model.ShowEditView = true; + model.ModuleId = this.ModuleId; + model.TabId = this.TabId; + model.PortalId = this.PortalId; + model.RedirectUrl = this.navigationManager.NavigateURL(); + int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; + + var htmlContentItemID = Null.NullInteger; + var htmlContent = this.htmlTextController.GetTopHtmlText(this.ModuleId, false, workflowID); + + if (htmlContent != null) + { + htmlContentItemID = htmlContent.ItemID; + var html = System.Web.HttpUtility.HtmlDecode(htmlContent.Content); + model.EditorContent = html; + } + + var workflow = this.workflowManager.GetWorkflow(workflowID); + var workflowStates = workflow.States.ToList(); + model.MaxVersions = this.htmlTextController.GetMaximumVersionHistory(this.PortalId); + var userCanEdit = this.UserInfo.IsSuperUser || PortalSecurity.IsInRole(this.PortalSettings.AdministratorRoleName); + + model.PageSize = Math.Min(Math.Max(model.MaxVersions, 5), 10); // min 5, max 10 + + switch (workflow.WorkflowKey) + { + case SystemWorkflowManager.DirectPublishWorkflowKey: + model.CurrentWorkflowType = WorkflowType.DirectPublish; + break; + case SystemWorkflowManager.SaveDraftWorkflowKey: + model.CurrentWorkflowType = WorkflowType.SaveDraft; + break; + case SystemWorkflowManager.ContentAprovalWorkflowKey: + model.CurrentWorkflowType = WorkflowType.ContentApproval; + break; + } + + if (htmlContentItemID != -1) + { + this.PopulateModelWithContent(model, htmlContent); + } + else + { + this.PopulateModelWithInitialContent(model, workflowStates[0]); + } + + model.ShowPublishOption = model.CurrentWorkflowType != WorkflowType.DirectPublish; + model.ShowCurrentVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; + model.ShowPreviewVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; + model.ShowHistoryView = false; + model.ShowMasterContentButton = false; + } + catch (Exception exc) + { + // Exceptions.ProcessModuleLoadException(this, exc); + throw new Exception("EditHTML", exc); + } + + /* + this.RegisterScript("~/Resources/Shared/scripts/jquery/jquery.form.min.js"); + this.RegisterStyleSheet("~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); + this.RegisterStyleSheet("~/DesktopModules/HTML/edit.css"); + this.RegisterScript("~/DesktopModules/HTML/js/edit.js"); + */ + /* + MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/Resources/Shared/scripts/jquery/jquery.form.min.js"); + MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); + MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/DesktopModules/HTML/edit.css"); + MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/DesktopModules/HTML/js/edit.js"); + */ + + this.contentSecurityPolicy.StyleSource.AddInline(); + this.contentSecurityPolicy.ScriptSource.AddSelf().AddInline(); + this.contentSecurityPolicy.ImgSource.AddScheme("data:"); + return model; + } + + private void PopulateModelWithContent(EditHtmlViewModel model, HtmlTextInfo htmlContent) + { + model.CurrentWorkflowInUse = htmlContent.WorkflowName; + model.CurrentWorkflowState = htmlContent.StateName; + model.CurrentVersion = htmlContent.Version.ToString(); + + // model.Content = this.FormatContent(htmlContent.Content); + } + + private void PopulateModelWithInitialContent(EditHtmlViewModel model, WorkflowState firstState) + { + // model.EditorContent = this.LocalizeString("AddContent"); + model.CurrentWorkflowInUse = firstState.StateName; + model.ShowCurrentWorkflowState = false; + model.ShowCurrentVersion = false; + } + } +} diff --git a/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs b/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs index 980defaabf3..85619862d09 100644 --- a/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs +++ b/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs @@ -7,25 +7,27 @@ namespace DotNetNuke.Modules.Html using System.Collections.Generic; using System.Linq; using System.Web; + using System.Web.Mvc; using DotNetNuke.Abstractions; using DotNetNuke.Entities.Modules; using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Modules.Html.Models; using DotNetNuke.Security; using DotNetNuke.Security.Permissions; using DotNetNuke.Services.Localization; using DotNetNuke.Web.MvcPipeline.ModuleControl; using Microsoft.Extensions.DependencyInjection; - public class HtmlModuleControl : ModuleControlBase, IActionable + public class HtmlModuleControl : RazorModuleControlBase, IActionable { private readonly INavigationManager navigationManager; + private readonly HtmlTextController htmlTextController; public HtmlModuleControl() { this.navigationManager = this.DependencyProvider.GetRequiredService(); - this.ControlPath = "DesktopModules/HTML"; - this.ID = "HtmlModule.ascx"; + this.htmlTextController = new HtmlTextController(this.navigationManager); } /// Gets moduleActions is an interface property that returns the module actions collection for the module. @@ -63,5 +65,22 @@ public ModuleActionCollection ModuleActions return actions; } } + + public override object ViewModel() + { + int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; + HtmlTextInfo content = this.htmlTextController.GetTopHtmlText(this.ModuleId, true, workflowID); + + var html = string.Empty; + if (content != null) + { + html = System.Web.HttpUtility.HtmlDecode(content.Content); + } + + return new HtmlModuleModel() + { + Html = html, + }; + } } } diff --git a/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs b/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs new file mode 100644 index 00000000000..466db06c02c --- /dev/null +++ b/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs @@ -0,0 +1,102 @@ +// 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.Modules.Html +{ + using System.Collections.Generic; + using System.Linq; + + using DotNetNuke.Abstractions; + using DotNetNuke.Common; + using DotNetNuke.Entities.Content.Workflow.Entities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Entities.Modules.Settings; + using DotNetNuke.Framework.JavaScriptLibraries; + using DotNetNuke.Modules.Html; + using DotNetNuke.Modules.Html.Components; + using DotNetNuke.Modules.Html.Models; + using DotNetNuke.Security; + using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.Mvc; + using DotNetNuke.Web.MvcPipeline.Controllers; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Website.Controllers; + using Microsoft.Extensions.DependencyInjection; + + public class MyWorkControl : RazorModuleControlBase, IActionable, IResourcable + { + private readonly INavigationManager navigationManager; + + public MyWorkControl() + { + this.navigationManager = Globals.DependencyProvider.GetRequiredService(); + } + + public ModuleActionCollection ModuleActions + { + get + { + var actions = new ModuleActionCollection(); + actions.Add( + this.GetNextActionID(), + Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), + ModuleActionType.AddContent, + string.Empty, + string.Empty, + this.EditUrl(), + false, + SecurityAccessLevel.Edit, + true, + false); + + return actions; + } + } + + public ModuleResources ModuleResources + { + get + { + return new ModuleResources() + { + StyleSheets = new List() + { + new ModuleStyleSheet() + { + FilePath = "~/DesktopModules/HTML/edit.css", + }, + new ModuleStyleSheet() + { + FilePath = "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css", + }, + }, + }; + } + } + + public override object ViewModel() + { + var objHtmlTextUsers = new HtmlTextUserController(); + var lst = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID).Cast(); + + return new MyWorkModel() + { + LocalResourceFile = this.LocalResourceFile, + ModuleId = this.ModuleId, + TabId = this.TabId, + RedirectUrl = this.navigationManager.NavigateURL(), + HtmlTextUsers = lst.Select(u => new HtmlTextUserModel() + { + Url = this.navigationManager.NavigateURL(u.TabID), + ModuleID = u.ModuleID, + ModuleTitle = u.ModuleTitle, + StateName = u.StateName, + }).ToList(), + }; + } + } +} diff --git a/DNN Platform/Modules/HTML/MyWork.ascx.cs b/DNN Platform/Modules/HTML/MyWork.ascx.cs index 770b05fa8ac..3394814b0e6 100644 --- a/DNN Platform/Modules/HTML/MyWork.ascx.cs +++ b/DNN Platform/Modules/HTML/MyWork.ascx.cs @@ -4,28 +4,36 @@ namespace DotNetNuke.Modules.Html { using System; + using System.Web.UI; using DotNetNuke.Abstractions; using DotNetNuke.Common; using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Security; using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.ModuleControl; using Microsoft.Extensions.DependencyInjection; /// MyWork allows a user to view any outstanding workflow items. - public partial class MyWork : PortalModuleBase + public partial class MyWork : PortalModuleBase, IActionable { - private readonly INavigationManager navigationManager; + private readonly MvcModuleControlRenderer renderer; /// Initializes a new instance of the class. public MyWork() { - this.navigationManager = this.DependencyProvider.GetRequiredService(); + this.renderer = new MvcModuleControlRenderer(this); } - public string FormatURL(object dataItem) + public ModuleActionCollection ModuleActions { - var objHtmlTextUser = (HtmlTextUserInfo)dataItem; - return "" + objHtmlTextUser.ModuleTitle + " ( " + objHtmlTextUser.StateName + " )"; + get + { + return this.renderer.ModuleControl.ModuleActions; + } } /// Page_Load runs when the control is loaded. @@ -33,16 +41,12 @@ public string FormatURL(object dataItem) protected override void OnLoad(EventArgs e) { base.OnLoad(e); - this.hlCancel.NavigateUrl = this.navigationManager.NavigateURL(); try { - if (!this.Page.IsPostBack) - { - var objHtmlTextUsers = new HtmlTextUserController(); - this.dgTabs.DataSource = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID); - this.dgTabs.DataBind(); - } + var html = this.renderer.RenderToString(); + this.Controls.Add(new LiteralControl(html)); + this.renderer.RegisterResources(this.renderer.ModuleControl); } catch (Exception exc) { diff --git a/DNN Platform/Modules/HTML/MyWorkOld.ascx b/DNN Platform/Modules/HTML/MyWorkOld.ascx new file mode 100644 index 00000000000..7104a1d3b9b --- /dev/null +++ b/DNN Platform/Modules/HTML/MyWorkOld.ascx @@ -0,0 +1,25 @@ +<%@ Control language="C#" Inherits="DotNetNuke.Modules.Html.MyWorkOld" CodeBehind="MyWorkOld.ascx.cs" AutoEventWireup="false" %> +<%@ Register TagPrefix="dnnweb" Namespace="DotNetNuke.Web.UI.WebControls.Internal" Assembly="DotNetNuke.Web" %> +<%@ Register TagPrefix="dnncl" Namespace="DotNetNuke.Web.Client.ClientResourceManagement" Assembly="DotNetNuke.Web.Client" %> + + + +
+ + + + + <%#FormatURL(Container.DataItem)%> + + + + +
+ +
+
+
+
    +
  • +
+
\ No newline at end of file diff --git a/DNN Platform/Modules/HTML/MyWorkOld.ascx.cs b/DNN Platform/Modules/HTML/MyWorkOld.ascx.cs new file mode 100644 index 00000000000..ff3599019fc --- /dev/null +++ b/DNN Platform/Modules/HTML/MyWorkOld.ascx.cs @@ -0,0 +1,59 @@ +// 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.Modules.Html +{ + using System; + using System.Web.UI; + + using DotNetNuke.Abstractions; + using DotNetNuke.Common; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Security; + using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using Microsoft.Extensions.DependencyInjection; + + /// MyWork allows a user to view any outstanding workflow items. + public partial class MyWorkOld : PortalModuleBase + { + private readonly INavigationManager navigationManager; + + /// Initializes a new instance of the class. + public MyWorkOld() + { + this.navigationManager = this.DependencyProvider.GetRequiredService(); + } + + public string FormatURL(object dataItem) + { + var objHtmlTextUser = (HtmlTextUserInfo)dataItem; + return "" + objHtmlTextUser.ModuleTitle + " ( " + objHtmlTextUser.StateName + " )"; + } + + /// Page_Load runs when the control is loaded. + /// The event arguments. + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + this.hlCancel.NavigateUrl = this.navigationManager.NavigateURL(); + + try + { + if (!this.Page.IsPostBack) + { + var objHtmlTextUsers = new HtmlTextUserController(); + this.dgTabs.DataSource = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID); + this.dgTabs.DataBind(); + } + } + catch (Exception exc) + { + Exceptions.ProcessModuleLoadException(this, exc); + } + } + } +} diff --git a/DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs b/DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs new file mode 100644 index 00000000000..e3c4b5f0b52 --- /dev/null +++ b/DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. +// +// Les changements apportés à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// +//------------------------------------------------------------------------------ + +namespace DotNetNuke.Modules.Html +{ + + + public partial class MyWorkOld + { + + /// + /// Contrôle customJS. + /// + /// + /// Champ généré automatiquement. + /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. + /// + protected global::DotNetNuke.Web.Client.ClientResourceManagement.DnnCssInclude customJS; + + /// + /// Contrôle dgTabs. + /// + /// + /// Champ généré automatiquement. + /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. + /// + protected global::DotNetNuke.Web.UI.WebControls.Internal.DnnGrid dgTabs; + + /// + /// Contrôle hlCancel. + /// + /// + /// Champ généré automatiquement. + /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. + /// + protected global::System.Web.UI.WebControls.HyperLink hlCancel; + } +} diff --git a/DNN Platform/Website/DotNetNuke.Website.csproj b/DNN Platform/Website/DotNetNuke.Website.csproj index ec7f3b34594..13d765b4d17 100644 --- a/DNN Platform/Website/DotNetNuke.Website.csproj +++ b/DNN Platform/Website/DotNetNuke.Website.csproj @@ -608,6 +608,7 @@ stylecop.json + AuthenticationEditor.ascx @@ -1278,7 +1279,7 @@ - + web.config @@ -3393,6 +3394,7 @@ + diff --git a/DNN Platform/Website/Views/ModuleActionsView/Invoke.cshtml b/DNN Platform/Website/Views/Default/ModuleActions.cshtml similarity index 100% rename from DNN Platform/Website/Views/ModuleActionsView/Invoke.cshtml rename to DNN Platform/Website/Views/Default/ModuleActions.cshtml diff --git a/DNN Platform/Website/Views/PrivacyView/Invoke.cshtml b/DNN Platform/Website/Views/Default/Pricacy.cshtml similarity index 100% rename from DNN Platform/Website/Views/PrivacyView/Invoke.cshtml rename to DNN Platform/Website/Views/Default/Pricacy.cshtml diff --git a/DNN Platform/Website/Views/TermsView/Invoke.cshtml b/DNN Platform/Website/Views/Default/Terms.cshtml similarity index 100% rename from DNN Platform/Website/Views/TermsView/Invoke.cshtml rename to DNN Platform/Website/Views/Default/Terms.cshtml From f60ada02886ee206a24f01c2d2d70a45be05abe1 Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 16:32:03 +0200 Subject: [PATCH 06/34] restructure ModuleControls to fit more the the ViewComponent patern --- .../DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs | 2 +- .../DefaultMvcModuleControlBase.cs | 24 +++----- .../ModuleControl/MvcModuleControl.cs | 44 +++++++------ .../ModuleControl/MvcModuleControlRenderer.cs | 39 ++---------- .../ModuleControl/Razor/IRazorModuleResult.cs | 18 ++++++ .../ModuleControl/Razor/IViewRenderer.cs | 13 ++++ .../Razor/ViewRazorModuleResult.cs | 26 ++++++++ .../ModuleControl/RazorModuleControlBase.cs | 35 ++++++++--- .../{ => Resources}/IResourcable.cs | 2 +- .../{ => Resources}/ModuleResources.cs | 2 +- .../{ => Resources}/ModuleScript.cs | 2 +- .../{ => Resources}/ModuleStyleSheet.cs | 2 +- .../Resources/ResourceableExtensions.cs | 53 ++++++++++++++++ .../ModuleControl/SpaModuleControl.cs | 10 ++- .../ModuleControl/Test/TestModule.cs | 61 +++++++++++++++++++ .../ModuleControl/Test/TestModuleControl.cs | 37 +++++++++++ .../UI/Utilities/MvcUtils.cs | 37 +++++++---- .../Controls/ModuleActionsControl.cs | 17 ++---- .../Controls/PrivacyControl.cs | 13 +--- .../Controls/TermsControl.cs | 12 +--- .../Modules/HTML/Mvc/EditHTMLControl.cs | 5 +- .../Modules/HTML/Mvc/HtmlModuleControl.cs | 7 ++- .../Modules/HTML/Mvc/MyWorkControl.cs | 8 ++- DNN Platform/Modules/HTML/MyWork.ascx.cs | 2 +- 24 files changed, 327 insertions(+), 144 deletions(-) create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IRazorModuleResult.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IViewRenderer.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/ViewRazorModuleResult.cs rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{ => Resources}/IResourcable.cs (83%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{ => Resources}/ModuleResources.cs (87%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{ => Resources}/ModuleScript.cs (83%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{ => Resources}/ModuleStyleSheet.cs (83%) create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ResourceableExtensions.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs index c09bd52c4a9..e8d2f65f47a 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/HtmlHelpers.cs @@ -16,7 +16,7 @@ namespace DotNetNuke.Web.MvcPipeline using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Framework; using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; - using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using DotNetNuke.Web.MvcPipeline.UI.Utilities; public static partial class HtmlHelpers diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs index 2e4ba96c233..76ebf72a353 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs @@ -24,23 +24,10 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl public abstract class DefaultMvcModuleControlBase : IMvcModuleControl, IDisposable { - /* - protected static readonly Regex FileInfoRegex = new Regex( - @"\.([a-z]{2,3}\-[0-9A-Z]{2,4}(-[A-Z]{2})?)(\.(Host|Portal-\d+))?\.resx$", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - TimeSpan.FromSeconds(1)); - */ - - - - private readonly ILog tracelLogger = LoggerSource.Instance.GetLogger("DNN.Trace"); private readonly Lazy serviceScopeContainer = new Lazy(ServiceScopeContainer.GetRequestOrCreateScope); private string localResourceFile; private ModuleInstanceContext moduleContext; - - //public ViewContext ViewContext { get; set; } - public ModuleInfo ModuleConfiguration { get @@ -140,15 +127,18 @@ public virtual string ControlName get { return Path.GetFileNameWithoutExtension(this.ModuleConfiguration.ModuleControl.ControlSrc); + } } + /// Gets or Sets the Path for this control (used primarily for UserControls). /// A String. public virtual string ControlPath { get { + return Path.GetDirectoryName(this.ModuleConfiguration.ModuleControl.ControlSrc); } } @@ -166,10 +156,10 @@ public ModuleInstanceContext ModuleContext return this.moduleContext; } - internal set - { - this.moduleContext = value; - } + //internal set + //{ + // this.moduleContext = value; + //} } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs index 401b3ee9817..b2654ee0def 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControl.cs @@ -32,6 +32,25 @@ public class MvcModuleControl : DefaultMvcModuleControlBase private const string ExcludedQueryStringParams = "tabid,mid,ctl,language,popup,action,controller"; private const string ExcludedRouteValues = "mid,ctl,popup"; + public override string ControlName + { + get + { + return RouteActionName; + } + } + + + /// Gets or Sets the Path for this control (used primarily for UserControls). + /// A String. + public override string ControlPath + { + get + { + return string.Format("~/DesktopModules/MVC/{0}", ModuleConfiguration.DesktopModule.FolderName); + } + } + /// Gets or sets the action name for the MVC route. /// A String. public string RouteActionName @@ -87,26 +106,6 @@ public string[] GetSegments() return this.ModuleConfiguration.ModuleControl.ControlSrc.Replace(".mvc", string.Empty).Split('/'); } - /// Gets the Name for this control. - /// A String. - public override string ControlName - { - get - { - return RouteActionName; - } - } - - /// Gets or Sets the Path for this control (used primarily for UserControls). - /// A String. - public override string ControlPath - { - get - { - return string.Format("~/DesktopModules/MVC/{0}", ModuleConfiguration.DesktopModule.FolderName); - } - } - public override IHtmlString Html(HtmlHelper htmlHelper) { var module = this.ModuleConfiguration; @@ -127,13 +126,12 @@ public override IHtmlString Html(HtmlHelper htmlHelper) string actionName = string.Empty; var controlKey = module.ModuleControl.ControlKey; - /* - var localResourceFile = string.Format( + + this.LocalResourceFile = string.Format( "~/DesktopModules/MVC/{0}/{1}/{2}.resx", module.DesktopModule.FolderName, Localization.LocalResourceDirectory, RouteActionName); - */ RouteValueDictionary values = new RouteValueDictionary { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs index f0d67458160..e0dc656e3b6 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs @@ -10,6 +10,7 @@ using DotNetNuke.UI.Modules; using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; +using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using DotNetNuke.Web.MvcPipeline.Utils; namespace DotNetNuke.Web.MvcPipeline.ModuleControl @@ -21,7 +22,7 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl public MvcModuleControlRenderer(Control control, ModuleInstanceContext moduleContext) { this.moduleControl = new T(); - moduleControl.ModuleContext = moduleContext; + moduleControl.ModuleContext.Configuration = moduleContext.Configuration; moduleControl.Control = control; } @@ -34,42 +35,12 @@ public MvcModuleControlRenderer(PortalModuleBase control) public string RenderToString() { var renderer = new ViewRenderer(); - return renderer.RenderViewToString(moduleControl.ViewName, moduleControl.ViewModel()); + var res = moduleControl.Invoke(); + return renderer.RenderViewToString(res.ViewName, res.Model); } public T ModuleControl => this.moduleControl; - public void RegisterResources(IResourcable resourcable) - { - if (resourcable.ModuleResources.StyleSheets != null) - { - foreach (var styleSheet in resourcable.ModuleResources.StyleSheets) - { - ClientResourceManager.RegisterStyleSheet(ModuleControl.Control.Page, styleSheet.FilePath, styleSheet.Priority, styleSheet.HtmlAttributes); - } - } - if (resourcable.ModuleResources.Scripts != null) - { - foreach (var javaScript in resourcable.ModuleResources.Scripts) - { - ClientResourceManager.RegisterScript(ModuleControl.Control.Page, javaScript.FilePath, javaScript.Priority, javaScript.HtmlAttributes); - } - } - if (resourcable.ModuleResources.Libraries != null) - { - foreach (var lib in resourcable.ModuleResources.Libraries) - { - JavaScript.RequestRegistration(lib); - } - } - if (resourcable.ModuleResources.AjaxScript) - { - ServicesFramework.Instance.RequestAjaxScriptSupport(); - } - if (resourcable.ModuleResources.AjaxAntiForgery) - { - ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); - } - } + } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IRazorModuleResult.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IRazorModuleResult.cs new file mode 100644 index 00000000000..aeed024b7ff --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IRazorModuleResult.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using DotNetNuke.Web.MvcPipeline.Utils; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Razor +{ + public interface IRazorModuleResult + { + IHtmlString Execute(HtmlHelper htmlHelper); + string ViewName { get; } + object Model { get; } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IViewRenderer.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IViewRenderer.cs new file mode 100644 index 00000000000..53358d4255c --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/IViewRenderer.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Razor +{ + public interface IViewRenderer + { + string RenderViewToString(string viewPath, object model = null); + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/ViewRazorModuleResult.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/ViewRazorModuleResult.cs new file mode 100644 index 00000000000..52d476133ea --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/ViewRazorModuleResult.cs @@ -0,0 +1,26 @@ +using System; +using System.Web; +using System.Web.Mvc; +using System.Web.Mvc.Html; +using DotNetNuke.Web.MvcPipeline.Utils; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Razor +{ + public class ViewRazorModuleResult : IRazorModuleResult + { + public ViewRazorModuleResult(string viewName, object model) + { + this.ViewName = viewName; + this.Model = model; + } + + public string ViewName { get; private set; } + public object Model { get; private set; } + + public IHtmlString Execute(HtmlHelper htmlHelper) + { + return htmlHelper.Partial(ViewName, Model); + } + + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs index a976ce11571..b43b52f3334 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs @@ -6,21 +6,19 @@ using System.Web; using System.Web.Mvc; using System.Web.Mvc.Html; +using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; namespace DotNetNuke.Web.MvcPipeline.ModuleControl { public abstract class RazorModuleControlBase : DefaultMvcModuleControlBase { - - public abstract object ViewModel(); - public override IHtmlString Html(HtmlHelper htmlHelper) { - var model = this.ViewModel(); - return htmlHelper.Partial(this.ViewName, model); + var res = this.Invoke(); + return res.Execute(htmlHelper); } - public virtual string ViewName + protected virtual string DefaultViewName { get { @@ -28,6 +26,29 @@ public virtual string ViewName } } - public abstract object ViewModel(); + public abstract IRazorModuleResult Invoke(); + + public IRazorModuleResult View() + { + return View(null); + } + + public IRazorModuleResult View(string viewName) + { + return View(viewName, null); + } + + public IRazorModuleResult View(object model) + { + return View(null, model); + } + public IRazorModuleResult View(string viewName, object model) + { + if (string.IsNullOrEmpty(viewName)) + { + viewName= this.DefaultViewName; + } + return new ViewRazorModuleResult(viewName, model); + } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/IResourcable.cs similarity index 83% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/IResourcable.cs index a29ec846454..cafb7e91cf6 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/IResourcable.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/IResourcable.cs @@ -2,7 +2,7 @@ // 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.Web.MvcPipeline.ModuleControl +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Resources { public interface IResourcable { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleResources.cs similarity index 87% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleResources.cs index a2d60825410..2a66652ad7f 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleResources.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleResources.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace DotNetNuke.Web.MvcPipeline.ModuleControl +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Resources { public class ModuleResources { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleScript.cs similarity index 83% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleScript.cs index 1ba8b41abfc..499a5ba4d8e 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleScript.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleScript.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using DotNetNuke.Web.Client; -namespace DotNetNuke.Web.MvcPipeline.ModuleControl +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Resources { public class ModuleScript { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleStyleSheet.cs similarity index 83% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleStyleSheet.cs index bc03acd7763..6b6e579181d 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/ModuleStyleSheet.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ModuleStyleSheet.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using DotNetNuke.Web.Client; -namespace DotNetNuke.Web.MvcPipeline.ModuleControl +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Resources { public class ModuleStyleSheet { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ResourceableExtensions.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ResourceableExtensions.cs new file mode 100644 index 00000000000..2b6628eb4f6 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Resources/ResourceableExtensions.cs @@ -0,0 +1,53 @@ +// 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 + +using System.Web.UI; +using DotNetNuke.Framework; +using DotNetNuke.Framework.JavaScriptLibraries; +using DotNetNuke.Web.Client.ClientResourceManagement; +using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl +{ + + + /// + /// Extension methods for IResourceable interface. + /// + public static class ResourceableExtensions + { + public static void RegisterResources(this IResourcable resourcable, Page page) + { + if (resourcable.ModuleResources.StyleSheets != null) + { + foreach (var styleSheet in resourcable.ModuleResources.StyleSheets) + { + ClientResourceManager.RegisterStyleSheet(page, styleSheet.FilePath, styleSheet.Priority, styleSheet.HtmlAttributes); + } + } + if (resourcable.ModuleResources.Scripts != null) + { + foreach (var javaScript in resourcable.ModuleResources.Scripts) + { + ClientResourceManager.RegisterScript(page, javaScript.FilePath, javaScript.Priority, javaScript.HtmlAttributes); + } + } + if (resourcable.ModuleResources.Libraries != null) + { + foreach (var lib in resourcable.ModuleResources.Libraries) + { + JavaScript.RequestRegistration(lib); + } + } + if (resourcable.ModuleResources.AjaxScript) + { + ServicesFramework.Instance.RequestAjaxScriptSupport(); + } + if (resourcable.ModuleResources.AjaxAntiForgery) + { + ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); + } + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs index 421da678750..47b2b134bdd 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs @@ -31,6 +31,7 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl using DotNetNuke.UI.Modules.Html5; using DotNetNuke.Web.Client; using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using DotNetNuke.Web.MvcPipeline.Tokens; using Microsoft.Extensions.DependencyInjection; @@ -38,12 +39,12 @@ public class SpaModuleControl : DefaultMvcModuleControlBase, IResourcable { private readonly IBusinessControllerProvider businessControllerProvider; - public SpaModuleControl() + public SpaModuleControl(): base() { this.businessControllerProvider = Globals.DependencyProvider.GetRequiredService(); } - public SpaModuleControl(IBusinessControllerProvider businessControllerProvider) + public SpaModuleControl(IBusinessControllerProvider businessControllerProvider) : base() { this.businessControllerProvider = businessControllerProvider; } @@ -52,9 +53,7 @@ public string html5File { get { - var controlSrc = ModuleConfiguration.ModuleControl.ControlSrc; - - return controlSrc; + return ModuleConfiguration.ModuleControl.ControlSrc; } } @@ -97,7 +96,6 @@ public ModuleResources ModuleResources return resource; } } - public override IHtmlString Html(HtmlHelper htmlHelper) { var fileContent = string.Empty; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs new file mode 100644 index 00000000000..fd6924285d5 --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.UI; +using System.Web.UI.WebControls; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Entities.Modules.Actions; +using DotNetNuke.Web.MvcPipeline.ModuleControl; +using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; +using DotNetNuke.Web.MvcPipeline.UI.Utilities; +using DotNetNuke.Web.MvcPipeline.Utils; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Test { + + public class TestModule : PortalModuleBase, IActionable + { + private string html = string.Empty; + + public ModuleActionCollection ModuleActions { get; private set; } = new ModuleActionCollection(); + + // Make sure child controls are created when needed + protected override void CreateChildControls() + { + Controls.Clear(); + Controls.Add(new LiteralControl(html)); + // important so ASP.NET tracks the created controls across postbacks + ChildControlsCreated = true; + base.CreateChildControls(); + } + + // ensure child controls exist early in page lifecycle + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + var mc = MvcUtils.CreateModuleControl(this.ModuleConfiguration); + if (mc is RazorModuleControlBase) + { + var moduleControl = (RazorModuleControlBase)mc; + moduleControl.Control = this; + // moduleControl.ModuleContext = this.ModuleContext; + var res = moduleControl.Invoke(); + + var renderer = new ViewRenderer(); + html = renderer.RenderViewToString(res.ViewName, res.Model); + } + if (mc is IActionable){ + var moduleControl = (IActionable)mc; + this.ModuleActions = moduleControl.ModuleActions; + } + if (mc is IResourcable) + { + var moduleControl = (IResourcable)mc; + moduleControl.RegisterResources(this.Page); + } + + EnsureChildControls(); + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs new file mode 100644 index 00000000000..9d6c955c80f --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Test +{ + public class TestModuleControl : RazorModuleControlBase + { + public override string ControlName + { + get + { + return "TestModuleControl"; + } + } + + /// Gets or Sets the Path for this control (used primarily for UserControls). + /// A String. + public override string ControlPath + { + get + { + + return "DesktopModules/mvcpl/mvcpl1"; + } + } + + public override IRazorModuleResult Invoke() + { + return View("~/Views/Default/Terms.cshtml", "Hello from TestModuleControl"); + } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs index fe7035d0808..64eb58d3848 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs @@ -47,7 +47,7 @@ public static string GetControlControllerName(string controlSrc) { "Admin/Portal/Privacy.ascx", "DotNetNuke.Web.MvcWebsite.Controls.PrivacyControl, DotNetNuke.Web.MvcWebsite" } }; - public static IMvcModuleControl GetModuleControl(ModuleInfo module) + public static IMvcModuleControl CreateModuleControl(ModuleInfo module) { return GetModuleControl(module, module.ModuleControl.ControlSrc); } @@ -85,20 +85,33 @@ public static IMvcModuleControl GetModuleControl(ModuleInfo module, string contr } else { - if (string.IsNullOrEmpty(module.DesktopModule.BusinessControllerClass)) + var controlSrcType = Reflection.CreateType(controlSrc); + if (controlSrcType != null) { - throw new Exception("The BusinessControllerClass is not defined for the module " + module.ModuleDefinition.FriendlyName); + var controlClass = controlSrcType.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(controlSrcType.Name) + "Control," + controlSrcType.Assembly; + try + { + var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); + control = controller as IMvcModuleControl; + } + catch (Exception ex) + { + throw new Exception("Could not create instance of " + controlClass, ex); + } } - var businessController = Reflection.CreateType(module.DesktopModule.BusinessControllerClass); - var controlClass = businessController.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(controlSrc) + "Control," + businessController.Assembly; - try + else { - var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); - control = controller as IMvcModuleControl; - } - catch (Exception ex) - { - throw new Exception("Could not create instance of " + controlClass, ex); + var businessController = Reflection.CreateType(module.DesktopModule.BusinessControllerClass); + var controlClass = businessController.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(controlSrc) + "Control," + businessController.Assembly; + try + { + var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); + control = controller as IMvcModuleControl; + } + catch (Exception ex) + { + throw new Exception("Could not create instance of " + controlClass, ex); + } } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs index 6f0568b3b44..88ef27f718d 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/ModuleActionsControl.cs @@ -8,7 +8,6 @@ namespace DotNetNuke.Web.MvcWebsite.Controls using System.Collections.Generic; using System.Web.Mvc; using System.Web.Script.Serialization; - using DotNetNuke.Common; using DotNetNuke.Common.Utilities; using DotNetNuke.Entities.Modules; @@ -27,9 +26,10 @@ namespace DotNetNuke.Web.MvcWebsite.Controls using DotNetNuke.Web.Client; using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Framework.JavascriptLibraries; - using DotNetNuke.Web.MvcPipeline.ModuleControl; using DotNetNuke.Web.MvcPipeline.Models; using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using DotNetNuke.Web.MvcPipeline.UI.Utilities; using DotNetNuke.Web.MvcWebsite.Models; @@ -110,7 +110,7 @@ protected ModuleActionCollection Actions } } - public override object ViewModel() + public override IRazorModuleResult Invoke() { var moduleInfo = ModuleConfiguration; this.OnInit(); @@ -135,7 +135,7 @@ public override object ViewModel() ActionScripts = this.actionScripts, }; - return viewModel; + return View("ModuleActions", viewModel); } protected string LocalizeString(string key) @@ -198,7 +198,7 @@ protected void OnLoad(ModuleInfo moduleInfo) var moduleActions = new ModuleActionCollection(); - var moduleControl = MvcUtils.GetModuleControl(moduleInfo); + var moduleControl = MvcUtils.CreateModuleControl(moduleInfo); var actionable = moduleControl as IActionable; if (actionable != null) @@ -346,12 +346,5 @@ protected void OnLoad(ModuleInfo moduleInfo) } } - public override string ViewName - { - get - { - return "ModuleActions"; - } - } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs index 9767f837fbe..f7afc579777 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs @@ -7,20 +7,13 @@ namespace DotNetNuke.Web.MvcWebsite.Controls using DotNetNuke.Entities.Portals; using DotNetNuke.Services.Localization; using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; public class PrivacyControl : RazorModuleControlBase { - public override object ViewModel() + public override IRazorModuleResult Invoke() { - return Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_PRIVACY"); - } - - public override string ViewName - { - get - { - return "Terms"; - } + return View("Privacy", Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_PRIVACY")); } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs index 270c0fc29f1..358ea650ad4 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs @@ -8,20 +8,14 @@ namespace DotNetNuke.Web.MvcWebsite.Controls { using DotNetNuke.Entities.Portals; using DotNetNuke.Services.Localization; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; public class TermsControl : RazorModuleControlBase { - public override object ViewModel() + public override IRazorModuleResult Invoke() { - return Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_TERMS"); + return View("Terms", Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_TERMS")); } - public override string ViewName - { - get - { - return "Terms"; - } - } } } diff --git a/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs b/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs index ef9f648097e..0000b93a31c 100644 --- a/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs +++ b/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs @@ -30,6 +30,7 @@ namespace DotNetNuke.Modules.Html using DotNetNuke.Web.Client.ClientResourceManagement; using DotNetNuke.Web.MvcPipeline.Controllers; using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; using Microsoft.Extensions.DependencyInjection; public class EditHTMLControl : RazorModuleControlBase @@ -51,7 +52,7 @@ public EditHTMLControl(IContentSecurityPolicy csp) public override string ID => "EditHTML"; */ - public override object ViewModel() + public override IRazorModuleResult Invoke() { var model = new EditHtmlViewModel(); try @@ -131,7 +132,7 @@ public override object ViewModel() this.contentSecurityPolicy.StyleSource.AddInline(); this.contentSecurityPolicy.ScriptSource.AddSelf().AddInline(); this.contentSecurityPolicy.ImgSource.AddScheme("data:"); - return model; + return this.View(model); } private void PopulateModelWithContent(EditHtmlViewModel model, HtmlTextInfo htmlContent) diff --git a/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs b/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs index 85619862d09..6560303e5a6 100644 --- a/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs +++ b/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs @@ -17,6 +17,7 @@ namespace DotNetNuke.Modules.Html using DotNetNuke.Security.Permissions; using DotNetNuke.Services.Localization; using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; using Microsoft.Extensions.DependencyInjection; public class HtmlModuleControl : RazorModuleControlBase, IActionable @@ -66,7 +67,7 @@ public ModuleActionCollection ModuleActions } } - public override object ViewModel() + public override IRazorModuleResult Invoke() { int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; HtmlTextInfo content = this.htmlTextController.GetTopHtmlText(this.ModuleId, true, workflowID); @@ -77,10 +78,10 @@ public override object ViewModel() html = System.Web.HttpUtility.HtmlDecode(content.Content); } - return new HtmlModuleModel() + return this.View(new HtmlModuleModel() { Html = html, - }; + }); } } } diff --git a/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs b/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs index 466db06c02c..593a46bfc31 100644 --- a/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs +++ b/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs @@ -24,6 +24,8 @@ namespace DotNetNuke.Modules.Html using DotNetNuke.Web.Mvc; using DotNetNuke.Web.MvcPipeline.Controllers; using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using DotNetNuke.Website.Controllers; using Microsoft.Extensions.DependencyInjection; @@ -78,12 +80,12 @@ public ModuleResources ModuleResources } } - public override object ViewModel() + public override IRazorModuleResult Invoke() { var objHtmlTextUsers = new HtmlTextUserController(); var lst = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID).Cast(); - return new MyWorkModel() + return this.View(new MyWorkModel() { LocalResourceFile = this.LocalResourceFile, ModuleId = this.ModuleId, @@ -96,7 +98,7 @@ public override object ViewModel() ModuleTitle = u.ModuleTitle, StateName = u.StateName, }).ToList(), - }; + }); } } } diff --git a/DNN Platform/Modules/HTML/MyWork.ascx.cs b/DNN Platform/Modules/HTML/MyWork.ascx.cs index 3394814b0e6..b3f36a4e0f0 100644 --- a/DNN Platform/Modules/HTML/MyWork.ascx.cs +++ b/DNN Platform/Modules/HTML/MyWork.ascx.cs @@ -46,7 +46,7 @@ protected override void OnLoad(EventArgs e) { var html = this.renderer.RenderToString(); this.Controls.Add(new LiteralControl(html)); - this.renderer.RegisterResources(this.renderer.ModuleControl); + this.renderer.ModuleControl.RegisterResources(this.Page); } catch (Exception exc) { From c716f4e1ac9fad312631dbc8c8b267eb641f55e9 Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 22:03:22 +0200 Subject: [PATCH 07/34] fix logo styling --- .../DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Logo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Logo.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Logo.cs index ae0170dd365..4126a330e61 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Logo.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Logo.cs @@ -39,6 +39,7 @@ public static IHtmlString Logo(this HtmlHelper helper, string borderW tbImage.Attributes.Add("alt", portalSettings.PortalName); TagBuilder tbLink = new TagBuilder("a"); + tbLink.GenerateId("dnn_dnnLOGO_"); if (!string.IsNullOrEmpty(linkCssClass)) { tbLink.AddCssClass(linkCssClass); From be77a41c789dad9180b883a8b09c73d802859110 Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 22:03:51 +0200 Subject: [PATCH 08/34] fix html module --- .../Controllers/EditHTMLViewController.cs | 145 ------------------ .../Controllers/HtmlModuleViewController.cs | 67 -------- .../HTML/Controllers/MyWorkViewController.cs | 69 --------- .../HTML/DotNetNuke.Modules.Html.csproj | 11 -- DNN Platform/Modules/HTML/MyWork.ascx.cs | 30 ++-- .../Modules/HTML/MyWork.ascx.designer.cs | 53 ++++--- DNN Platform/Modules/HTML/MyWorkOld.ascx | 25 --- DNN Platform/Modules/HTML/MyWorkOld.ascx.cs | 59 ------- .../Modules/HTML/MyWorkOld.ascx.designer.cs | 44 ------ 9 files changed, 43 insertions(+), 460 deletions(-) delete mode 100644 DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs delete mode 100644 DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs delete mode 100644 DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs delete mode 100644 DNN Platform/Modules/HTML/MyWorkOld.ascx delete mode 100644 DNN Platform/Modules/HTML/MyWorkOld.ascx.cs delete mode 100644 DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs diff --git a/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs b/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs deleted file mode 100644 index daf270f6352..00000000000 --- a/DNN Platform/Modules/HTML/Controllers/EditHTMLViewController.cs +++ /dev/null @@ -1,145 +0,0 @@ -// 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.Modules.Html.Controllers -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net.NetworkInformation; - using System.Web; - using System.Web.Mvc; - - using DotNetNuke.Abstractions; - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.ContentSecurityPolicy; - using DotNetNuke.Entities.Content.Workflow; - using DotNetNuke.Entities.Content.Workflow.Entities; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Settings; - using DotNetNuke.Framework.JavaScriptLibraries; - using DotNetNuke.Modules.Html; - using DotNetNuke.Modules.Html.Components; - using DotNetNuke.Modules.Html.Models; - using DotNetNuke.Security; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.MvcPipeline.Controllers; - using Microsoft.Extensions.DependencyInjection; - - public class EditHTMLViewController : ModuleViewControllerBase - { - private readonly INavigationManager navigationManager; - private readonly HtmlTextController htmlTextController; - private readonly IWorkflowManager workflowManager = WorkflowManager.Instance; - private readonly IContentSecurityPolicy contentSecurityPolicy; - - public EditHTMLViewController(IContentSecurityPolicy csp) - { - this.navigationManager = Globals.DependencyProvider.GetRequiredService(); - this.htmlTextController = new HtmlTextController(this.navigationManager); - this.contentSecurityPolicy = csp; - } - - /* - public override string ControlPath => "~/DesktopModules/Html/"; - - public override string ID => "EditHTML"; - */ - protected override object ViewModel() - { - var model = new EditHtmlViewModel(); - try - { - model.LocalResourceFile = this.LocalResourceFile; - model.ShowEditView = true; - model.ModuleId = this.ModuleId; - model.TabId = this.TabId; - model.PortalId = this.PortalId; - model.RedirectUrl = this.navigationManager.NavigateURL(); - int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; - - var htmlContentItemID = Null.NullInteger; - var htmlContent = this.htmlTextController.GetTopHtmlText(this.ModuleId, false, workflowID); - - if (htmlContent != null) - { - htmlContentItemID = htmlContent.ItemID; - var html = System.Web.HttpUtility.HtmlDecode(htmlContent.Content); - model.EditorContent = html; - } - - var workflow = this.workflowManager.GetWorkflow(workflowID); - var workflowStates = workflow.States.ToList(); - model.MaxVersions = this.htmlTextController.GetMaximumVersionHistory(this.PortalId); - var userCanEdit = this.UserInfo.IsSuperUser || PortalSecurity.IsInRole(this.PortalSettings.AdministratorRoleName); - - model.PageSize = Math.Min(Math.Max(model.MaxVersions, 5), 10); // min 5, max 10 - - switch (workflow.WorkflowKey) - { - case SystemWorkflowManager.DirectPublishWorkflowKey: - model.CurrentWorkflowType = WorkflowType.DirectPublish; - break; - case SystemWorkflowManager.SaveDraftWorkflowKey: - model.CurrentWorkflowType = WorkflowType.SaveDraft; - break; - case SystemWorkflowManager.ContentAprovalWorkflowKey: - model.CurrentWorkflowType = WorkflowType.ContentApproval; - break; - } - - if (htmlContentItemID != -1) - { - this.PopulateModelWithContent(model, htmlContent); - } - else - { - this.PopulateModelWithInitialContent(model, workflowStates[0]); - } - - model.ShowPublishOption = model.CurrentWorkflowType != WorkflowType.DirectPublish; - model.ShowCurrentVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; - model.ShowPreviewVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; - model.ShowHistoryView = false; - model.ShowMasterContentButton = false; - } - catch (Exception exc) - { - // Exceptions.ProcessModuleLoadException(this, exc); - throw new Exception("EditHTML", exc); - } - - MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/Resources/Shared/scripts/jquery/jquery.form.min.js"); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/DesktopModules/HTML/edit.css"); - MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/DesktopModules/HTML/js/edit.js"); - - this.contentSecurityPolicy.StyleSource.AddInline(); - this.contentSecurityPolicy.ScriptSource.AddSelf().AddInline(); - this.contentSecurityPolicy.ImgSource.AddScheme("data:"); - return model; - } - - private void PopulateModelWithContent(EditHtmlViewModel model, HtmlTextInfo htmlContent) - { - model.CurrentWorkflowInUse = htmlContent.WorkflowName; - model.CurrentWorkflowState = htmlContent.StateName; - model.CurrentVersion = htmlContent.Version.ToString(); - - // model.Content = this.FormatContent(htmlContent.Content); - } - - private void PopulateModelWithInitialContent(EditHtmlViewModel model, WorkflowState firstState) - { - // model.EditorContent = this.LocalizeString("AddContent"); - model.CurrentWorkflowInUse = firstState.StateName; - model.ShowCurrentWorkflowState = false; - model.ShowCurrentVersion = false; - } - } -} diff --git a/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs b/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs deleted file mode 100644 index ca69e786269..00000000000 --- a/DNN Platform/Modules/HTML/Controllers/HtmlModuleViewController.cs +++ /dev/null @@ -1,67 +0,0 @@ -// 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.Modules.Html.Controllers -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net.NetworkInformation; - using System.Web; - using System.Web.Mvc; - - using DotNetNuke.Abstractions; - using DotNetNuke.Common; - using DotNetNuke.Entities.Content.Workflow.Entities; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Actions; - using DotNetNuke.Entities.Modules.Settings; - using DotNetNuke.Framework.JavaScriptLibraries; - using DotNetNuke.Modules.Html; - using DotNetNuke.Modules.Html.Components; - using DotNetNuke.Modules.Html.Models; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Services.Personalization; - using DotNetNuke.UI.Modules; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.MvcPipeline.Controllers; - using Microsoft.Extensions.DependencyInjection; - - public class HtmlModuleViewController : ModuleViewControllerBase - { - private readonly INavigationManager navigationManager; - private readonly HtmlTextController htmlTextController; - - public HtmlModuleViewController() - { - this.navigationManager = Globals.DependencyProvider.GetRequiredService(); - this.htmlTextController = new HtmlTextController(this.navigationManager); - } - - /* - public override string ControlPath => "~/DesktopModules/Html/"; - - public override string ID => "HtmlModule"; - */ - - protected override object ViewModel() - { - int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; - HtmlTextInfo content = this.htmlTextController.GetTopHtmlText(this.ModuleId, true, workflowID); - - var html = string.Empty; - if (content != null) - { - html = System.Web.HttpUtility.HtmlDecode(content.Content); - } - - return new HtmlModuleModel() - { - Html = html, - }; - } - } -} diff --git a/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs b/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs deleted file mode 100644 index afd57f56835..00000000000 --- a/DNN Platform/Modules/HTML/Controllers/MyWorkViewController.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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.Modules.Html.Controllers -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net.NetworkInformation; - using System.Web; - using System.Web.Mvc; - - using DotNetNuke.Abstractions; - using DotNetNuke.Common; - using DotNetNuke.Entities.Content.Workflow.Entities; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Settings; - using DotNetNuke.Framework.JavaScriptLibraries; - using DotNetNuke.Modules.Html; - using DotNetNuke.Modules.Html.Components; - using DotNetNuke.Modules.Html.Models; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.Mvc; - using DotNetNuke.Web.MvcPipeline.Controllers; - using DotNetNuke.Website.Controllers; - using Microsoft.Extensions.DependencyInjection; - - public class MyWorkViewController : ModuleViewControllerBase - { - private readonly INavigationManager navigationManager; - - public MyWorkViewController() - { - this.navigationManager = Globals.DependencyProvider.GetRequiredService(); - } - - /* - public override string ControlPath => "~/DesktopModules/Html/"; - - public override string ID => "MyWork"; - */ - - protected override object ViewModel() - { - var objHtmlTextUsers = new HtmlTextUserController(); - var lst = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID).Cast(); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/DesktopModules/HTML/edit.css"); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); - return new MyWorkModel() - { - LocalResourceFile = this.LocalResourceFile, - ModuleId = this.ModuleId, - TabId = this.TabId, - RedirectUrl = this.navigationManager.NavigateURL(), - HtmlTextUsers = lst.Select(u => new HtmlTextUserModel() - { - Url = this.navigationManager.NavigateURL(u.TabID), - ModuleID = u.ModuleID, - ModuleTitle = u.ModuleTitle, - StateName = u.StateName, - }).ToList(), - }; - } - } -} diff --git a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj index d00866a1854..8d6f2fa0fd1 100644 --- a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj +++ b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj @@ -159,9 +159,6 @@ - - - @@ -186,13 +183,6 @@ - - MyWorkOld.ascx - ASPXCodeBehind - - - MyWorkOld.ascx - MyWork.ascx ASPXCodeBehind @@ -231,7 +221,6 @@ - diff --git a/DNN Platform/Modules/HTML/MyWork.ascx.cs b/DNN Platform/Modules/HTML/MyWork.ascx.cs index b3f36a4e0f0..770b05fa8ac 100644 --- a/DNN Platform/Modules/HTML/MyWork.ascx.cs +++ b/DNN Platform/Modules/HTML/MyWork.ascx.cs @@ -4,36 +4,28 @@ namespace DotNetNuke.Modules.Html { using System; - using System.Web.UI; using DotNetNuke.Abstractions; using DotNetNuke.Common; using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Actions; - using DotNetNuke.Security; using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.MvcPipeline.ModuleControl; using Microsoft.Extensions.DependencyInjection; /// MyWork allows a user to view any outstanding workflow items. - public partial class MyWork : PortalModuleBase, IActionable + public partial class MyWork : PortalModuleBase { - private readonly MvcModuleControlRenderer renderer; + private readonly INavigationManager navigationManager; /// Initializes a new instance of the class. public MyWork() { - this.renderer = new MvcModuleControlRenderer(this); + this.navigationManager = this.DependencyProvider.GetRequiredService(); } - public ModuleActionCollection ModuleActions + public string FormatURL(object dataItem) { - get - { - return this.renderer.ModuleControl.ModuleActions; - } + var objHtmlTextUser = (HtmlTextUserInfo)dataItem; + return "" + objHtmlTextUser.ModuleTitle + " ( " + objHtmlTextUser.StateName + " )"; } /// Page_Load runs when the control is loaded. @@ -41,12 +33,16 @@ public ModuleActionCollection ModuleActions protected override void OnLoad(EventArgs e) { base.OnLoad(e); + this.hlCancel.NavigateUrl = this.navigationManager.NavigateURL(); try { - var html = this.renderer.RenderToString(); - this.Controls.Add(new LiteralControl(html)); - this.renderer.ModuleControl.RegisterResources(this.Page); + if (!this.Page.IsPostBack) + { + var objHtmlTextUsers = new HtmlTextUserController(); + this.dgTabs.DataSource = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID); + this.dgTabs.DataBind(); + } } catch (Exception exc) { diff --git a/DNN Platform/Modules/HTML/MyWork.ascx.designer.cs b/DNN Platform/Modules/HTML/MyWork.ascx.designer.cs index d1c20a4491d..0310486ee53 100644 --- a/DNN Platform/Modules/HTML/MyWork.ascx.designer.cs +++ b/DNN Platform/Modules/HTML/MyWork.ascx.designer.cs @@ -1,36 +1,43 @@ -// -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// +// Les changements apportés à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// //------------------------------------------------------------------------------ -namespace DotNetNuke.Modules.Html { - - - public partial class MyWork { - /// customJS control. +namespace DotNetNuke.Modules.Html +{ + + + public partial class MyWork + { + + /// + /// Contrôle customJS. + /// /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. + /// Champ généré automatiquement. + /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. /// protected global::DotNetNuke.Web.Client.ClientResourceManagement.DnnCssInclude customJS; - /// dgTabs control. + + /// + /// Contrôle dgTabs. + /// /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. + /// Champ généré automatiquement. + /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. /// protected global::DotNetNuke.Web.UI.WebControls.Internal.DnnGrid dgTabs; - /// hlCancel control. + + /// + /// Contrôle hlCancel. + /// /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. + /// Champ généré automatiquement. + /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. /// protected global::System.Web.UI.WebControls.HyperLink hlCancel; } diff --git a/DNN Platform/Modules/HTML/MyWorkOld.ascx b/DNN Platform/Modules/HTML/MyWorkOld.ascx deleted file mode 100644 index 7104a1d3b9b..00000000000 --- a/DNN Platform/Modules/HTML/MyWorkOld.ascx +++ /dev/null @@ -1,25 +0,0 @@ -<%@ Control language="C#" Inherits="DotNetNuke.Modules.Html.MyWorkOld" CodeBehind="MyWorkOld.ascx.cs" AutoEventWireup="false" %> -<%@ Register TagPrefix="dnnweb" Namespace="DotNetNuke.Web.UI.WebControls.Internal" Assembly="DotNetNuke.Web" %> -<%@ Register TagPrefix="dnncl" Namespace="DotNetNuke.Web.Client.ClientResourceManagement" Assembly="DotNetNuke.Web.Client" %> - - - -
- - - - - <%#FormatURL(Container.DataItem)%> - - - - -
- -
-
-
-
    -
  • -
-
\ No newline at end of file diff --git a/DNN Platform/Modules/HTML/MyWorkOld.ascx.cs b/DNN Platform/Modules/HTML/MyWorkOld.ascx.cs deleted file mode 100644 index ff3599019fc..00000000000 --- a/DNN Platform/Modules/HTML/MyWorkOld.ascx.cs +++ /dev/null @@ -1,59 +0,0 @@ -// 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.Modules.Html -{ - using System; - using System.Web.UI; - - using DotNetNuke.Abstractions; - using DotNetNuke.Common; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Actions; - using DotNetNuke.Security; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.MvcPipeline.ModuleControl; - using Microsoft.Extensions.DependencyInjection; - - /// MyWork allows a user to view any outstanding workflow items. - public partial class MyWorkOld : PortalModuleBase - { - private readonly INavigationManager navigationManager; - - /// Initializes a new instance of the class. - public MyWorkOld() - { - this.navigationManager = this.DependencyProvider.GetRequiredService(); - } - - public string FormatURL(object dataItem) - { - var objHtmlTextUser = (HtmlTextUserInfo)dataItem; - return "" + objHtmlTextUser.ModuleTitle + " ( " + objHtmlTextUser.StateName + " )"; - } - - /// Page_Load runs when the control is loaded. - /// The event arguments. - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - this.hlCancel.NavigateUrl = this.navigationManager.NavigateURL(); - - try - { - if (!this.Page.IsPostBack) - { - var objHtmlTextUsers = new HtmlTextUserController(); - this.dgTabs.DataSource = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID); - this.dgTabs.DataBind(); - } - } - catch (Exception exc) - { - Exceptions.ProcessModuleLoadException(this, exc); - } - } - } -} diff --git a/DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs b/DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs deleted file mode 100644 index e3c4b5f0b52..00000000000 --- a/DNN Platform/Modules/HTML/MyWorkOld.ascx.designer.cs +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Ce code a été généré par un outil. -// -// Les changements apportés à ce fichier peuvent provoquer un comportement incorrect et seront perdues si -// le code est régénéré. -// -//------------------------------------------------------------------------------ - -namespace DotNetNuke.Modules.Html -{ - - - public partial class MyWorkOld - { - - /// - /// Contrôle customJS. - /// - /// - /// Champ généré automatiquement. - /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. - /// - protected global::DotNetNuke.Web.Client.ClientResourceManagement.DnnCssInclude customJS; - - /// - /// Contrôle dgTabs. - /// - /// - /// Champ généré automatiquement. - /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. - /// - protected global::DotNetNuke.Web.UI.WebControls.Internal.DnnGrid dgTabs; - - /// - /// Contrôle hlCancel. - /// - /// - /// Champ généré automatiquement. - /// Pour modifier, déplacez la déclaration de champ du fichier de concepteur dans le fichier code-behind. - /// - protected global::System.Web.UI.WebControls.HyperLink hlCancel; - } -} From d6354b6fa8a0d0311fb26c420678659e4d4aba5b Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 22:34:20 +0200 Subject: [PATCH 09/34] fix empty pane rendering --- .../ModelFactories/PaneModelFactory.cs | 3 ++- .../DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Pane.cs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs index 7d233e9e708..da8acc18fb7 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModelFactories/PaneModelFactory.cs @@ -112,6 +112,7 @@ public PaneModel ProcessPane(PaneModel pane) this.PaneControl.Controls.AddAt(0, ctlLabel); */ } + /* else { if (this.CanCollapsePane(pane)) @@ -126,7 +127,7 @@ public PaneModel ProcessPane(PaneModel pane) } } - + */ return pane; } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Pane.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Pane.cs index 3b196662a62..b3f6155029f 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Pane.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.Pane.cs @@ -88,9 +88,11 @@ public static IHtmlString Pane(this HtmlHelper htmlHelper, string id, paneDiv.AddCssClass("EditBarEmptyPane"); } } - + if (model.IsEditMode) { + // Add support for drag and drop + paneDiv.AddCssClass(" dnnSortable"); editDiv.InnerHtml += paneDiv.ToString(); return MvcHtmlString.Create(editDiv.ToString()); } From 0edffda809100ce017d364c5cef8e892aeec60bb Mon Sep 17 00:00:00 2001 From: Sacha Date: Thu, 11 Sep 2025 22:34:52 +0200 Subject: [PATCH 10/34] fix user skin object --- .../Skins/SkinHelpers.User.cs | 64 +++++++++++++------ 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.User.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.User.cs index 97fc67b1e13..87802350afa 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.User.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Skins/SkinHelpers.User.cs @@ -51,32 +51,56 @@ public static IHtmlString User(this HtmlHelper helper, string cssClas if (legacyMode) { - if (portalSettings.UserRegistration == (int)Globals.PortalRegistrationType.NoRegistration || - (portalSettings.Users > portalSettings.UserQuota && portalSettings.UserQuota != 0)) - { - return MvcHtmlString.Empty; - } - var registerLink = new TagBuilder("a"); - registerLink.AddCssClass("dnnRegisterLink"); - if (!string.IsNullOrEmpty(cssClass)) + if (helper.ViewContext.HttpContext.Request.IsAuthenticated == false) { - registerLink.AddCssClass(cssClass); - } + if (portalSettings.UserRegistration == (int)Globals.PortalRegistrationType.NoRegistration || + (portalSettings.Users > portalSettings.UserQuota && portalSettings.UserQuota != 0)) + { + return MvcHtmlString.Empty; + } - registerLink.Attributes.Add("rel", "nofollow"); - registerLink.InnerHtml = registerText; - registerLink.Attributes.Add("href", !string.IsNullOrEmpty(url) ? url : Globals.RegisterURL(HttpUtility.UrlEncode(navigationManager.NavigateURL()), Null.NullString)); + var registerLink = new TagBuilder("a"); + registerLink.AddCssClass("dnnRegisterLink"); + if (!string.IsNullOrEmpty(cssClass)) + { + registerLink.AddCssClass(cssClass); + } - string registerScript = string.Empty; - if (portalSettings.EnablePopUps && portalSettings.RegisterTabId == Null.NullInteger && !AuthenticationController.HasSocialAuthenticationEnabled(null)) + registerLink.Attributes.Add("rel", "nofollow"); + registerLink.InnerHtml = registerText; + registerLink.Attributes.Add("href", !string.IsNullOrEmpty(url) ? url : Globals.RegisterURL(HttpUtility.UrlEncode(navigationManager.NavigateURL()), Null.NullString)); + + string registerScript = string.Empty; + if (portalSettings.EnablePopUps && portalSettings.RegisterTabId == Null.NullInteger && !AuthenticationController.HasSocialAuthenticationEnabled(null)) + { + // var clickEvent = "return " + UrlUtils.PopUpUrl(registerLink.Attributes["href"], portalSettings, true, false, 600, 950); + // registerLink.Attributes.Add("onclick", clickEvent); + registerScript = GetRegisterScript(registerLink.Attributes["href"], nonce); + } + return new MvcHtmlString(registerLink.ToString() + registerScript); + } + else { - // var clickEvent = "return " + UrlUtils.PopUpUrl(registerLink.Attributes["href"], portalSettings, true, false, 600, 950); - // registerLink.Attributes.Add("onclick", clickEvent); - registerScript = GetRegisterScript(registerLink.Attributes["href"], nonce); + var userInfo = UserController.Instance.GetCurrentUserInfo(); + if (userInfo.UserID != -1) + { + var userDisplayText = userInfo.DisplayName; + var userDisplayTextUrl = Globals.UserProfileURL(userInfo.UserID); + var userDisplayTextToolTip = Localization.GetString("VisitMyProfile", userResourceFile); + var userLink = new TagBuilder("a"); + userLink.AddCssClass("dnnUserLink"); + if (!string.IsNullOrEmpty(cssClass)) + { + userLink.AddCssClass(cssClass); + } + userLink.Attributes.Add("href", userDisplayTextUrl); + userLink.Attributes.Add("title", userDisplayTextToolTip); + userLink.InnerHtml = userDisplayText; + return new MvcHtmlString(userLink.ToString()); + } + return MvcHtmlString.Empty; } - - return new MvcHtmlString(registerLink.ToString() + registerScript); } else { From 54a68f86bbe8e0611cb9166440c73218543795f6 Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 12 Sep 2025 10:34:09 +0200 Subject: [PATCH 11/34] cleanup --- .../DefaultMvcModuleControlBase.cs | 15 --- .../MvcModuleControlExtensions.cs | 58 +---------- .../Razor/RazorModuleViewContext.cs | 14 +++ .../ModuleControl/RazorModuleControlBase.cs | 41 +++++++- .../ModuleControl/SpaModuleControl.cs | 13 +-- .../ModuleControl/Test/TestModule.cs | 9 +- .../ModuleControl/Test/TestModuleControl.cs | 32 ++++--- .../{ => Utils}/MvcModuleControlRenderer.cs | 5 +- .../Utils/ViewRenderer.cs | 95 +++++++++++++++++++ .../Controls/PrivacyControl.cs | 5 +- .../Controls/TermsControl.cs | 6 +- .../Website/admin/Portal/Views/Pricacy.cshtml | 5 + .../Website/admin/Portal/Views/Terms.cshtml | 5 + .../Website/admin/Portal/Views/web.config | 33 +++++++ 14 files changed, 234 insertions(+), 102 deletions(-) create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/RazorModuleViewContext.cs rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{ => Utils}/MvcModuleControlRenderer.cs (86%) create mode 100644 DNN Platform/Website/admin/Portal/Views/Pricacy.cshtml create mode 100644 DNN Platform/Website/admin/Portal/Views/Terms.cshtml create mode 100644 DNN Platform/Website/admin/Portal/Views/web.config diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs index 76ebf72a353..9d3c6d81046 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs @@ -283,21 +283,6 @@ public void Dispose() } } - /// - /// Helper method that can be used to add an ActionEventHandler to the Skin for this - /// Module Control. - /// - protected void AddActionHandler(ActionEventHandler e) - { - /* - UI.Skins.Skin parentSkin = UI.Skins.Skin.GetParentSkin(this); - if (parentSkin != null) - { - parentSkin.RegisterModuleActionEvent(this.ModuleId, e); - } - */ - } - protected string LocalizeString(string key) { return Localization.GetString(key, this.LocalResourceFile); diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs index 8bd801acf78..11c65d32e9d 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlExtensions.cs @@ -19,63 +19,7 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl ///
public static class MvcModuleControlExtensions { - /* - /// - /// Registers a JavaScript file for the module control. - /// - /// The module control instance. - /// The path to the JavaScript file. - /// The priority for loading the script. - public static void RegisterScript(this IMvcModuleControl moduleControl, string filePath, FileOrder.Js priority = FileOrder.Js.DefaultPriority) - { - if (moduleControl == null) - { - throw new ArgumentNullException(nameof(moduleControl)); - } - - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentException("File path cannot be null or empty.", nameof(filePath)); - } - - if (moduleControl.ViewContext != null) - { - MvcClientResourceManager.RegisterScript(moduleControl.ViewContext.Controller.ControllerContext, filePath, priority); - } - else if (moduleControl.Control != null) - { - ClientResourceManager.RegisterScript(moduleControl.Control.Page, filePath, priority); - } - } - - /// - /// Registers a CSS stylesheet for the module control. - /// - /// The module control instance. - /// The path to the CSS file. - /// The priority for loading the stylesheet. - public static void RegisterStyleSheet(this IMvcModuleControl moduleControl, string filePath, FileOrder.Css priority = FileOrder.Css.DefaultPriority) - { - if (moduleControl == null) - { - throw new ArgumentNullException(nameof(moduleControl)); - } - - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentException("File path cannot be null or empty.", nameof(filePath)); - } - - if (moduleControl.ViewContext != null) - { - MvcClientResourceManager.RegisterStyleSheet(moduleControl.ViewContext.Controller.ControllerContext, filePath, priority); - } - else if (moduleControl.Control != null) - { - ClientResourceManager.RegisterStyleSheet(moduleControl.Control.Page, filePath, priority); - } - } - */ + /// /// Gets a localized string for the module control. /// diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/RazorModuleViewContext.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/RazorModuleViewContext.cs new file mode 100644 index 00000000000..2cc76cf542d --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Razor/RazorModuleViewContext.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; + +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Razor +{ + public class RazorModuleViewContext + { + public HttpContextBase HttpContext { get; internal set; } + } +} diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs index b43b52f3334..ad21f2ff400 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/RazorModuleControlBase.cs @@ -1,19 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; +using System.Security.Principal; using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using System.Web.Mvc.Html; +using System.Web.Routing; using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; namespace DotNetNuke.Web.MvcPipeline.ModuleControl { public abstract class RazorModuleControlBase : DefaultMvcModuleControlBase { + private RazorModuleViewContext _viewContext; public override IHtmlString Html(HtmlHelper htmlHelper) { + this.ViewContext.HttpContext = htmlHelper.ViewContext.HttpContext; var res = this.Invoke(); return res.Execute(htmlHelper); } @@ -22,7 +27,7 @@ protected virtual string DefaultViewName { get { - return "~/" + this.ControlPath.Replace('\\', '/') + "/Views/" + this.ControlName + ".cshtml"; + return "~/" + this.ControlPath.Replace('\\', '/').Trim('/') + "/Views/" + this.ControlName + ".cshtml"; } } @@ -50,5 +55,39 @@ public IRazorModuleResult View(string viewName, object model) } return new ViewRazorModuleResult(viewName, model); } + + public RazorModuleViewContext ViewContext + { + get + { + // This should run only for the ViewComponent unit test scenarios. + if (_viewContext == null) + { + _viewContext = new RazorModuleViewContext(); + } + + return _viewContext; + } + set + { + if (value == null) + { + throw new ArgumentNullException(); + } + + _viewContext = value; + } + } + + /// + /// Gets the . + /// + public HttpContextBase HttpContext => ViewContext.HttpContext; + + /// + /// Gets the . + /// + public HttpRequestBase Request => ViewContext.HttpContext.Request; + } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs index 47b2b134bdd..c862c837341 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/SpaModuleControl.cs @@ -49,13 +49,7 @@ public SpaModuleControl(IBusinessControllerProvider businessControllerProvider) this.businessControllerProvider = businessControllerProvider; } - public string html5File - { - get - { - return ModuleConfiguration.ModuleControl.ControlSrc; - } - } + public string html5File => ModuleConfiguration.ModuleControl.ControlSrc; public ModuleResources ModuleResources { @@ -63,6 +57,7 @@ public ModuleResources ModuleResources { var resource = new ModuleResources() { + // Register for Services Framework AjaxScript = true }; @@ -106,9 +101,7 @@ public override IHtmlString Html(HtmlHelper htmlHelper) var tokenReplace = new MvcHtml5ModuleTokenReplace(htmlHelper.ViewContext, this.businessControllerProvider, this.html5File, this.ModuleContext, ModuleActions); fileContent = tokenReplace.ReplaceEnvironmentTokens(fileContent); } - - // Register for Services Framework - //ServicesFramework.Instance.RequestAjaxScriptSupport(); + return new HtmlString(HttpUtility.HtmlDecode(fileContent)); } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs index fd6924285d5..f5f95e9440b 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc.Html; using System.Web.UI; using System.Web.UI.WebControls; using DotNetNuke.Entities.Modules; @@ -35,16 +37,19 @@ protected override void OnInit(EventArgs e) { base.OnInit(e); var mc = MvcUtils.CreateModuleControl(this.ModuleConfiguration); + html = ViewRenderer.RenderHtmlHelperToString(helper => mc.Html(helper)); + /* if (mc is RazorModuleControlBase) { var moduleControl = (RazorModuleControlBase)mc; - moduleControl.Control = this; + // moduleControl.Control = this; // moduleControl.ModuleContext = this.ModuleContext; + moduleControl.ViewContext.HttpContext = new HttpContextWrapper(this.Context); var res = moduleControl.Invoke(); - var renderer = new ViewRenderer(); html = renderer.RenderViewToString(res.ViewName, res.Model); } + */ if (mc is IActionable){ var moduleControl = (IActionable)mc; this.ModuleActions = moduleControl.ModuleActions; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs index 9d6c955c80f..e3ba8abfafb 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs @@ -10,28 +10,34 @@ namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Test { public class TestModuleControl : RazorModuleControlBase { - public override string ControlName + public override string ControlName => "TestModuleControl"; + + public override string ControlPath => "DesktopModules/mvcpl/mvcpl1"; + + public override IRazorModuleResult Invoke() { - get + if (Request.QueryString["view"] == "Terms") { - return "TestModuleControl"; + return Terms(); + } + else if (Request.QueryString["view"] == "Privacy") + { + return Privacy(); + } + else + { + return View("~/admin/Portal/Views/Terms.cshtml", "Hello from TestModuleControl - Default view"); } } - /// Gets or Sets the Path for this control (used primarily for UserControls). - /// A String. - public override string ControlPath + private IRazorModuleResult Privacy() { - get - { - - return "DesktopModules/mvcpl/mvcpl1"; - } + return View("~/admin/Portal/Views/Privacy.cshtml", "Hello from TestModuleControl - Privacy view"); } - public override IRazorModuleResult Invoke() + private IRazorModuleResult Terms() { - return View("~/Views/Default/Terms.cshtml", "Hello from TestModuleControl"); + return View("~/Views/Default/Terms.cshtml", "Hello from TestModuleControl - Terms view"); } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Utils/MvcModuleControlRenderer.cs similarity index 86% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Utils/MvcModuleControlRenderer.cs index e0dc656e3b6..4031abdf90c 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/MvcModuleControlRenderer.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Utils/MvcModuleControlRenderer.cs @@ -13,7 +13,7 @@ using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using DotNetNuke.Web.MvcPipeline.Utils; -namespace DotNetNuke.Web.MvcPipeline.ModuleControl +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Utils { public class MvcModuleControlRenderer where T : RazorModuleControlBase, new() { @@ -23,7 +23,8 @@ public MvcModuleControlRenderer(Control control, ModuleInstanceContext moduleCon { this.moduleControl = new T(); moduleControl.ModuleContext.Configuration = moduleContext.Configuration; - moduleControl.Control = control; + moduleControl.ViewContext.HttpContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current); + //moduleControl.Control = control; } // Fix for CS0149: Replace the invalid constructor chaining syntax with a proper constructor call diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs index 5d3937ac4c2..9506b1ad510 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Utils/ViewRenderer.cs @@ -242,6 +242,46 @@ public static void RenderPartialView(string viewPath, TextWriter writer, object renderer.RenderPartialView(viewPath, model, writer); } + /// + /// Renders an HtmlHelper delegate to a string. This method creates a temporary view context + /// and captures the output of the HtmlHelper function. + /// + /// A function that takes an HtmlHelper and returns MvcHtmlString or IHtmlString + /// The model to attach to the view data + /// Active controller context (optional) + /// String representation of the rendered HTML helper output + public static string RenderHtmlHelperToString(Func htmlHelperFunc, object model = null, ControllerContext controllerContext = null) + { + if (htmlHelperFunc == null) + throw new ArgumentNullException(nameof(htmlHelperFunc)); + + ViewRenderer renderer = new ViewRenderer(controllerContext); + return renderer.RenderHtmlHelperToStringInternal(htmlHelperFunc, model); + } + + /// + /// Renders an HtmlHelper delegate to a string with error handling. This method creates a temporary view context + /// and captures the output of the HtmlHelper function. + /// + /// A function that takes an HtmlHelper and returns MvcHtmlString or IHtmlString + /// The model to attach to the view data + /// Active controller context (optional) + /// Output parameter that captures any error message instead of throwing + /// String representation of the rendered HTML helper output or null on error + public static string RenderHtmlHelperToString(Func htmlHelperFunc, object model, ControllerContext controllerContext, out string errorMessage) + { + errorMessage = null; + try + { + return RenderHtmlHelperToString(htmlHelperFunc, model, controllerContext); + } + catch (Exception ex) + { + errorMessage = ex.GetBaseException().Message; + return null; + } + } + /// /// Internal method that handles rendering of either partial or @@ -320,6 +360,37 @@ private string RenderViewToStringInternal(string viewPath, object model, return result; } + /// + /// Internal method that handles rendering of HtmlHelper delegate to a string. + /// + /// A function that takes an HtmlHelper and returns MvcHtmlString or IHtmlString + /// Model to attach to the view data + /// String representation of the rendered HTML helper output + private string RenderHtmlHelperToStringInternal(Func htmlHelperFunc, object model = null) + { + // Set the model to view data + Context.Controller.ViewData.Model = model; + + string result = null; + + using (var sw = new StringWriter()) + { + // Create a view data dictionary for the HtmlHelper + var viewDataContainer = new ViewDataContainer(Context.Controller.ViewData); + + // Create the HtmlHelper with the proper context + var htmlHelper = new HtmlHelper( + new ViewContext(Context, new FakeView(), Context.Controller.ViewData, Context.Controller.TempData, sw), + viewDataContainer); + + // Execute the HtmlHelper function and capture the result + var htmlResult = htmlHelperFunc(htmlHelper); + result = htmlResult?.ToString() ?? string.Empty; + } + + return result; + } + /// /// Creates an instance of an MVC controller from scratch @@ -365,4 +436,28 @@ public static T CreateController(RouteData routeData = null, params object[] public class EmptyController : Controller { } + + /// + /// Simple ViewDataContainer implementation for HtmlHelper usage + /// + internal class ViewDataContainer : IViewDataContainer + { + public ViewDataDictionary ViewData { get; set; } + + public ViewDataContainer(ViewDataDictionary viewData) + { + ViewData = viewData; + } + } + + /// + /// Fake view implementation for HtmlHelper contexts that don't require actual view rendering + /// + internal class FakeView : IView + { + public void Render(ViewContext viewContext, TextWriter writer) + { + // No-op implementation since we're only using this for HtmlHelper context + } + } } diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs index f7afc579777..9ee24586ee0 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/PrivacyControl.cs @@ -11,9 +11,12 @@ namespace DotNetNuke.Web.MvcWebsite.Controls public class PrivacyControl : RazorModuleControlBase { + public override string ControlName => "Privacy"; + + public override string ControlPath => "admin/Portal"; public override IRazorModuleResult Invoke() { - return View("Privacy", Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_PRIVACY")); + return View(Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_PRIVACY")); } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs index 358ea650ad4..fffb7e258f6 100644 --- a/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcWebsite/Controls/TermsControl.cs @@ -12,9 +12,13 @@ namespace DotNetNuke.Web.MvcWebsite.Controls public class TermsControl : RazorModuleControlBase { + public override string ControlName => "Terms"; + + public override string ControlPath => "admin/Portal"; + public override IRazorModuleResult Invoke() { - return View("Terms", Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_TERMS")); + return View(Localization.GetSystemMessage(PortalSettings.Current, "MESSAGE_PORTAL_TERMS")); } } diff --git a/DNN Platform/Website/admin/Portal/Views/Pricacy.cshtml b/DNN Platform/Website/admin/Portal/Views/Pricacy.cshtml new file mode 100644 index 00000000000..ed9bfb3556d --- /dev/null +++ b/DNN Platform/Website/admin/Portal/Views/Pricacy.cshtml @@ -0,0 +1,5 @@ +@model string + +
+ @Html.Raw(Model) +
\ No newline at end of file diff --git a/DNN Platform/Website/admin/Portal/Views/Terms.cshtml b/DNN Platform/Website/admin/Portal/Views/Terms.cshtml new file mode 100644 index 00000000000..7aeb1009b11 --- /dev/null +++ b/DNN Platform/Website/admin/Portal/Views/Terms.cshtml @@ -0,0 +1,5 @@ +@model string +@{ + +} +
@Html.Raw(Model)
diff --git a/DNN Platform/Website/admin/Portal/Views/web.config b/DNN Platform/Website/admin/Portal/Views/web.config new file mode 100644 index 00000000000..b9c29a8fc27 --- /dev/null +++ b/DNN Platform/Website/admin/Portal/Views/web.config @@ -0,0 +1,33 @@ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + From 1497a8be33e0ab94e83de2ae518ab8863fe4a5d7 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 14 Sep 2025 21:45:47 +0200 Subject: [PATCH 12/34] rename test to demo add readme --- .../TestModule.cs => Demo/DemoModule.cs} | 4 +- .../DemoModuleControl.cs} | 8 +- .../ModuleControl/README.md | 269 ++++++++++++++++++ .../Website/Views/Default/Pricacy.cshtml | 5 - .../Website/Views/Default/Terms.cshtml | 5 - 5 files changed, 275 insertions(+), 16 deletions(-) rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{Test/TestModule.cs => Demo/DemoModule.cs} (95%) rename DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/{Test/TestModuleControl.cs => Demo/DemoModuleControl.cs} (84%) create mode 100644 DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md delete mode 100644 DNN Platform/Website/Views/Default/Pricacy.cshtml delete mode 100644 DNN Platform/Website/Views/Default/Terms.cshtml diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Demo/DemoModule.cs similarity index 95% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Demo/DemoModule.cs index f5f95e9440b..b30369d93a2 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModule.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Demo/DemoModule.cs @@ -14,9 +14,9 @@ using DotNetNuke.Web.MvcPipeline.UI.Utilities; using DotNetNuke.Web.MvcPipeline.Utils; -namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Test { +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Demo { - public class TestModule : PortalModuleBase, IActionable + public class DemoModule : PortalModuleBase, IActionable { private string html = string.Empty; diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Demo/DemoModuleControl.cs similarity index 84% rename from DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs rename to DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Demo/DemoModuleControl.cs index e3ba8abfafb..d9c72beddb1 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Test/TestModuleControl.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/Demo/DemoModuleControl.cs @@ -6,13 +6,13 @@ using System.Threading.Tasks; using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; -namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Test +namespace DotNetNuke.Web.MvcPipeline.ModuleControl.Demo { - public class TestModuleControl : RazorModuleControlBase + public class DemoModuleControl : RazorModuleControlBase { - public override string ControlName => "TestModuleControl"; + public override string ControlName => "DemoModuleControl"; - public override string ControlPath => "DesktopModules/mvcpl/mvcpl1"; + public override string ControlPath => "DesktopModules/mvcpl/demo"; public override IRazorModuleResult Invoke() { diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md new file mode 100644 index 00000000000..395736fd40e --- /dev/null +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md @@ -0,0 +1,269 @@ +# MVC Module Control Implementation + +## Overview + +The MVC Module Control implementation provides a modern alternative to DNN's traditional WebForms-based module rendering pipeline. This new system enables DNN modules to leverage ASP.NET MVC architecture while maintaining compatibility with the existing DNN framework. + +## Problem Statement + +DNN Platform has historically relied on the WebForms pipeline accessed through `/default.aspx`. As outlined in [GitHub issue #6679](https://github.com/dnnsoftware/Dnn.Platform/issues/6679). + +## Solution: Hybrid Pipeline Architecture + +The MVC Pipeline introduces a dual-rendering mechanism: + +1. **Legacy Pipeline**: Traditional WebForms through `/default.aspx` +2. **New MVC Pipeline**: Modern MVC rendering through `/DesktopModules/Default/Page/{tabId}/{locale}` + +### Module Pipeline Support Matrix + +Based on the GitHub issue specifications, modules can support different pipeline patterns: + +| WebForms Support | MVC Module Support | SPA Module Support | +|------------------|--------------------|--------------------| +| Custom Control + Razor view | Use generic Control + Custom MVC Controller as child controller (shared with WebForms pipeline) | Use generic Control + return directly the html (shared with WebForms pipeline) | | +| Render Razor Partial | The generic control redirects to the controller defined in Control Src |The generic Control renders the html file defined in Control Src | | + +### Module Control Class Configuration + +Modules specify their MVC compatibility through: +- **MVC Control Class**: Defined in module control settings and module manifest +- **Interface Implementation**: Must implement `IMvcModuleControl` +- **Optional Interfaces**: Can implement `IActionable` for unified action handling +- **Pipeline Detection**: System can determine module compatibility and show appropriate messages + +## Core Components + +### 1. IMvcModuleControl Interface + +```csharp +public interface IMvcModuleControl : IModuleControl +{ + IHtmlString Html(HtmlHelper htmlHelper); +} +``` + +The base interface that all MVC module controls must implement, extending the standard `IModuleControl` with MVC-specific rendering capabilities. This interface enables: + +- **Pipeline Compatibility Detection**: The system can determine if a module supports the MVC pipeline +- **Unified Rendering**: The `Html()` method provides access to `HtmlHelper` with information about HttpContext, controller, and page model +- **Flexible Rendering Options**: Modules can use HTML helpers to render content (Razor partials, child action controllers, or other helpers) + +### 2. DefaultMvcModuleControlBase + +The abstract base class that provides common functionality for all MVC module controls: + +- **Dependency Injection**: Integrated service provider access +- **Module Context**: Access to DNN module configuration and settings +- **Portal Context**: Portal settings, user information, and localization +- **Resource Management**: Localization helpers and resource file management +- **URL Generation**: Helper methods for creating edit URLs + +**Key Features:** +- Service scoped dependency injection +- Automatic resource file path resolution +- Portal and user context access +- Module settings management +- Edit URL generation with MVC support + +### 3. Module Control Implementations + +#### MvcModuleControl +The standard MVC module control for traditional MVC controllers and actions. + +**Features:** +- Parses `.mvc` control source to extract controller and action names +- Supports routing with namespaces: `{namespace}/{controller}/{action}` +- Automatic query string parameter mapping +- Route value dictionary construction for MVC action execution +- Localization resource file resolution + +**Control Source Format:** +``` +{namespace}/{controller}/{action}.mvc +``` + +#### SpaModuleControl +Specialized control for Single Page Applications. + +**Features:** +- HTML5 file rendering with token replacement +- Automatic CSS and JavaScript file inclusion +- File existence caching for performance +- Support for HTML5 module token system +- Content caching with file dependency tracking + +**Supported Files:** +- `.html` or custom HTML5 files +- Automatic `.css` file inclusion (same name) +- Automatic `.js` file inclusion (same name) + +#### RazorModuleControlBase +Abstract base for modules using Razor view rendering. +This use MVC 5 razor views. +Recomended for Weforms control migrations +Folows the ViewComponent patern of .net Core for easy future trasition to .net Core + +**Features:** +- Direct Razor view rendering +- Model binding support +- Custom view context management +- Flexible view name resolution +- Request/Response context integration + +**Usage Pattern:** +```csharp +public class MyModuleControl : RazorModuleControlBase +{ + public override IRazorModuleResult Invoke() + { + var model = GetMyModel(); + return View("MyView", model); + } +} +``` + +### 4. Extension Methods (MvcModuleControlExtensions) + +Provides convenient extension methods for all MVC module controls: + +- **Localization**: `LocalizeString()`, `LocalizeSafeJsString()` +- **URL Generation**: `EditUrl()` with various overloads +- **Settings Access**: `GetModuleSetting()` with type conversion +- **State Checking**: `EditMode()`, `IsEditable()` + +### 5. Resource Management + +#### IResourcable Interface +Modules can implement this interface to automatically manage CSS and JavaScript resources. + +#### ModuleResources System +- Automatic resource registration +- Priority-based loading +- File existence validation +- Caching for performance +- Independent of the pipeline + +### 6. Utilities + +#### MvcModuleControlRenderer +Provides rendering capabilities for Razor-based module controls outside of the normal MVC pipeline. + +#### ViewRenderer +A powerful utility class for rendering MVC views to strings outside of the standard MVC request pipeline. This class is essential for the MVC module control system as it enables view rendering in non-controller contexts. + +**Core Methods:** +```csharp +// Render full view with layout +string html = ViewRenderer.RenderView("~/Views/MyView.cshtml", model); + +// Render partial view without layout +string partial = ViewRenderer.RenderPartialView("~/Views/_MyPartial.cshtml", model); + +// Render HtmlHelper delegates +string html = ViewRenderer.RenderHtmlHelperToString(helper => + helper.Action("MyAction", "MyController"), model); +``` + +## Demo Implementation + +The Demo folder includes demonstration classes that show practical implementation examples: + +### DemoModule.cs +A WebForms-compatible module that bridges to the MVC pipeline, demonstrating how to integrate MVC module controls within the traditional DNN WebForms infrastructure. + +**Key Features:** +- **Hybrid Bridge Pattern**: Inherits from `PortalModuleBase` to maintain WebForms compatibility +- **MVC Integration**: Uses `MvcUtils.CreateModuleControl()` to instantiate MVC module controls +- **ViewRenderer Integration**: Demonstrates `ViewRenderer.RenderHtmlHelperToString()` usage +- **Interface Support**: Handles `IActionable` and `IResourcable` interfaces automatically +- **Lifecycle Management**: Proper ASP.NET control lifecycle implementation + +**Implementation Pattern:** +```csharp +public class DemoModule : PortalModuleBase, IActionable +{ + protected override void OnInit(EventArgs e) + { + // Create MVC module control + var mc = MvcUtils.CreateModuleControl(this.ModuleConfiguration); + + // Render using ViewRenderer + html = ViewRenderer.RenderHtmlHelperToString(helper => mc.Html(helper)); + + // Handle optional interfaces + if (mc is IActionable actionable) + this.ModuleActions = actionable.ModuleActions; + + if (mc is IResourcable resourcable) + resourcable.RegisterResources(this.Page); + } +} +``` + +### DemoModuleControl.cs +A concrete implementation of `RazorModuleControlBase` showing how to create custom MVC module controls with dynamic view selection. + +**Key Features:** +- **Dynamic View Routing**: Uses query string parameters to determine which view to render +- **Multiple View Support**: Demonstrates rendering different views based on user input +- **Custom View Paths**: Shows how to specify custom view file locations +- **Model Passing**: Illustrates passing data models to views + +**Implementation Example:** +```csharp +public class DemoModuleControl : RazorModuleControlBase +{ + public override IRazorModuleResult Invoke() + { + // Dynamic view selection based on query parameters + switch (Request.QueryString["view"]) + { + case "Terms": + return View("~/Views/Default/Terms.cshtml", "Terms content"); + case "Privacy": + return View("~/admin/Portal/Views/Privacy.cshtml", "Privacy content"); + default: + return View("~/admin/Portal/Views/Terms.cshtml", "Default content"); + } + } +} +``` + +**Usage Scenarios:** +- **Migration Testing**: Use DemoModule to test MVC controls within WebForms pages +- **Development Reference**: DemoModuleControl shows best practices for Razor module implementation +- **Integration Patterns**: Demonstrates how to handle multiple interfaces (`IActionable`, `IResourcable`) +- **View Management**: Shows flexible view path configuration and model binding + +**Bridge Pattern Benefits:** +The DemoModule demonstrates the bridge pattern that allows: +- Gradual migration from WebForms to MVC +- Using MVC controls within existing WebForms infrastructure +- Maintaining compatibility with existing DNN module architecture +- Automatic handling of module actions and resource registration + +## Key Benefits + +This implementation provides several key advantages: + +### 1. Modern Development Experience +- MVC pattern for better separation of concerns +- Dependency injection support +- Testable architecture +- Familiar development patterns for modern .NET developers + +### 2. Gradual Migration Path +- Hybrid architecture allows coexistence of WebForms and MVC +- Module-by-module migration strategy +- Backward compatibility maintained + +### 3. Pipeline Transparency & Compatibility +- **Unified Interface Implementation**: MVC modules can implement `IActionable` in a unified way +- **No Legacy Modifications**: No modifications required to the existing module pipeline +- **Custom Module Patterns**: Open to custom module control patterns + +### 4. Future-Proof Architecture +- **Configuration-Based**: Uses class config in module manifest rather than simple boolean flags +- **.NET Core Preparation**: Architecture aligns with .NET Core patterns where there's no separate module pipeline +- **Extensible Design**: Open to custom module control patterns and future enhancements diff --git a/DNN Platform/Website/Views/Default/Pricacy.cshtml b/DNN Platform/Website/Views/Default/Pricacy.cshtml deleted file mode 100644 index ed9bfb3556d..00000000000 --- a/DNN Platform/Website/Views/Default/Pricacy.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@model string - -
- @Html.Raw(Model) -
\ No newline at end of file diff --git a/DNN Platform/Website/Views/Default/Terms.cshtml b/DNN Platform/Website/Views/Default/Terms.cshtml deleted file mode 100644 index 7aeb1009b11..00000000000 --- a/DNN Platform/Website/Views/Default/Terms.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@model string -@{ - -} -
@Html.Raw(Model)
From d3830abb9c3ca75de25d667e8fccd9480b09cbb6 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 14 Sep 2025 22:36:58 +0200 Subject: [PATCH 13/34] performance optimization for menu --- .../Modules/NewDDRMenu/MvcMenuBase.cs | 2 +- .../Modules/NewDDRMenu/SkinHelpers.cs | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/DNN Platform/Modules/NewDDRMenu/MvcMenuBase.cs b/DNN Platform/Modules/NewDDRMenu/MvcMenuBase.cs index 65b0406028a..4ad8f400d00 100644 --- a/DNN Platform/Modules/NewDDRMenu/MvcMenuBase.cs +++ b/DNN Platform/Modules/NewDDRMenu/MvcMenuBase.cs @@ -126,7 +126,7 @@ internal virtual void PreRender() { #pragma warning disable CS0618 // Type or member is obsolete // TODO: In Dnn v11, replace this to use IPortalSettings private field instantiate in constructor - new Localiser().LocaliseNode(this.RootNode); + new Localiser().LocaliseNode(this.RootNode, this.HostPortalSettings.PortalId); #pragma warning restore CS0618 // Type or member is obsolete } diff --git a/DNN Platform/Modules/NewDDRMenu/SkinHelpers.cs b/DNN Platform/Modules/NewDDRMenu/SkinHelpers.cs index 7fc8970dd5a..3a7d7c1b6bf 100644 --- a/DNN Platform/Modules/NewDDRMenu/SkinHelpers.cs +++ b/DNN Platform/Modules/NewDDRMenu/SkinHelpers.cs @@ -72,15 +72,23 @@ public static IHtmlString DDRMenu( var localiser = new Localiser(); if (string.IsNullOrEmpty(nodeXmlPath)) { + // Use cached nodes if available + DotNetNuke.UI.WebControls.DNNNodeCollection dnnNodes = htmlHelper.ViewContext.HttpContext.Items["DNNMenuNodes"] as DotNetNuke.UI.WebControls.DNNNodeCollection; + if (dnnNodes == null) + { + dnnNodes = localiser.LocaliseDNNNodeCollection( + Navigation.GetNavigationNodes( + clientID, + Navigation.ToolTipSource.None, + -1, + -1, + DNNAbstract.GetNavNodeOptions(true))); + htmlHelper.ViewContext.HttpContext.Items["DNNMenuNodes"] = dnnNodes; + } + menu.RootNode = new DDRMenu.MenuNode( - localiser.LocaliseDNNNodeCollection( - Navigation.GetNavigationNodes( - clientID, - Navigation.ToolTipSource.None, - -1, - -1, - DNNAbstract.GetNavNodeOptions(true)))); + dnnNodes); } menu.PreRender(); From 39d80840d7c3913a0ab9525a44b2448d4f9904de Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 14 Sep 2025 22:38:31 +0200 Subject: [PATCH 14/34] add cursor ai ignore --- .cursorignore | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .cursorignore diff --git a/.cursorignore b/.cursorignore new file mode 100644 index 00000000000..0c5ddee146d --- /dev/null +++ b/.cursorignore @@ -0,0 +1,30 @@ +node_modules/ +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.DS_Store +.idea/ +.vscode/ +.gitignore +.git/ +.gitignore + +.vs/ + +build/ +build.* +.yarn/ +Artifacts/ +DotNetNuke.Internal.SourceGenerators/ +Install/ +tools/ +Website/ +.nuget/ +.github/ +Packages/ +Refs/ +tools/ +Dnn Platform/node_modules/ +Dnn Platform/Tests \ No newline at end of file From 644247fbb8b5da8c2449d44608f6364251d7f6c2 Mon Sep 17 00:00:00 2001 From: Sacha Date: Mon, 15 Sep 2025 14:07:09 +0200 Subject: [PATCH 15/34] fix unit tests --- .../Framework/Controllers/DnnController.cs | 18 +----------------- .../ModuleControl/README.md | 7 ++----- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs b/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs index f145b303e92..8264d66dc72 100644 --- a/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs +++ b/DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs @@ -150,7 +150,7 @@ protected override void Initialize(RequestContext requestContext) { base.Initialize(requestContext); - if (requestContext.RouteData.Values.ContainsKey("mvcpage")) + if (requestContext.RouteData != null && requestContext.RouteData.Values.ContainsKey("mvcpage")) { var values = requestContext.RouteData.Values; var moduleContext = new ModuleInstanceContext(); @@ -168,20 +168,6 @@ protected override void Initialize(RequestContext requestContext) moduleContext.Configuration = moduleInfo; - /* - var desktopModule = DesktopModuleControllerAdapter.Instance.GetDesktopModule(moduleInfo.DesktopModuleID, moduleInfo.PortalID); - var moduleRequestContext = new ModuleRequestContext - { - HttpContext = httpContext, - ModuleContext = moduleContext, - ModuleApplication = new ModuleApplication(this.RequestContext, DisableMvcResponseHeader) - { - ModuleName = desktopModule.ModuleName, - FolderPath = desktopModule.FolderName, - }, - }; - */ - this.ModuleContext = new ModuleInstanceContext() { Configuration = moduleInfo }; this.LocalResourceFile = string.Format( "~/DesktopModules/MVC/{0}/{1}/{2}.resx", @@ -196,8 +182,6 @@ protected override void Initialize(RequestContext requestContext) }; moduleApplication.Init(); - // var viewEngines = new ViewEngineCollection(); - // viewEngines.Add(new ModuleDelegatingViewEngine()); this.ViewEngineCollectionEx = moduleApplication.ViewEngines; } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md index 395736fd40e..20d30f86bb0 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md @@ -231,7 +231,7 @@ public class DemoModuleControl : RazorModuleControlBase ``` **Usage Scenarios:** -- **Migration Testing**: Use DemoModule to test MVC controls within WebForms pages +- **Migration**: Use DemoModule to run MVC controls within WebForms pages - **Development Reference**: DemoModuleControl shows best practices for Razor module implementation - **Integration Patterns**: Demonstrates how to handle multiple interfaces (`IActionable`, `IResourcable`) - **View Management**: Shows flexible view path configuration and model binding @@ -263,7 +263,4 @@ This implementation provides several key advantages: - **No Legacy Modifications**: No modifications required to the existing module pipeline - **Custom Module Patterns**: Open to custom module control patterns -### 4. Future-Proof Architecture -- **Configuration-Based**: Uses class config in module manifest rather than simple boolean flags -- **.NET Core Preparation**: Architecture aligns with .NET Core patterns where there's no separate module pipeline -- **Extensible Design**: Open to custom module control patterns and future enhancements + From d3cb123fdac8759f3fd10a54909c46c026b9246a Mon Sep 17 00:00:00 2001 From: Sacha Date: Wed, 17 Sep 2025 14:02:48 +0200 Subject: [PATCH 16/34] add MvcControlClass to UI and db --- .../Models/ContainerModel.cs | 8 - .../DefaultMvcModuleControlBase.cs | 10 +- .../ModuleControl/README.md | 55 +++++ .../UI/Utilities/MvcUtils.cs | 61 +++--- DNN Platform/Library/Data/DataProvider.cs | 6 +- .../Library/Entities/Modules/ControlInfo.cs | 19 +- .../Modules/ModuleControlController.cs | 2 + .../Library/Entities/Modules/ModuleInfo.cs | 5 + .../Installer/Writers/ModulePackageWriter.cs | 2 +- .../Library/Services/Upgrade/Upgrade.cs | 12 +- .../Modules/HTML/Mvc/EditHTMLControl.cs | 155 -------------- .../Modules/HTML/Mvc/HtmlModuleControl.cs | 87 -------- .../Modules/HTML/Mvc/MyWorkControl.cs | 104 --------- .../SqlDataProvider/10.99.00.SqlDataProvider | 141 +++++++++++++ .../Dto/Editors/ModuleControlDto.cs | 11 +- .../Dto/Editors/ModuleDefinitionDto.cs | 116 +++++----- .../Dto/Editors/ModulePackageDetailDto.cs | 198 +++++++++--------- .../App_LocalResources/Extensions.resx | 6 + 18 files changed, 435 insertions(+), 563 deletions(-) delete mode 100644 DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs delete mode 100644 DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs delete mode 100644 DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs create mode 100644 DNN Platform/Website/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/Models/ContainerModel.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/Models/ContainerModel.cs index 4cca7dda7f4..108914a4dc5 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/Models/ContainerModel.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/Models/ContainerModel.cs @@ -94,14 +94,6 @@ public string ControllerName } } - public string RazorFile - { - get - { - return this.moduleConfiguration.ModuleControl.ControlSrc.Replace(".ascx", string.Empty); - } - } - public string ContainerRazorFile { get diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs index 9d3c6d81046..15fac66e7fa 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/DefaultMvcModuleControlBase.cs @@ -138,8 +138,14 @@ public virtual string ControlPath { get { - - return Path.GetDirectoryName(this.ModuleConfiguration.ModuleControl.ControlSrc); + if (this.ModuleConfiguration.DesktopModule == null) + { + return Path.GetDirectoryName(this.ModuleConfiguration.ModuleControl.ControlSrc); + } + else + { + return this.ModuleConfiguration.DesktopModule.FolderName; + } } } diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md index 20d30f86bb0..4887631261a 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/ModuleControl/README.md @@ -32,6 +32,61 @@ Modules specify their MVC compatibility through: - **Optional Interfaces**: Can implement `IActionable` for unified action handling - **Pipeline Detection**: System can determine module compatibility and show appropriate messages +## Class Diagram + +```mermaid +classDiagram + %% Interfaces + class IMvcModuleControl { + <> + +Html(helper) IHtmlString + } + + class IModuleControl { + <> + + +string ControlPath + +string ControlName + +ModuleInstanceContext ModuleContext + +string LocalResourceFile + } + + + %% Concrete Classes + class MvcModuleControl { + +Html(helper) IHtmlString + } + note for MvcModuleControl "MVC controller" + + class SpaModuleControl { + +Html(helper) IHtmlString + } + note for SpaModuleControl "Html with tokens" + + %% Abstract Classes + + class DefaultMvcModuleControlBase { + +Html(helper) IHtmlString + } + + class RazorModuleControlBase { + + +Invoke() IRazorModuleResult + } + note for RazorModuleControlBase "Razor view from model" + + %% Relationships + IMvcModuleControl ..|> IModuleControl : extends + + DefaultMvcModuleControlBase ..|> IMvcModuleControl : implements + + MvcModuleControl --|> DefaultMvcModuleControlBase : extends + RazorModuleControlBase --|> DefaultMvcModuleControlBase : extends + SpaModuleControl --|> DefaultMvcModuleControlBase : extends + + +``` + ## Core Components ### 1. IMvcModuleControl Interface diff --git a/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs b/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs index 64eb58d3848..cb2a7b8ada8 100644 --- a/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs +++ b/DNN Platform/DotNetNuke.Web.MvcPipeline/UI/Utilities/MvcUtils.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; + using System.Security.AccessControl; using System.Web.UI; using DotNetNuke.Common; using DotNetNuke.Entities.Modules; @@ -43,8 +44,8 @@ public static string GetControlControllerName(string controlSrc) static private IDictionary _moduleClasses = new Dictionary() { { "ModuleActions", "DotNetNuke.Web.MvcWebsite.Controls.ModuleActionsControl, DotNetNuke.Web.MvcWebsite" }, - { "Admin/Portal/Terms.ascx", "DotNetNuke.Web.MvcWebsite.Controls.TermsControl, DotNetNuke.Web.MvcWebsite" }, - { "Admin/Portal/Privacy.ascx", "DotNetNuke.Web.MvcWebsite.Controls.PrivacyControl, DotNetNuke.Web.MvcWebsite" } + // { "Admin/Portal/Terms.ascx", "DotNetNuke.Web.MvcWebsite.Controls.TermsControl, DotNetNuke.Web.MvcWebsite" }, + // { "Admin/Portal/Privacy.ascx", "DotNetNuke.Web.MvcWebsite.Controls.PrivacyControl, DotNetNuke.Web.MvcWebsite" } }; public static IMvcModuleControl CreateModuleControl(ModuleInfo module) @@ -70,12 +71,31 @@ public static IMvcModuleControl GetModuleControl(ModuleInfo module, string contr } else { - if (module.DesktopModule == null) + //if (module.DesktopModule == null) + //{ + // throw new Exception("No DesktopModule is not defined for the module " + module.ModuleTitle); + //} + if (!string.IsNullOrEmpty(module.ModuleControl.MvcControlClass)) { - throw new Exception("No DesktopModule is not defined for the module " + module.ModuleTitle); + var controlClass = module.ModuleControl.MvcControlClass; + try + { + var obj = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); + if (obj is IMvcModuleControl) + { + control = obj as IMvcModuleControl; + } + else + { + throw new Exception("Mvc Control needs to implement IMvcModuleControl : " + controlClass); + } + } + catch (Exception ex) + { + throw new Exception("Could not create instance of " + controlClass, ex); + } } - - if (controlSrc.EndsWith(".mvc", System.StringComparison.OrdinalIgnoreCase)) + else if (controlSrc.EndsWith(".mvc", System.StringComparison.OrdinalIgnoreCase)) { control = new MvcModuleControl(); } @@ -85,34 +105,7 @@ public static IMvcModuleControl GetModuleControl(ModuleInfo module, string contr } else { - var controlSrcType = Reflection.CreateType(controlSrc); - if (controlSrcType != null) - { - var controlClass = controlSrcType.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(controlSrcType.Name) + "Control," + controlSrcType.Assembly; - try - { - var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); - control = controller as IMvcModuleControl; - } - catch (Exception ex) - { - throw new Exception("Could not create instance of " + controlClass, ex); - } - } - else - { - var businessController = Reflection.CreateType(module.DesktopModule.BusinessControllerClass); - var controlClass = businessController.Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(controlSrc) + "Control," + businessController.Assembly; - try - { - var controller = Reflection.CreateObject(Globals.DependencyProvider, controlClass, controlClass); - control = controller as IMvcModuleControl; - } - catch (Exception ex) - { - throw new Exception("Could not create instance of " + controlClass, ex); - } - } + throw new Exception("The module control dous not support MVC pipeline : " + module.ModuleTitle + " / " + module.ModuleControl.ControlTitle); } } control.ModuleContext.Configuration = module; diff --git a/DNN Platform/Library/Data/DataProvider.cs b/DNN Platform/Library/Data/DataProvider.cs index 0241e5547d9..577a8c5ebad 100644 --- a/DNN Platform/Library/Data/DataProvider.cs +++ b/DNN Platform/Library/Data/DataProvider.cs @@ -1309,7 +1309,7 @@ public virtual void UpdateModuleDefinition(int moduleDefId, string friendlyName, lastModifiedByUserID); } - public virtual int AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string iconFile, int controlType, int viewOrder, string helpUrl, bool supportsPartialRendering, bool supportsPopUps, int createdByUserID) + public virtual int AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string mvcControlClass, string iconFile, int controlType, int viewOrder, string helpUrl, bool supportsPartialRendering, bool supportsPopUps, int createdByUserID) { return this.ExecuteScalar( "AddModuleControl", @@ -1317,6 +1317,7 @@ public virtual int AddModuleControl(int moduleDefId, string controlKey, string c this.GetNull(controlKey), this.GetNull(controlTitle), controlSrc, + this.GetNull(mvcControlClass), this.GetNull(iconFile), controlType, this.GetNull(viewOrder), @@ -1336,7 +1337,7 @@ public virtual IDataReader GetModuleControls() return this.ExecuteReader("GetModuleControls"); } - public virtual void UpdateModuleControl(int moduleControlId, int moduleDefId, string controlKey, string controlTitle, string controlSrc, string iconFile, int controlType, int viewOrder, string helpUrl, bool supportsPartialRendering, bool supportsPopUps, int lastModifiedByUserID) + public virtual void UpdateModuleControl(int moduleControlId, int moduleDefId, string controlKey, string controlTitle, string controlSrc, string mvcControlClass, string iconFile, int controlType, int viewOrder, string helpUrl, bool supportsPartialRendering, bool supportsPopUps, int lastModifiedByUserID) { this.ExecuteNonQuery( "UpdateModuleControl", @@ -1345,6 +1346,7 @@ public virtual void UpdateModuleControl(int moduleControlId, int moduleDefId, st this.GetNull(controlKey), this.GetNull(controlTitle), controlSrc, + this.GetNull(mvcControlClass), this.GetNull(iconFile), controlType, this.GetNull(viewOrder), diff --git a/DNN Platform/Library/Entities/Modules/ControlInfo.cs b/DNN Platform/Library/Entities/Modules/ControlInfo.cs index ffa39542aa8..2213368d51a 100644 --- a/DNN Platform/Library/Entities/Modules/ControlInfo.cs +++ b/DNN Platform/Library/Entities/Modules/ControlInfo.cs @@ -5,9 +5,9 @@ namespace DotNetNuke.Entities.Modules { using System; using System.Data; - using System.Xml; + using System.Xml; - using DotNetNuke.Common.Utilities; + using DotNetNuke.Common.Utilities; /// Project : DotNetNuke /// Namespace: DotNetNuke.Entities.Modules @@ -28,7 +28,11 @@ protected ControlInfo() /// Gets or sets the Control Source. /// A String. - public string ControlSrc { get; set; } + public string ControlSrc { get; set; } + + /// Gets or sets the Mvc Control Class. + /// A String. + public string MvcControlClass { get; set; } /// /// Gets or sets a value indicating whether gets and sets a flag that determines whether the control support the AJAX @@ -44,7 +48,8 @@ protected override void FillInternal(IDataReader dr) // Call EntityBaseInfo's implementation base.FillInternal(dr); this.ControlKey = Null.SetNullString(dr["ControlKey"]); - this.ControlSrc = Null.SetNullString(dr["ControlSrc"]); + this.ControlSrc = Null.SetNullString(dr["ControlSrc"]); + this.MvcControlClass = Null.SetNullString(dr["MvcControlClass"]); this.SupportsPartialRendering = Null.SetNullBoolean(dr["SupportsPartialRendering"]); } @@ -57,6 +62,9 @@ protected void ReadXmlInternal(XmlReader reader) break; case "controlSrc": this.ControlSrc = reader.ReadElementContentAsString(); + break; + case "mvcControlClass": + this.MvcControlClass = reader.ReadElementContentAsString(); break; case "supportsPartialRendering": string elementvalue = reader.ReadElementContentAsString(); @@ -73,7 +81,8 @@ protected void WriteXmlInternal(XmlWriter writer) { // write out properties writer.WriteElementString("controlKey", this.ControlKey); - writer.WriteElementString("controlSrc", this.ControlSrc); + writer.WriteElementString("controlSrc", this.ControlSrc); + writer.WriteElementString("mvcControlClass", this.MvcControlClass); writer.WriteElementString("supportsPartialRendering", this.SupportsPartialRendering.ToString()); } } diff --git a/DNN Platform/Library/Entities/Modules/ModuleControlController.cs b/DNN Platform/Library/Entities/Modules/ModuleControlController.cs index e77615c48b1..59a6d810657 100644 --- a/DNN Platform/Library/Entities/Modules/ModuleControlController.cs +++ b/DNN Platform/Library/Entities/Modules/ModuleControlController.cs @@ -80,6 +80,7 @@ public static int SaveModuleControl(ModuleControlInfo moduleControl, bool clearC moduleControl.ControlKey, moduleControl.ControlTitle, moduleControl.ControlSrc, + moduleControl.MvcControlClass, moduleControl.IconFile, Convert.ToInt32(moduleControl.ControlType), moduleControl.ViewOrder, @@ -97,6 +98,7 @@ public static int SaveModuleControl(ModuleControlInfo moduleControl, bool clearC moduleControl.ControlKey, moduleControl.ControlTitle, moduleControl.ControlSrc, + moduleControl.MvcControlClass, moduleControl.IconFile, Convert.ToInt32(moduleControl.ControlType), moduleControl.ViewOrder, diff --git a/DNN Platform/Library/Entities/Modules/ModuleInfo.cs b/DNN Platform/Library/Entities/Modules/ModuleInfo.cs index abafcd245ee..1c03fd2ac52 100644 --- a/DNN Platform/Library/Entities/Modules/ModuleInfo.cs +++ b/DNN Platform/Library/Entities/Modules/ModuleInfo.cs @@ -837,6 +837,11 @@ public string GetProperty(string propertyName, string format, CultureInfo format propertyNotFound = false; result = PropertyAccess.FormatString(this.ModuleControl.ControlSrc, format); break; + case "mvcControlClass": + isPublic = false; + propertyNotFound = false; + result = PropertyAccess.FormatString(this.ModuleControl.MvcControlClass, format); + break; case "controltitle": propertyNotFound = false; result = PropertyAccess.FormatString(this.ModuleControl.ControlTitle, format); diff --git a/DNN Platform/Library/Services/Installer/Writers/ModulePackageWriter.cs b/DNN Platform/Library/Services/Installer/Writers/ModulePackageWriter.cs index 61ec40ad88e..9306ab3c35e 100644 --- a/DNN Platform/Library/Services/Installer/Writers/ModulePackageWriter.cs +++ b/DNN Platform/Library/Services/Installer/Writers/ModulePackageWriter.cs @@ -137,7 +137,7 @@ private static void ProcessControls(XPathNavigator controlNav, string moduleFold controlSrc = controlSrc.Replace('\\', '/'); moduleControl.ControlSrc = controlSrc; - + moduleControl.MvcControlClass = Util.ReadElement(controlNav, "mvcControlClass"); moduleControl.IconFile = Util.ReadElement(controlNav, "iconfile"); string controlType = Util.ReadElement(controlNav, "type"); diff --git a/DNN Platform/Library/Services/Upgrade/Upgrade.cs b/DNN Platform/Library/Services/Upgrade/Upgrade.cs index 510af422a12..17cf58979d9 100644 --- a/DNN Platform/Library/Services/Upgrade/Upgrade.cs +++ b/DNN Platform/Library/Services/Upgrade/Upgrade.cs @@ -212,13 +212,14 @@ public static TabInfo AddHostPage(string tabName, string description, string tab /// The key for this control in the Definition. /// The title of this control. /// The source of ths control. + /// The mvc control class of ths control. /// The icon file. /// The type of control. /// The vieworder for this module. - public static void AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string iconFile, SecurityAccessLevel controlType, int viewOrder) + public static void AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string mvcControlClass, string iconFile, SecurityAccessLevel controlType, int viewOrder) { // Call Overload with HelpUrl = Null.NullString - AddModuleControl(moduleDefId, controlKey, controlTitle, controlSrc, iconFile, controlType, viewOrder, Null.NullString); + AddModuleControl(moduleDefId, controlKey, controlTitle, controlSrc, mvcControlClass, iconFile, controlType, viewOrder, Null.NullString); } /// AddModuleDefinition adds a new Core Module Definition to the system. @@ -2109,12 +2110,12 @@ protected static bool IsLanguageEnabled(int portalid, string code) /// The type of control. /// The vieworder for this module. /// The Help Url. - private static void AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string iconFile, SecurityAccessLevel controlType, int viewOrder, string helpURL) + private static void AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string mvcControlClass, string iconFile, SecurityAccessLevel controlType, int viewOrder, string helpURL) { - AddModuleControl(moduleDefId, controlKey, controlTitle, controlSrc, iconFile, controlType, viewOrder, helpURL, false); + AddModuleControl(moduleDefId, controlKey, controlTitle, controlSrc, mvcControlClass, iconFile, controlType, viewOrder, helpURL, false); } - private static void AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string iconFile, SecurityAccessLevel controlType, int viewOrder, string helpURL, bool supportsPartialRendering) + private static void AddModuleControl(int moduleDefId, string controlKey, string controlTitle, string controlSrc, string mvcControlClass, string iconFile, SecurityAccessLevel controlType, int viewOrder, string helpURL, bool supportsPartialRendering) { DnnInstallLogger.InstallLogInfo(Localization.GetString("LogStart", Localization.GlobalResourceFile) + "AddModuleControl:" + moduleDefId); @@ -2129,6 +2130,7 @@ private static void AddModuleControl(int moduleDefId, string controlKey, string ControlKey = controlKey, ControlTitle = controlTitle, ControlSrc = controlSrc, + MvcControlClass = mvcControlClass, ControlType = controlType, ViewOrder = viewOrder, IconFile = iconFile, diff --git a/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs b/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs deleted file mode 100644 index 0000b93a31c..00000000000 --- a/DNN Platform/Modules/HTML/Mvc/EditHTMLControl.cs +++ /dev/null @@ -1,155 +0,0 @@ -// 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.Modules.Html -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net.NetworkInformation; - using System.Web; - using System.Web.Mvc; - - using DotNetNuke.Abstractions; - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.ContentSecurityPolicy; - using DotNetNuke.Entities.Content.Workflow; - using DotNetNuke.Entities.Content.Workflow.Entities; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Settings; - using DotNetNuke.Framework.JavaScriptLibraries; - using DotNetNuke.Modules.Html; - using DotNetNuke.Modules.Html.Components; - using DotNetNuke.Modules.Html.Models; - using DotNetNuke.Security; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.MvcPipeline.Controllers; - using DotNetNuke.Web.MvcPipeline.ModuleControl; - using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; - using Microsoft.Extensions.DependencyInjection; - - public class EditHTMLControl : RazorModuleControlBase - { - private readonly INavigationManager navigationManager; - private readonly HtmlTextController htmlTextController; - private readonly IWorkflowManager workflowManager = WorkflowManager.Instance; - private readonly IContentSecurityPolicy contentSecurityPolicy; - - public EditHTMLControl(IContentSecurityPolicy csp) - { - this.navigationManager = Globals.DependencyProvider.GetRequiredService(); - this.htmlTextController = new HtmlTextController(this.navigationManager); - this.contentSecurityPolicy = csp; - } - - /* - public override string ControlPath => "~/DesktopModules/Html/"; - - public override string ID => "EditHTML"; - */ - public override IRazorModuleResult Invoke() - { - var model = new EditHtmlViewModel(); - try - { - model.LocalResourceFile = this.LocalResourceFile; - model.ShowEditView = true; - model.ModuleId = this.ModuleId; - model.TabId = this.TabId; - model.PortalId = this.PortalId; - model.RedirectUrl = this.navigationManager.NavigateURL(); - int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; - - var htmlContentItemID = Null.NullInteger; - var htmlContent = this.htmlTextController.GetTopHtmlText(this.ModuleId, false, workflowID); - - if (htmlContent != null) - { - htmlContentItemID = htmlContent.ItemID; - var html = System.Web.HttpUtility.HtmlDecode(htmlContent.Content); - model.EditorContent = html; - } - - var workflow = this.workflowManager.GetWorkflow(workflowID); - var workflowStates = workflow.States.ToList(); - model.MaxVersions = this.htmlTextController.GetMaximumVersionHistory(this.PortalId); - var userCanEdit = this.UserInfo.IsSuperUser || PortalSecurity.IsInRole(this.PortalSettings.AdministratorRoleName); - - model.PageSize = Math.Min(Math.Max(model.MaxVersions, 5), 10); // min 5, max 10 - - switch (workflow.WorkflowKey) - { - case SystemWorkflowManager.DirectPublishWorkflowKey: - model.CurrentWorkflowType = WorkflowType.DirectPublish; - break; - case SystemWorkflowManager.SaveDraftWorkflowKey: - model.CurrentWorkflowType = WorkflowType.SaveDraft; - break; - case SystemWorkflowManager.ContentAprovalWorkflowKey: - model.CurrentWorkflowType = WorkflowType.ContentApproval; - break; - } - - if (htmlContentItemID != -1) - { - this.PopulateModelWithContent(model, htmlContent); - } - else - { - this.PopulateModelWithInitialContent(model, workflowStates[0]); - } - - model.ShowPublishOption = model.CurrentWorkflowType != WorkflowType.DirectPublish; - model.ShowCurrentVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; - model.ShowPreviewVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; - model.ShowHistoryView = false; - model.ShowMasterContentButton = false; - } - catch (Exception exc) - { - // Exceptions.ProcessModuleLoadException(this, exc); - throw new Exception("EditHTML", exc); - } - - /* - this.RegisterScript("~/Resources/Shared/scripts/jquery/jquery.form.min.js"); - this.RegisterStyleSheet("~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); - this.RegisterStyleSheet("~/DesktopModules/HTML/edit.css"); - this.RegisterScript("~/DesktopModules/HTML/js/edit.js"); - */ - /* - MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/Resources/Shared/scripts/jquery/jquery.form.min.js"); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); - MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/DesktopModules/HTML/edit.css"); - MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/DesktopModules/HTML/js/edit.js"); - */ - - this.contentSecurityPolicy.StyleSource.AddInline(); - this.contentSecurityPolicy.ScriptSource.AddSelf().AddInline(); - this.contentSecurityPolicy.ImgSource.AddScheme("data:"); - return this.View(model); - } - - private void PopulateModelWithContent(EditHtmlViewModel model, HtmlTextInfo htmlContent) - { - model.CurrentWorkflowInUse = htmlContent.WorkflowName; - model.CurrentWorkflowState = htmlContent.StateName; - model.CurrentVersion = htmlContent.Version.ToString(); - - // model.Content = this.FormatContent(htmlContent.Content); - } - - private void PopulateModelWithInitialContent(EditHtmlViewModel model, WorkflowState firstState) - { - // model.EditorContent = this.LocalizeString("AddContent"); - model.CurrentWorkflowInUse = firstState.StateName; - model.ShowCurrentWorkflowState = false; - model.ShowCurrentVersion = false; - } - } -} diff --git a/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs b/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs deleted file mode 100644 index 6560303e5a6..00000000000 --- a/DNN Platform/Modules/HTML/Mvc/HtmlModuleControl.cs +++ /dev/null @@ -1,87 +0,0 @@ -// 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.Modules.Html -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Web; - using System.Web.Mvc; - - using DotNetNuke.Abstractions; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Actions; - using DotNetNuke.Modules.Html.Models; - using DotNetNuke.Security; - using DotNetNuke.Security.Permissions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.MvcPipeline.ModuleControl; - using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; - using Microsoft.Extensions.DependencyInjection; - - public class HtmlModuleControl : RazorModuleControlBase, IActionable - { - private readonly INavigationManager navigationManager; - private readonly HtmlTextController htmlTextController; - - public HtmlModuleControl() - { - this.navigationManager = this.DependencyProvider.GetRequiredService(); - this.htmlTextController = new HtmlTextController(this.navigationManager); - } - - /// Gets moduleActions is an interface property that returns the module actions collection for the module. - public ModuleActionCollection ModuleActions - { - get - { - // add the Edit Text action - var actions = new ModuleActionCollection(); - actions.Add( - this.GetNextActionID(), - Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), - ModuleActionType.AddContent, - string.Empty, - string.Empty, - this.EditUrl("mvcpage", "yes"), - false, - SecurityAccessLevel.Edit, - true, - false); - - // add mywork to action menu - actions.Add( - this.GetNextActionID(), - Localization.GetString("MyWork.Action", this.LocalResourceFile), - "MyWork.Action", - string.Empty, - "view.gif", - this.EditUrl("mvcpage", "yes", "MyWork"), - false, - SecurityAccessLevel.Edit, - true, - false); - - return actions; - } - } - - public override IRazorModuleResult Invoke() - { - int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; - HtmlTextInfo content = this.htmlTextController.GetTopHtmlText(this.ModuleId, true, workflowID); - - var html = string.Empty; - if (content != null) - { - html = System.Web.HttpUtility.HtmlDecode(content.Content); - } - - return this.View(new HtmlModuleModel() - { - Html = html, - }); - } - } -} diff --git a/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs b/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs deleted file mode 100644 index 593a46bfc31..00000000000 --- a/DNN Platform/Modules/HTML/Mvc/MyWorkControl.cs +++ /dev/null @@ -1,104 +0,0 @@ -// 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.Modules.Html -{ - using System.Collections.Generic; - using System.Linq; - - using DotNetNuke.Abstractions; - using DotNetNuke.Common; - using DotNetNuke.Entities.Content.Workflow.Entities; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Modules.Actions; - using DotNetNuke.Entities.Modules.Settings; - using DotNetNuke.Framework.JavaScriptLibraries; - using DotNetNuke.Modules.Html; - using DotNetNuke.Modules.Html.Components; - using DotNetNuke.Modules.Html.Models; - using DotNetNuke.Security; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; - using DotNetNuke.Web.Client.ClientResourceManagement; - using DotNetNuke.Web.Mvc; - using DotNetNuke.Web.MvcPipeline.Controllers; - using DotNetNuke.Web.MvcPipeline.ModuleControl; - using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; - using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; - using DotNetNuke.Website.Controllers; - using Microsoft.Extensions.DependencyInjection; - - public class MyWorkControl : RazorModuleControlBase, IActionable, IResourcable - { - private readonly INavigationManager navigationManager; - - public MyWorkControl() - { - this.navigationManager = Globals.DependencyProvider.GetRequiredService(); - } - - public ModuleActionCollection ModuleActions - { - get - { - var actions = new ModuleActionCollection(); - actions.Add( - this.GetNextActionID(), - Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), - ModuleActionType.AddContent, - string.Empty, - string.Empty, - this.EditUrl(), - false, - SecurityAccessLevel.Edit, - true, - false); - - return actions; - } - } - - public ModuleResources ModuleResources - { - get - { - return new ModuleResources() - { - StyleSheets = new List() - { - new ModuleStyleSheet() - { - FilePath = "~/DesktopModules/HTML/edit.css", - }, - new ModuleStyleSheet() - { - FilePath = "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css", - }, - }, - }; - } - } - - public override IRazorModuleResult Invoke() - { - var objHtmlTextUsers = new HtmlTextUserController(); - var lst = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID).Cast(); - - return this.View(new MyWorkModel() - { - LocalResourceFile = this.LocalResourceFile, - ModuleId = this.ModuleId, - TabId = this.TabId, - RedirectUrl = this.navigationManager.NavigateURL(), - HtmlTextUsers = lst.Select(u => new HtmlTextUserModel() - { - Url = this.navigationManager.NavigateURL(u.TabID), - ModuleID = u.ModuleID, - ModuleTitle = u.ModuleTitle, - StateName = u.StateName, - }).ToList(), - }); - } - } -} diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider new file mode 100644 index 00000000000..35d2e1784b3 --- /dev/null +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider @@ -0,0 +1,141 @@ +/************************************************************/ +/***** SqlDataProvider *****/ +/***** *****/ +/***** *****/ +/***** Note: To manually execute this script you must *****/ +/***** perform a search and replace operation *****/ +/***** for {databaseOwner} and {objectQualifier} *****/ +/***** *****/ +/************************************************************/ + +/* Add MvcControlClass Column to ModuleControls Table */ +/*****************************************************/ + +IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME='{objectQualifier}ModuleControls' AND COLUMN_NAME='MvcControlClass') + BEGIN + -- Add new Column + ALTER TABLE {databaseOwner}{objectQualifier}ModuleControls + ADD MvcControlClass [nvarchar] (256) NULL + END +GO + +/* Update AddModuleControl */ +/***************************/ + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}AddModuleControl]') AND type in (N'P', N'PC')) + DROP PROCEDURE {databaseOwner}[{objectQualifier}AddModuleControl] +GO + +CREATE PROCEDURE {databaseOwner}[{objectQualifier}AddModuleControl] + + @ModuleDefID int, + @ControlKey nvarchar(50), + @ControlTitle nvarchar(50), + @ControlSrc nvarchar(256), + @MvcControlClass nvarchar(256) = null, + @IconFile nvarchar(100), + @ControlType int, + @ViewOrder int, + @HelpUrl nvarchar(200), + @SupportsPartialRendering bit, + @SupportsPopUps bit, + @CreatedByUserID int + +AS + INSERT INTO {databaseOwner}{objectQualifier}ModuleControls ( + ModuleDefID, + ControlKey, + ControlTitle, + ControlSrc, + MvcControlClass, + IconFile, + ControlType, + ViewOrder, + HelpUrl, + SupportsPartialRendering, + SupportsPopUps, + CreatedByUserID, + CreatedOnDate, + LastModifiedByUserID, + LastModifiedOnDate + ) + VALUES ( + @ModuleDefID, + @ControlKey, + @ControlTitle, + @ControlSrc, + @MvcControlClass, + @IconFile, + @ControlType, + @ViewOrder, + @HelpUrl, + @SupportsPartialRendering, + @SupportsPopUps, + @CreatedByUserID, + getdate(), + @CreatedByUserID, + getdate() + ) + + SELECT SCOPE_IDENTITY() +GO + +/* Update UpdateModuleControl */ +/******************************/ + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}UpdateModuleControl]') AND type in (N'P', N'PC')) + DROP PROCEDURE {databaseOwner}[{objectQualifier}UpdateModuleControl] +GO + +CREATE PROCEDURE {databaseOwner}[{objectQualifier}UpdateModuleControl] + @ModuleControlId int, + @ModuleDefID int, + @ControlKey nvarchar(50), + @ControlTitle nvarchar(50), + @ControlSrc nvarchar(256), + @MvcControlClass nvarchar(256) = null, + @IconFile nvarchar(100), + @ControlType int, + @ViewOrder int, + @HelpUrl nvarchar(200), + @SupportsPartialRendering bit, + @SupportsPopUps bit, + @LastModifiedByUserID int + +AS + UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + ModuleDefId = @ModuleDefId, + ControlKey = @ControlKey, + ControlTitle = @ControlTitle, + ControlSrc = @ControlSrc, + MvcControlClass = @MvcControlClass, + IconFile = @IconFile, + ControlType = @ControlType, + ViewOrder = ViewOrder, + HelpUrl = @HelpUrl, + SupportsPartialRendering = @SupportsPartialRendering, + SupportsPopUps = @SupportsPopUps, + LastModifiedByUserID = @LastModifiedByUserID, + LastModifiedOnDate = getdate() + WHERE ModuleControlId = @ModuleControlId +GO + +/* Update Terms and privacy */ +/************************************************/ + +UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + MvcControlClass = 'DotNetNuke.Web.MvcWebsite.Controls.PrivacyControl, DotNetNuke.Web.MvcWebsite' + WHERE ControlSrc = 'Admin/Portal/Privacy.ascx' + +UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + MvcControlClass = 'DotNetNuke.Web.MvcWebsite.Controls.TermsControl, DotNetNuke.Web.MvcWebsite' + WHERE ControlSrc = 'Admin/Portal/Terms.ascx' + + +UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + MvcControlClass = 'DotNetNuke.Web.MvcWebsite.Controls.TermsControl, DotNetNuke.Web.MvcWebsite' + WHERE ControlSrc = 'Admin/Portal/Terms.ascx' \ No newline at end of file diff --git a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleControlDto.cs b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleControlDto.cs index ee46fd4708a..7dd0525c1ac 100644 --- a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleControlDto.cs +++ b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleControlDto.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information namespace Dnn.PersonaBar.Extensions.Components.Dto.Editors -{ +{ using DotNetNuke.Entities.Modules; using DotNetNuke.Security; - using Newtonsoft.Json; - + using Newtonsoft.Json; + [JsonObject] public class ModuleControlDto { @@ -21,6 +21,7 @@ public ModuleControlDto(ModuleControlInfo moduleControl) this.Key = moduleControl.ControlKey; this.Title = moduleControl.ControlTitle; this.Source = moduleControl.ControlSrc; + this.MvcControl = moduleControl.MvcControlClass; this.Type = moduleControl.ControlType; this.Order = moduleControl.ViewOrder; this.Icon = moduleControl.IconFile; @@ -44,6 +45,9 @@ public ModuleControlDto(ModuleControlInfo moduleControl) [JsonProperty("source")] public string Source { get; set; } + [JsonProperty("mvcControl")] + public string MvcControl { get; set; } + [JsonProperty("type")] public SecurityAccessLevel Type { get; set; } @@ -71,6 +75,7 @@ public ModuleControlInfo ToModuleControlInfo() ControlKey = this.Key, ControlTitle = this.Title, ControlSrc = this.Source, + MvcControlClass = this.MvcControl, ControlType = this.Type, ViewOrder = this.Order, IconFile = this.Icon, diff --git a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleDefinitionDto.cs b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleDefinitionDto.cs index f39a817b0bb..8cd02b65b0c 100644 --- a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleDefinitionDto.cs +++ b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModuleDefinitionDto.cs @@ -1,62 +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 Dnn.PersonaBar.Extensions.Components.Dto.Editors +// 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 Dnn.PersonaBar.Extensions.Components.Dto.Editors { - using System.Collections.Generic; + using System.Collections.Generic; - using DotNetNuke.Entities.Modules.Definitions; + using DotNetNuke.Entities.Modules.Definitions; using Newtonsoft.Json; - [JsonObject] - public class ModuleDefinitionDto - { - public ModuleDefinitionDto() - { - } - - public ModuleDefinitionDto(ModuleDefinitionInfo definition) - { - this.Id = definition.ModuleDefID; - this.DesktopModuleId = definition.DesktopModuleID; - this.Name = definition.DefinitionName; - this.FriendlyName = definition.FriendlyName; - this.CacheTime = definition.DefaultCacheTime; - - foreach (var moduleControlInfo in definition.ModuleControls.Values) - { - this.Controls.Add(new ModuleControlDto(moduleControlInfo)); - } - } - - [JsonProperty("id")] - public int Id { get; set; } - - [JsonProperty("desktopModuleId")] - public int DesktopModuleId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("friendlyName")] - public string FriendlyName { get; set; } - - [JsonProperty("cacheTime")] - public int CacheTime { get; set; } - - [JsonProperty("controls")] - public IList Controls { get; set; } = new List(); - - public ModuleDefinitionInfo ToModuleDefinitionInfo() - { - return new ModuleDefinitionInfo - { - ModuleDefID = this.Id, - DesktopModuleID = this.DesktopModuleId, - DefinitionName = this.Name, - FriendlyName = this.FriendlyName, - DefaultCacheTime = this.CacheTime, - }; - } - } -} + [JsonObject] + public class ModuleDefinitionDto + { + public ModuleDefinitionDto() + { + } + + public ModuleDefinitionDto(ModuleDefinitionInfo definition) + { + this.Id = definition.ModuleDefID; + this.DesktopModuleId = definition.DesktopModuleID; + this.Name = definition.DefinitionName; + this.FriendlyName = definition.FriendlyName; + this.CacheTime = definition.DefaultCacheTime; + + foreach (var moduleControlInfo in definition.ModuleControls.Values) + { + this.Controls.Add(new ModuleControlDto(moduleControlInfo)); + } + } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("desktopModuleId")] + public int DesktopModuleId { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("friendlyName")] + public string FriendlyName { get; set; } + + [JsonProperty("cacheTime")] + public int CacheTime { get; set; } + + [JsonProperty("controls")] + public IList Controls { get; set; } = new List(); + + public ModuleDefinitionInfo ToModuleDefinitionInfo() + { + return new ModuleDefinitionInfo + { + ModuleDefID = this.Id, + DesktopModuleID = this.DesktopModuleId, + DefinitionName = this.Name, + FriendlyName = this.FriendlyName, + DefaultCacheTime = this.CacheTime, + }; + } + } +} diff --git a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModulePackageDetailDto.cs b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModulePackageDetailDto.cs index efa82234ab1..2268ac169f0 100644 --- a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModulePackageDetailDto.cs +++ b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/Components/Extensions/Dto/Editors/ModulePackageDetailDto.cs @@ -1,104 +1,104 @@ -// 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 Dnn.PersonaBar.Extensions.Components.Dto.Editors +// 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 Dnn.PersonaBar.Extensions.Components.Dto.Editors { - using System.Collections.Generic; - using System.Linq; + using System.Collections.Generic; + using System.Linq; - using DotNetNuke.Entities.Modules; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Services.Installer.Packages; - using Newtonsoft.Json; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Services.Installer.Packages; + using Newtonsoft.Json; - [JsonObject] - public class ModulePackageDetailDto : ModulePackagePermissionsDto - { - public ModulePackageDetailDto() - { - } + [JsonObject] + public class ModulePackageDetailDto : ModulePackagePermissionsDto + { + public ModulePackageDetailDto() + { + } public ModulePackageDetailDto(int portalId, PackageInfo package, DesktopModuleInfo desktopModule) - : base(portalId, package) - { - this.DesktopModuleId = desktopModule.DesktopModuleID; - this.ModuleName = desktopModule.ModuleName; - this.FolderName = desktopModule.FolderName; - this.BusinessController = desktopModule.BusinessControllerClass; - this.Category = desktopModule.Category; - this.Dependencies = desktopModule.Dependencies; - this.HostPermissions = desktopModule.Permissions; - this.Portable = desktopModule.IsPortable; - this.Searchable = desktopModule.IsSearchable; - this.Upgradeable = desktopModule.IsUpgradeable; - this.PremiumModule = desktopModule.IsPremium; - this.Shareable = desktopModule.Shareable; - - if (!desktopModule.IsAdmin) - { - var portalDesktopModules = - DesktopModuleController.GetPortalDesktopModulesByDesktopModuleID(desktopModule.DesktopModuleID); - foreach (var portalDesktopModuleInfo in portalDesktopModules) - { - var value = portalDesktopModuleInfo.Value; - this.AssignedPortals.Add(new ListItemDto { Id = value.PortalID, Name = value.PortalName }); - } - - var assignedIds = this.AssignedPortals.Select(p => p.Id).ToArray(); - var allPortals = PortalController.Instance.GetPortals().OfType().Where(p => !assignedIds.Contains(p.PortalID)); - - foreach (var portalInfo in allPortals) - { - this.UnassignedPortals.Add(new ListItemDto { Id = portalInfo.PortalID, Name = portalInfo.PortalName }); - } - } - - foreach (var moduleDefinition in desktopModule.ModuleDefinitions.Values) - { - this.ModuleDefinitions.Add(new ModuleDefinitionDto(moduleDefinition)); - } - } - - [JsonProperty("moduleName")] - public string ModuleName { get; set; } - - [JsonProperty("folderName")] - public string FolderName { get; set; } - - [JsonProperty("category")] - public string Category { get; set; } - - [JsonProperty("businessController")] - public string BusinessController { get; set; } - - [JsonProperty("dependencies")] - public string Dependencies { get; set; } - - [JsonProperty("hostPermissions")] - public string HostPermissions { get; set; } - - [JsonProperty("portable")] - public bool Portable { get; set; } - - [JsonProperty("searchable")] - public bool Searchable { get; set; } - - [JsonProperty("upgradeable")] - public bool Upgradeable { get; set; } - - [JsonProperty("shareable")] - public ModuleSharing Shareable { get; set; } - - [JsonProperty("premiumModule")] - public bool PremiumModule { get; set; } - - [JsonProperty("assignedPortals")] - public IList AssignedPortals { get; set; } = new List(); - - [JsonProperty("unassignedPortals")] - public IList UnassignedPortals { get; set; } = new List(); - - [JsonProperty("moduleDefinitions")] - public IList ModuleDefinitions { get; set; } = new List(); - } -} + : base(portalId, package) + { + this.DesktopModuleId = desktopModule.DesktopModuleID; + this.ModuleName = desktopModule.ModuleName; + this.FolderName = desktopModule.FolderName; + this.BusinessController = desktopModule.BusinessControllerClass; + this.Category = desktopModule.Category; + this.Dependencies = desktopModule.Dependencies; + this.HostPermissions = desktopModule.Permissions; + this.Portable = desktopModule.IsPortable; + this.Searchable = desktopModule.IsSearchable; + this.Upgradeable = desktopModule.IsUpgradeable; + this.PremiumModule = desktopModule.IsPremium; + this.Shareable = desktopModule.Shareable; + + if (!desktopModule.IsAdmin) + { + var portalDesktopModules = + DesktopModuleController.GetPortalDesktopModulesByDesktopModuleID(desktopModule.DesktopModuleID); + foreach (var portalDesktopModuleInfo in portalDesktopModules) + { + var value = portalDesktopModuleInfo.Value; + this.AssignedPortals.Add(new ListItemDto { Id = value.PortalID, Name = value.PortalName }); + } + + var assignedIds = this.AssignedPortals.Select(p => p.Id).ToArray(); + var allPortals = PortalController.Instance.GetPortals().OfType().Where(p => !assignedIds.Contains(p.PortalID)); + + foreach (var portalInfo in allPortals) + { + this.UnassignedPortals.Add(new ListItemDto { Id = portalInfo.PortalID, Name = portalInfo.PortalName }); + } + } + + foreach (var moduleDefinition in desktopModule.ModuleDefinitions.Values) + { + this.ModuleDefinitions.Add(new ModuleDefinitionDto(moduleDefinition)); + } + } + + [JsonProperty("moduleName")] + public string ModuleName { get; set; } + + [JsonProperty("folderName")] + public string FolderName { get; set; } + + [JsonProperty("category")] + public string Category { get; set; } + + [JsonProperty("businessController")] + public string BusinessController { get; set; } + + [JsonProperty("dependencies")] + public string Dependencies { get; set; } + + [JsonProperty("hostPermissions")] + public string HostPermissions { get; set; } + + [JsonProperty("portable")] + public bool Portable { get; set; } + + [JsonProperty("searchable")] + public bool Searchable { get; set; } + + [JsonProperty("upgradeable")] + public bool Upgradeable { get; set; } + + [JsonProperty("shareable")] + public ModuleSharing Shareable { get; set; } + + [JsonProperty("premiumModule")] + public bool PremiumModule { get; set; } + + [JsonProperty("assignedPortals")] + public IList AssignedPortals { get; set; } = new List(); + + [JsonProperty("unassignedPortals")] + public IList UnassignedPortals { get; set; } = new List(); + + [JsonProperty("moduleDefinitions")] + public IList ModuleDefinitions { get; set; } = new List(); + } +} diff --git a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/admin/personaBar/Dnn.Extensions/App_LocalResources/Extensions.resx b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/admin/personaBar/Dnn.Extensions/App_LocalResources/Extensions.resx index ced89b16e7d..cbc0e70075f 100644 --- a/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/admin/personaBar/Dnn.Extensions/App_LocalResources/Extensions.resx +++ b/Dnn.AdminExperience/Dnn.PersonaBar.Extensions/admin/personaBar/Dnn.Extensions/App_LocalResources/Extensions.resx @@ -1220,4 +1220,10 @@ Common issues with bad installation files: Your extensions will be here in a just a moment + + The fully qualified class name of this mvc control required to suporting the Mvc Pipeline. + + + Mvc Control class + \ No newline at end of file From eb790e0f0113e074d694073b2b246c079671af70 Mon Sep 17 00:00:00 2001 From: Sacha Date: Wed, 17 Sep 2025 14:04:08 +0200 Subject: [PATCH 17/34] ad mvcmodelclass to db for html module --- .../Modules/HTML/Controls/EditHTMLControl.cs | 155 ++++++++++++++++++ .../HTML/Controls/HtmlModuleControl.cs | 87 ++++++++++ .../Modules/HTML/Controls/MyWorkControl.cs | 104 ++++++++++++ .../HTML/DotNetNuke.Modules.Html.csproj | 9 +- .../SqlDataProvider/10.99.00.SqlDataProvider | 27 +++ DNN Platform/Modules/HTML/dnn_HTML.dnn | 7 +- .../Controls/ControlFields.jsx | 7 + 7 files changed, 391 insertions(+), 5 deletions(-) create mode 100644 DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs create mode 100644 DNN Platform/Modules/HTML/Controls/HtmlModuleControl.cs create mode 100644 DNN Platform/Modules/HTML/Controls/MyWorkControl.cs create mode 100644 DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider diff --git a/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs b/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs new file mode 100644 index 00000000000..5aa32d57738 --- /dev/null +++ b/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs @@ -0,0 +1,155 @@ +// 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.Modules.Html.Controls +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net.NetworkInformation; + using System.Web; + using System.Web.Mvc; + + using DotNetNuke.Abstractions; + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.ContentSecurityPolicy; + using DotNetNuke.Entities.Content.Workflow; + using DotNetNuke.Entities.Content.Workflow.Entities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Settings; + using DotNetNuke.Framework.JavaScriptLibraries; + using DotNetNuke.Modules.Html; + using DotNetNuke.Modules.Html.Components; + using DotNetNuke.Modules.Html.Models; + using DotNetNuke.Security; + using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.MvcPipeline.Controllers; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + using Microsoft.Extensions.DependencyInjection; + + public class EditHTMLControl : RazorModuleControlBase + { + private readonly INavigationManager navigationManager; + private readonly HtmlTextController htmlTextController; + private readonly IWorkflowManager workflowManager = WorkflowManager.Instance; + private readonly IContentSecurityPolicy contentSecurityPolicy; + + public EditHTMLControl(IContentSecurityPolicy csp) + { + this.navigationManager = Globals.DependencyProvider.GetRequiredService(); + this.htmlTextController = new HtmlTextController(this.navigationManager); + this.contentSecurityPolicy = csp; + } + + /* + public override string ControlPath => "~/DesktopModules/Html/"; + + public override string ID => "EditHTML"; + */ + public override IRazorModuleResult Invoke() + { + var model = new EditHtmlViewModel(); + try + { + model.LocalResourceFile = this.LocalResourceFile; + model.ShowEditView = true; + model.ModuleId = this.ModuleId; + model.TabId = this.TabId; + model.PortalId = this.PortalId; + model.RedirectUrl = this.navigationManager.NavigateURL(); + int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; + + var htmlContentItemID = Null.NullInteger; + var htmlContent = this.htmlTextController.GetTopHtmlText(this.ModuleId, false, workflowID); + + if (htmlContent != null) + { + htmlContentItemID = htmlContent.ItemID; + var html = System.Web.HttpUtility.HtmlDecode(htmlContent.Content); + model.EditorContent = html; + } + + var workflow = this.workflowManager.GetWorkflow(workflowID); + var workflowStates = workflow.States.ToList(); + model.MaxVersions = this.htmlTextController.GetMaximumVersionHistory(this.PortalId); + var userCanEdit = this.UserInfo.IsSuperUser || PortalSecurity.IsInRole(this.PortalSettings.AdministratorRoleName); + + model.PageSize = Math.Min(Math.Max(model.MaxVersions, 5), 10); // min 5, max 10 + + switch (workflow.WorkflowKey) + { + case SystemWorkflowManager.DirectPublishWorkflowKey: + model.CurrentWorkflowType = WorkflowType.DirectPublish; + break; + case SystemWorkflowManager.SaveDraftWorkflowKey: + model.CurrentWorkflowType = WorkflowType.SaveDraft; + break; + case SystemWorkflowManager.ContentAprovalWorkflowKey: + model.CurrentWorkflowType = WorkflowType.ContentApproval; + break; + } + + if (htmlContentItemID != -1) + { + this.PopulateModelWithContent(model, htmlContent); + } + else + { + this.PopulateModelWithInitialContent(model, workflowStates[0]); + } + + model.ShowPublishOption = model.CurrentWorkflowType != WorkflowType.DirectPublish; + model.ShowCurrentVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; + model.ShowPreviewVersion = model.CurrentWorkflowType != WorkflowType.DirectPublish; + model.ShowHistoryView = false; + model.ShowMasterContentButton = false; + } + catch (Exception exc) + { + // Exceptions.ProcessModuleLoadException(this, exc); + throw new Exception("EditHTML", exc); + } + + /* + this.RegisterScript("~/Resources/Shared/scripts/jquery/jquery.form.min.js"); + this.RegisterStyleSheet("~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); + this.RegisterStyleSheet("~/DesktopModules/HTML/edit.css"); + this.RegisterScript("~/DesktopModules/HTML/js/edit.js"); + */ + /* + MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/Resources/Shared/scripts/jquery/jquery.form.min.js"); + MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css"); + MvcClientResourceManager.RegisterStyleSheet(this.ControllerContext, "~/DesktopModules/HTML/edit.css"); + MvcClientResourceManager.RegisterScript(this.ControllerContext, "~/DesktopModules/HTML/js/edit.js"); + */ + + this.contentSecurityPolicy.StyleSource.AddInline(); + this.contentSecurityPolicy.ScriptSource.AddSelf().AddInline(); + this.contentSecurityPolicy.ImgSource.AddScheme("data:"); + return this.View(model); + } + + private void PopulateModelWithContent(EditHtmlViewModel model, HtmlTextInfo htmlContent) + { + model.CurrentWorkflowInUse = htmlContent.WorkflowName; + model.CurrentWorkflowState = htmlContent.StateName; + model.CurrentVersion = htmlContent.Version.ToString(); + + // model.Content = this.FormatContent(htmlContent.Content); + } + + private void PopulateModelWithInitialContent(EditHtmlViewModel model, WorkflowState firstState) + { + // model.EditorContent = this.LocalizeString("AddContent"); + model.CurrentWorkflowInUse = firstState.StateName; + model.ShowCurrentWorkflowState = false; + model.ShowCurrentVersion = false; + } + } +} diff --git a/DNN Platform/Modules/HTML/Controls/HtmlModuleControl.cs b/DNN Platform/Modules/HTML/Controls/HtmlModuleControl.cs new file mode 100644 index 00000000000..2461e877504 --- /dev/null +++ b/DNN Platform/Modules/HTML/Controls/HtmlModuleControl.cs @@ -0,0 +1,87 @@ +// 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.Modules.Html.Controls +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.Mvc; + + using DotNetNuke.Abstractions; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Modules.Html.Models; + using DotNetNuke.Security; + using DotNetNuke.Security.Permissions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + using Microsoft.Extensions.DependencyInjection; + + public class HtmlModuleControl : RazorModuleControlBase, IActionable + { + private readonly INavigationManager navigationManager; + private readonly HtmlTextController htmlTextController; + + public HtmlModuleControl() + { + this.navigationManager = this.DependencyProvider.GetRequiredService(); + this.htmlTextController = new HtmlTextController(this.navigationManager); + } + + /// Gets moduleActions is an interface property that returns the module actions collection for the module. + public ModuleActionCollection ModuleActions + { + get + { + // add the Edit Text action + var actions = new ModuleActionCollection(); + actions.Add( + this.GetNextActionID(), + Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), + ModuleActionType.AddContent, + string.Empty, + string.Empty, + this.EditUrl("mvcpage", "yes"), + false, + SecurityAccessLevel.Edit, + true, + false); + + // add mywork to action menu + actions.Add( + this.GetNextActionID(), + Localization.GetString("MyWork.Action", this.LocalResourceFile), + "MyWork.Action", + string.Empty, + "view.gif", + this.EditUrl("mvcpage", "yes", "MyWork"), + false, + SecurityAccessLevel.Edit, + true, + false); + + return actions; + } + } + + public override IRazorModuleResult Invoke() + { + int workflowID = this.htmlTextController.GetWorkflow(this.ModuleId, this.TabId, this.PortalId).Value; + HtmlTextInfo content = this.htmlTextController.GetTopHtmlText(this.ModuleId, true, workflowID); + + var html = string.Empty; + if (content != null) + { + html = System.Web.HttpUtility.HtmlDecode(content.Content); + } + + return this.View(new HtmlModuleModel() + { + Html = html, + }); + } + } +} diff --git a/DNN Platform/Modules/HTML/Controls/MyWorkControl.cs b/DNN Platform/Modules/HTML/Controls/MyWorkControl.cs new file mode 100644 index 00000000000..7e617c0c1b5 --- /dev/null +++ b/DNN Platform/Modules/HTML/Controls/MyWorkControl.cs @@ -0,0 +1,104 @@ +// 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.Modules.Html.Controls +{ + using System.Collections.Generic; + using System.Linq; + + using DotNetNuke.Abstractions; + using DotNetNuke.Common; + using DotNetNuke.Entities.Content.Workflow.Entities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Entities.Modules.Actions; + using DotNetNuke.Entities.Modules.Settings; + using DotNetNuke.Framework.JavaScriptLibraries; + using DotNetNuke.Modules.Html; + using DotNetNuke.Modules.Html.Components; + using DotNetNuke.Modules.Html.Models; + using DotNetNuke.Security; + using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; + using DotNetNuke.Web.Client.ClientResourceManagement; + using DotNetNuke.Web.Mvc; + using DotNetNuke.Web.MvcPipeline.Controllers; + using DotNetNuke.Web.MvcPipeline.ModuleControl; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; + using DotNetNuke.Website.Controllers; + using Microsoft.Extensions.DependencyInjection; + + public class MyWorkControl : RazorModuleControlBase, IActionable, IResourcable + { + private readonly INavigationManager navigationManager; + + public MyWorkControl() + { + this.navigationManager = Globals.DependencyProvider.GetRequiredService(); + } + + public ModuleActionCollection ModuleActions + { + get + { + var actions = new ModuleActionCollection(); + actions.Add( + this.GetNextActionID(), + Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), + ModuleActionType.AddContent, + string.Empty, + string.Empty, + this.EditUrl(), + false, + SecurityAccessLevel.Edit, + true, + false); + + return actions; + } + } + + public ModuleResources ModuleResources + { + get + { + return new ModuleResources() + { + StyleSheets = new List() + { + new ModuleStyleSheet() + { + FilePath = "~/DesktopModules/HTML/edit.css", + }, + new ModuleStyleSheet() + { + FilePath = "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css", + }, + }, + }; + } + } + + public override IRazorModuleResult Invoke() + { + var objHtmlTextUsers = new HtmlTextUserController(); + var lst = objHtmlTextUsers.GetHtmlTextUser(this.UserInfo.UserID).Cast(); + + return this.View(new MyWorkModel() + { + LocalResourceFile = this.LocalResourceFile, + ModuleId = this.ModuleId, + TabId = this.TabId, + RedirectUrl = this.navigationManager.NavigateURL(), + HtmlTextUsers = lst.Select(u => new HtmlTextUserModel() + { + Url = this.navigationManager.NavigateURL(u.TabID), + ModuleID = u.ModuleID, + ModuleTitle = u.ModuleTitle, + StateName = u.StateName, + }).ToList(), + }); + } + } +} diff --git a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj index 609a18cc232..e022a88678c 100644 --- a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj +++ b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj @@ -181,10 +181,10 @@ - - - - + + + + MyWork.ascx ASPXCodeBehind @@ -249,6 +249,7 @@ + diff --git a/DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider b/DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider new file mode 100644 index 00000000000..f621603e539 --- /dev/null +++ b/DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider @@ -0,0 +1,27 @@ +/************************************************************/ +/***** SqlDataProvider *****/ +/***** *****/ +/***** *****/ +/***** Note: To manually execute this script you must *****/ +/***** perform a search and replace operation *****/ +/***** for {databaseOwner} and {objectQualifier} *****/ +/***** *****/ +/************************************************************/ + +/* Add MVC pipeline support */ +/************************************************/ + +UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + MvcControlClass = 'DotNetNuke.Modules.Html.Controls.HtmlModuleControl, DotNetNuke.Modules.Html' + WHERE ControlSrc = 'DesktopModules/HTML/HtmlModule.ascx' + +UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + MvcControlClass = 'DotNetNuke.Modules.Html.Controls.EditHTMLControl, DotNetNuke.Modules.Html' + WHERE ControlSrc = 'DesktopModules/HTML/EditHTML.ascx' + +UPDATE {databaseOwner}{objectQualifier}ModuleControls + SET + MvcControlClass = 'DotNetNuke.Modules.Html.Controls.MyWorkControl, DotNetNuke.Modules.Html' + WHERE ControlSrc = 'DesktopModules/HTML/MyWork.ascx' diff --git a/DNN Platform/Modules/HTML/dnn_HTML.dnn b/DNN Platform/Modules/HTML/dnn_HTML.dnn index 9c505e1be5a..4a64f42a2b3 100644 --- a/DNN Platform/Modules/HTML/dnn_HTML.dnn +++ b/DNN Platform/Modules/HTML/dnn_HTML.dnn @@ -1,6 +1,6 @@  - + HTML This module renders a block of HTML or Text content. The Html/Text module allows authorized users to edit the content either inline or in a separate administration page. Optional tokens can be used that get replaced dynamically during display. All versions of content are stored in the database including the ability to rollback to an older version. DesktopModules\HTML\Images\html.png @@ -105,6 +105,11 @@ 10.00.02.SqlDataProvider 10.00.02 + + +// Nonce is automatically applied when using AddNonce() +csp.ScriptSource.AddNonce(nonce); +``` + +### Removing Sources + +```csharp +// Remove unsafe script sources +csp.RemoveScriptSources(CspSourceType.Inline); +csp.RemoveScriptSources(CspSourceType.Eval); +``` + +### Reporting Configuration + +```csharp +// Configure violation reporting +csp.AddReportEndpoint("default", "/api/csp-reports"); +csp.AddReportTo("default"); +``` + +### Generating Policy Headers + +```csharp +// Generate the complete CSP header value +string cspHeader = csp.GeneratePolicy(); +// Result: "default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self' 'unsafe-inline'" + +// Generate reporting endpoints header +string reportingHeader = csp.GenerateReportingEndpoints(); +``` + +## Source Types + +The library supports all standard CSP source types through the `CspSourceType` enumeration: + +- **Host**: Specific domains (e.g., `example.com`, `*.example.com`) +- **Scheme**: Protocol schemes (e.g., `https:`, `data:`, `blob:`) +- **Self**: Same origin (`'self'`) +- **Inline**: Inline scripts/styles (`'unsafe-inline'`) +- **Eval**: Dynamic code evaluation (`'unsafe-eval'`) +- **Nonce**: Cryptographic nonce (`'nonce-abc123'`) +- **Hash**: Cryptographic hash (`'sha256-abc123'`) +- **None**: Block all sources (`'none'`) +- **StrictDynamic**: Enable strict dynamic loading (`'strict-dynamic'`) + +## Security Best Practices + +1. **Avoid `'unsafe-inline'`**: Use nonces or hashes instead +2. **Avoid `'unsafe-eval'`**: Prevents code injection attacks +3. **Use `'strict-dynamic'`**: For modern browsers with script loading +4. **Implement reporting**: Monitor CSP violations +5. **Start restrictive**: Begin with strict policies and relax as needed +6. **Test thoroughly**: Ensure all legitimate resources load correctly + +## Implementation Details + +### Key Classes + +- **ContentSecurityPolicy**: Main implementation of `IContentSecurityPolicy` +- **SourceCspContributor**: Manages source-based directives +- **CspSource**: Represents individual CSP sources +- **CspDirectiveType**: Enumeration of all CSP directive types +- **CspSourceType**: Enumeration of all CSP source types + +### Thread Safety + +The CSP implementation is designed to be used within a single request context. For multi-threaded scenarios, create separate instances per thread or request. + +### Performance Considerations + +- Nonce generation uses cryptographically secure random number generation +- Policy generation is optimized for minimal string operations +- Source deduplication prevents duplicate entries + +## Class Diagram + +```mermaid +classDiagram + class IContentSecurityPolicy { + <> + +string Nonce + +SourceCspContributor DefaultSource + +SourceCspContributor ScriptSource + +SourceCspContributor StyleSource + +SourceCspContributor ImgSource + +SourceCspContributor ConnectSource + +SourceCspContributor FontSource + +SourceCspContributor ObjectSource + +SourceCspContributor MediaSource + +SourceCspContributor FrameSource + +SourceCspContributor FrameAncestors + +SourceCspContributor FormAction + +SourceCspContributor BaseUriSource + +RemoveScriptSources(CspSourceType) void + +AddPluginTypes(string) void + +AddSandboxDirective(string) void + +AddFormAction(CspSourceType, string) void + +AddFrameAncestors(CspSourceType, string) void + +AddReportEndpoint(string, string) void + +AddReportTo(string) void + +GeneratePolicy() string + +GenerateReportingEndpoints() string + +UpgradeInsecureRequests() void + } + + class ContentSecurityPolicy { + + } + + class BaseCspContributor { + <> + +Guid Id + +CspDirectiveType DirectiveType + +GenerateDirective()* string + } + + class SourceCspContributor { + -List~CspSource~ Sources + +bool InlineForBackwardCompatibility + +AddInline() SourceCspContributor + +AddSelf() SourceCspContributor + +AddSourceEval() SourceCspContributor + +AddHost(string) SourceCspContributor + +AddScheme(string) SourceCspContributor + +AddNonce(string) SourceCspContributor + +AddHash(string) SourceCspContributor + +AddNone() SourceCspContributor + +AddStrictDynamic() SourceCspContributor + +AddSource(CspSource) SourceCspContributor + +RemoveSources(CspSourceType) void + +GenerateDirective() string + +GetSourcesByType(CspSourceType) IEnumerable~CspSource~ + } + + class ReportingCspContributor { + -List~string~ reportingEndpoints + +AddReportingEndpoint(string) void + +GenerateDirective() string + } + + class ReportingEndpointContributor { + -List~ReportingEndpoint~ reportingEndpoints + +AddReportingEndpoint(string, string) void + +GenerateDirective() string + } + + class CspSource { + +CspSourceType Type + +string Value + +CspSource(CspSourceType, string) + +ToString() string + -ValidateSource(CspSourceType, string) string + -ValidateHostSource(string) string + -ValidateSchemeSource(string) string + -ValidateNonceSource(string) string + -ValidateHashSource(string) string + -IsBase64String(string) bool + } + + + + IContentSecurityPolicy <|.. ContentSecurityPolicy : implements + BaseCspContributor <|-- SourceCspContributor : extends + BaseCspContributor <|-- DocumentCspContributor : extends + BaseCspContributor <|-- ReportingCspContributor : extends + BaseCspContributor <|-- ReportingEndpointContributor : extends + ContentSecurityPolicy *-- BaseCspContributor : contains + SourceCspContributor *-- CspSource : contains + + + +``` + +## Integration with DotNetNuke + +This library integrates seamlessly with the DotNetNuke Platform's security infrastructure and can be used within: + +- Custom modules +- Skin implementations +- HTTP modules and handlers +- API controllers +- Page rendering pipelines + From 176faf4f0d4cd4eb269500e4e34eafb2bcb81277 Mon Sep 17 00:00:00 2001 From: Sacha Date: Wed, 17 Sep 2025 16:25:18 +0200 Subject: [PATCH 19/34] update mvcmoduleclass in manifest and remove sql migration script --- .../Modules/HTML/Controls/EditHTMLControl.cs | 32 ++++++++++++++++--- .../HTML/DotNetNuke.Modules.Html.csproj | 3 +- .../SqlDataProvider/10.99.00.SqlDataProvider | 27 ---------------- DNN Platform/Modules/HTML/dnn_HTML.dnn | 10 +++--- 4 files changed, 32 insertions(+), 40 deletions(-) delete mode 100644 DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider diff --git a/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs b/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs index 5aa32d57738..5fa2b537fc1 100644 --- a/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs +++ b/DNN Platform/Modules/HTML/Controls/EditHTMLControl.cs @@ -31,9 +31,10 @@ namespace DotNetNuke.Modules.Html.Controls using DotNetNuke.Web.MvcPipeline.Controllers; using DotNetNuke.Web.MvcPipeline.ModuleControl; using DotNetNuke.Web.MvcPipeline.ModuleControl.Razor; + using DotNetNuke.Web.MvcPipeline.ModuleControl.Resources; using Microsoft.Extensions.DependencyInjection; - public class EditHTMLControl : RazorModuleControlBase + public class EditHTMLControl : RazorModuleControlBase, IResourcable { private readonly INavigationManager navigationManager; private readonly HtmlTextController htmlTextController; @@ -47,11 +48,32 @@ public EditHTMLControl(IContentSecurityPolicy csp) this.contentSecurityPolicy = csp; } - /* - public override string ControlPath => "~/DesktopModules/Html/"; + public ModuleResources ModuleResources => new ModuleResources() + { + StyleSheets = new List() + { + new ModuleStyleSheet() + { + FilePath = "~/DesktopModules/HTML/edit.css", + }, + new ModuleStyleSheet() + { + FilePath = "~/Portals/_default/Skins/_default/WebControlSkin/Default/GridView.default.css", + }, + }, + Scripts = new List() + { + new ModuleScript() + { + FilePath = "~/Resources/Shared/scripts/jquery/jquery.form.min.js", + }, + new ModuleScript() + { + FilePath = "~/DesktopModules/HTML/js/edit.js", + }, + }, + }; - public override string ID => "EditHTML"; - */ public override IRazorModuleResult Invoke() { var model = new EditHtmlViewModel(); diff --git a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj index e022a88678c..984ddfe301d 100644 --- a/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj +++ b/DNN Platform/Modules/HTML/DotNetNuke.Modules.Html.csproj @@ -184,7 +184,7 @@ - + MyWork.ascx ASPXCodeBehind @@ -249,7 +249,6 @@ - diff --git a/DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider b/DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider deleted file mode 100644 index f621603e539..00000000000 --- a/DNN Platform/Modules/HTML/Providers/DataProviders/SqlDataProvider/10.99.00.SqlDataProvider +++ /dev/null @@ -1,27 +0,0 @@ -/************************************************************/ -/***** SqlDataProvider *****/ -/***** *****/ -/***** *****/ -/***** Note: To manually execute this script you must *****/ -/***** perform a search and replace operation *****/ -/***** for {databaseOwner} and {objectQualifier} *****/ -/***** *****/ -/************************************************************/ - -/* Add MVC pipeline support */ -/************************************************/ - -UPDATE {databaseOwner}{objectQualifier}ModuleControls - SET - MvcControlClass = 'DotNetNuke.Modules.Html.Controls.HtmlModuleControl, DotNetNuke.Modules.Html' - WHERE ControlSrc = 'DesktopModules/HTML/HtmlModule.ascx' - -UPDATE {databaseOwner}{objectQualifier}ModuleControls - SET - MvcControlClass = 'DotNetNuke.Modules.Html.Controls.EditHTMLControl, DotNetNuke.Modules.Html' - WHERE ControlSrc = 'DesktopModules/HTML/EditHTML.ascx' - -UPDATE {databaseOwner}{objectQualifier}ModuleControls - SET - MvcControlClass = 'DotNetNuke.Modules.Html.Controls.MyWorkControl, DotNetNuke.Modules.Html' - WHERE ControlSrc = 'DesktopModules/HTML/MyWork.ascx' diff --git a/DNN Platform/Modules/HTML/dnn_HTML.dnn b/DNN Platform/Modules/HTML/dnn_HTML.dnn index 4a64f42a2b3..59ed978176a 100644 --- a/DNN Platform/Modules/HTML/dnn_HTML.dnn +++ b/DNN Platform/Modules/HTML/dnn_HTML.dnn @@ -104,12 +104,7 @@ Providers\DataProviders\SqlDataProvider 10.00.02.SqlDataProvider 10.00.02 - - +