From 1f79d9e635f6cf7385390d0a0c93dd0ffd041555 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 24 Jan 2019 14:29:00 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=AA=F0=9F=94=AANext=20on=20the=20chobb?= =?UTF-8?q?ing=20block=20is=20config/create/ui.xml=20&=20references=20back?= =?UTF-8?q?=20to=20it=20which=20was=20Legacy=20Controller,=20DialogTask=20?= =?UTF-8?q?etc=F0=9F=94=AA=F0=9F=94=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Umbraco.Core/IO/SystemFiles.cs | 2 - src/Umbraco.Tests/UI/LegacyDialogTests.cs | 34 --- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 - .../src/common/resources/legacy.resource.js | 29 --- .../common/overlays/ysod/ysod.controller.js | 2 +- .../Editors/BackOfficeServerVariables.cs | 6 +- src/Umbraco.Web/Editors/LegacyController.cs | 59 ----- src/Umbraco.Web/Umbraco.Web.csproj | 5 - src/Umbraco.Web/_Legacy/UI/ITask.cs | 18 -- src/Umbraco.Web/_Legacy/UI/ITaskReturnUrl.cs | 10 - .../_Legacy/UI/LegacyDialogHandler.cs | 228 ------------------ .../_Legacy/UI/LegacyDialogTask.cs | 94 -------- 12 files changed, 2 insertions(+), 486 deletions(-) delete mode 100644 src/Umbraco.Tests/UI/LegacyDialogTests.cs delete mode 100644 src/Umbraco.Web.UI.Client/src/common/resources/legacy.resource.js delete mode 100644 src/Umbraco.Web/Editors/LegacyController.cs delete mode 100644 src/Umbraco.Web/_Legacy/UI/ITask.cs delete mode 100644 src/Umbraco.Web/_Legacy/UI/ITaskReturnUrl.cs delete mode 100644 src/Umbraco.Web/_Legacy/UI/LegacyDialogHandler.cs delete mode 100644 src/Umbraco.Web/_Legacy/UI/LegacyDialogTask.cs diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 449d5bdad6..0e5ae8388b 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -7,8 +7,6 @@ namespace Umbraco.Core.IO { public class SystemFiles { - public static string CreateUiXml => SystemDirectories.Umbraco + "/config/create/UI.xml"; - public static string TinyMceConfig => SystemDirectories.Config + "/tinyMceConfig.config"; public static string GetContentCacheXml(IGlobalSettings globalSettings) diff --git a/src/Umbraco.Tests/UI/LegacyDialogTests.cs b/src/Umbraco.Tests/UI/LegacyDialogTests.cs deleted file mode 100644 index 9f1e474bd9..0000000000 --- a/src/Umbraco.Tests/UI/LegacyDialogTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using NUnit.Framework; -using umbraco; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Web; -using Umbraco.Web._Legacy.UI; - -namespace Umbraco.Tests.UI -{ - [TestFixture] - public class LegacyDialogTests - { - - [Test] - public void Ensure_All_Tasks_Are_Secured() - { - var allTasks = TypeFinder.FindClassesOfType(); - - foreach (var t in allTasks) - { - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(t), "The type " + t + " is not of type " + typeof(LegacyDialogTask)); - } - } - - //[TestCase(typeof(macroTasks), Constants.Applications.Settings)] - //public void Check_Assigned_Apps_For_Tasks(Type taskType, string app) - //{ - // var task = (LegacyDialogTask)Activator.CreateInstance(taskType); - // Assert.AreEqual(task.AssignedApp, app); - //} - - } -} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 11f5527a8c..61d0672d7f 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -470,7 +470,6 @@ True TestFiles.resx - diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/legacy.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/legacy.resource.js deleted file mode 100644 index b42d80408f..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/resources/legacy.resource.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @ngdoc service - * @name umbraco.resources.legacyResource - * @description Handles legacy dialog requests - **/ -function legacyResource($q, $http, umbRequestHelper) { - - //the factory object returned - return { - /** Loads in the data to display the section list */ - deleteItem: function (args) { - - if (!args.nodeId || !args.nodeType || !args.alias) { - throw "The args parameter is not formatted correct, it requires properties: nodeId, nodeType, alias"; - } - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "legacyApiBaseUrl", - "DeleteLegacyItem", - [{ nodeId: args.nodeId }, { nodeType: args.nodeType }, { alias: args.alias }])), - 'Failed to delete item ' + args.nodeId); - - } - }; -} - -angular.module('umbraco.resources').factory('legacyResource', legacyResource); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/ysod/ysod.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/ysod/ysod.controller.js index f632547bfc..f3c220075d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/ysod/ysod.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/ysod/ysod.controller.js @@ -1,5 +1,5 @@ angular.module("umbraco") - .controller("Umbraco.Overlays.YsodController", function ($scope, legacyResource, treeService, navigationService, localizationService) { + .controller("Umbraco.Overlays.YsodController", function ($scope, localizationService) { function onInit() { diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index d6a6947eba..14853d97d8 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -183,11 +183,7 @@ namespace Umbraco.Web.Editors { "currentUserApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.PostChangePassword(null)) - }, - { - "legacyApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( - controller => controller.DeleteLegacyItem(null, null, null)) - }, + }, { "entityApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetById(0, UmbracoEntityTypes.Media)) diff --git a/src/Umbraco.Web/Editors/LegacyController.cs b/src/Umbraco.Web/Editors/LegacyController.cs deleted file mode 100644 index e2e22457c1..0000000000 --- a/src/Umbraco.Web/Editors/LegacyController.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Web; -using System.Web.Http; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi.Filters; -using Umbraco.Web._Legacy.UI; - -namespace Umbraco.Web.Editors -{ - /// - /// The API controller used for dealing with legacy content - /// - [PluginController("UmbracoApi")] - [ValidationFilter] - public class LegacyController : UmbracoAuthorizedJsonController - { - /// - /// This will perform the delete operation for legacy items which include any item that - /// has functionality included in the ui.xml structure. - /// - /// - [HttpPost] - public HttpResponseMessage DeleteLegacyItem(string nodeId, string alias, string nodeType) - { - //U4-2686 - alias is html encoded, make sure to decode - alias = HttpUtility.HtmlDecode(alias); - - //In order to process this request we MUST have an HttpContext available - var httpContextAttempt = TryGetHttpContext(); - if (httpContextAttempt.Success) - { - //this is a hack check based on legacy - if (nodeType == "memberGroups") - { - LegacyDialogHandler.Delete(httpContextAttempt.Result, Security.CurrentUser, nodeType, 0, alias); - return Request.CreateResponse(HttpStatusCode.OK); - } - - int id; - if (int.TryParse(nodeId, out id)) - { - LegacyDialogHandler.Delete(httpContextAttempt.Result, Security.CurrentUser, nodeType, id, alias); - return Request.CreateResponse(HttpStatusCode.OK); - } - - //the way this legacy stuff used to work is that if the node id didn't parse, we would - //pass the node id as the alias with an id of zero = sure whatevs. - LegacyDialogHandler.Delete(httpContextAttempt.Result, Security.CurrentUser, nodeType, 0, nodeId); - return Request.CreateResponse(HttpStatusCode.OK); - } - - //We must have an HttpContext available for this to work. - return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, new InvalidOperationException("No HttpContext found in the current request")); - } - - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index ec19acb00d..86772c13c4 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -921,7 +921,6 @@ - @@ -1146,10 +1145,6 @@ - - - - diff --git a/src/Umbraco.Web/_Legacy/UI/ITask.cs b/src/Umbraco.Web/_Legacy/UI/ITask.cs deleted file mode 100644 index 62ce4c92c8..0000000000 --- a/src/Umbraco.Web/_Legacy/UI/ITask.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace Umbraco.Web._Legacy.UI -{ - /// - /// Summary description for ITask. - /// - [Obsolete("ITask is used for legacy webforms back office editors, change to using the v7 angular approach")] - public interface ITask - { - int ParentID {set; get;} - int TypeID {set; get;} - string Alias {set; get;} - bool Save(); - bool Delete(); - int UserId {set;} - } -} diff --git a/src/Umbraco.Web/_Legacy/UI/ITaskReturnUrl.cs b/src/Umbraco.Web/_Legacy/UI/ITaskReturnUrl.cs deleted file mode 100644 index c42ad9dbdb..0000000000 --- a/src/Umbraco.Web/_Legacy/UI/ITaskReturnUrl.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Umbraco.Web._Legacy.UI -{ - [Obsolete("ITask is used for legacy webforms back office editors, change to using the v7 angular approach")] - public interface ITaskReturnUrl : ITask - { - string ReturnUrl {get;} - } -} diff --git a/src/Umbraco.Web/_Legacy/UI/LegacyDialogHandler.cs b/src/Umbraco.Web/_Legacy/UI/LegacyDialogHandler.cs deleted file mode 100644 index cfa93dc0f6..0000000000 --- a/src/Umbraco.Web/_Legacy/UI/LegacyDialogHandler.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Web; -using System.Xml; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Models.Membership; - -namespace Umbraco.Web._Legacy.UI -{ - /// - /// This is used to replace the old umbraco.presentation.create.dialogHandler_temp class which is used - /// to handle sections create/delete actions. - /// - /// - /// We need to overhaul how all of this is handled which is why this is a legacy class - /// http://issues.umbraco.org/issue/U4-1373 - /// - public static class LegacyDialogHandler - { - private enum Operation - { - Create, - Delete - } - - private const string ContextKeyCreate = "LegacyDialogHandler-Create-"; - private const string ContextKeyDelete = "LegacyDialogHandler-Delete-"; - - /// - /// Gets the ITask for the operation for the node Type - /// - /// - /// - /// - /// - /// - /// Returns the ITask if one is found and can be made, otherwise null - /// - /// - /// This will first check if we've already created the ITask in the current Http request - /// - private static ITask GetTaskForOperation(HttpContextBase httpContext, IUser umbracoUser, Operation op, string nodeType) - { - if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); - if (umbracoUser == null) throw new ArgumentNullException(nameof(umbracoUser)); - if (nodeType == null) throw new ArgumentNullException(nameof(nodeType)); - - var ctxKey = op == Operation.Create ? ContextKeyCreate : ContextKeyDelete; - - //check contextual cache - if (httpContext.Items[ctxKey] != null) - { - return (ITask) httpContext.Items[ctxKey]; - } - - var operationNode = op == Operation.Create ? "create" : "delete"; - var createDef = GetXmlDoc(); - var def = createDef.SelectSingleNode("//nodeType [@alias = '" + nodeType + "']"); - if (def == null) - { - return null; - } - var del = def.SelectSingleNode("./tasks/" + operationNode); - if (del == null) - { - return null; - } - if (!del.Attributes.HasAttribute("assembly")) - { - return null; - } - var taskAssembly = del.AttributeValue("assembly"); - - if (!del.Attributes.HasAttribute("type")) - { - return null; - } - var taskType = del.AttributeValue("type"); - - var assembly = Assembly.LoadFrom(IOHelper.MapPath(SystemDirectories.Bin + "/" + taskAssembly + ".dll")); - var type = assembly.GetType(taskAssembly + "." + taskType); - var typeInstance = Activator.CreateInstance(type) as ITask; - if (typeInstance == null) - { - return null; - } - - //set the user/user id for the instance - var dialogTask = typeInstance as LegacyDialogTask; - if (dialogTask != null) - { - dialogTask.User = umbracoUser; - } - else - { - typeInstance.UserId = umbracoUser.Id; - } - - //put in contextual cache - httpContext.Items[ctxKey] = typeInstance; - - return typeInstance; - } - - /// - /// Checks if the user has access to launch the ITask that matches the node type based on the app assigned - /// - /// - /// - /// - /// - /// - /// If the ITask doesn't implement LegacyDialogTask then we will return 'true' since we cannot validate - /// the application assigned. - /// - /// TODO: Create an API to assign a nodeType to an app so developers can manually secure it - /// - internal static bool UserHasCreateAccess(HttpContextBase httpContext, IUser umbracoUser, string nodeType) - { - var task = GetTaskForOperation(httpContext, umbracoUser, Operation.Create, nodeType); - - //if no task was found it will use the default task and we cannot validate the application assigned so return true - if (task == null) - return true; - - return task is LegacyDialogTask ltask ? ltask.ValidateUserForApplication() : true; - } - - /// - /// Checks if the user has access to launch the ITask that matches the node type based on the app assigned - /// - /// - /// - /// - /// - /// - /// If the ITask doesn't implement LegacyDialogTask then we will return 'true' since we cannot validate - /// the application assigned. - /// - /// TODO: Create an API to assign a nodeType to an app so developers can manually secure it - /// - internal static bool UserHasDeleteAccess(HttpContextBase httpContext, User umbracoUser, string nodeType) - { - var task = GetTaskForOperation(httpContext, umbracoUser, Operation.Delete, nodeType); - - //if no task was found it will use the default task and we cannot validate the application assigned so return true - if (task == null) - return true; - - return task is LegacyDialogTask ltask ? ltask.ValidateUserForApplication() : true; - } - - public static void Delete(HttpContextBase httpContext, IUser umbracoUser, string nodeType, int nodeId, string text) - { - var typeInstance = GetTaskForOperation(httpContext, umbracoUser, Operation.Delete, nodeType); - if (typeInstance == null) - throw new InvalidOperationException($"Could not task for operation {Operation.Delete} for node type {nodeType}"); - - typeInstance.ParentID = nodeId; - typeInstance.Alias = text; - - typeInstance.Delete(); - } - - public static string Create(HttpContextBase httpContext, IUser umbracoUser, string nodeType, int nodeId, string text, int typeId = 0) - { - var typeInstance = GetTaskForOperation(httpContext, umbracoUser, Operation.Create, nodeType); - if (typeInstance == null) - throw new InvalidOperationException($"Could not task for operation {Operation.Create} for node type {nodeType}"); - - typeInstance.TypeID = typeId; - typeInstance.ParentID = nodeId; - typeInstance.Alias = text; - - typeInstance.Save(); - - // check for returning url - var returnUrlTask = typeInstance as ITaskReturnUrl; - return returnUrlTask != null - ? returnUrlTask.ReturnUrl - : ""; - } - - internal static string Create(HttpContextBase httpContext, IUser umbracoUser, string nodeType, int nodeId, string text, IDictionary additionalValues, int typeId = 0) - { - var typeInstance = GetTaskForOperation(httpContext, umbracoUser, Operation.Create, nodeType); - if (typeInstance == null) - throw new InvalidOperationException($"Could not task for operation {Operation.Create} for node type {nodeType}"); - - typeInstance.TypeID = typeId; - typeInstance.ParentID = nodeId; - typeInstance.Alias = text; - - // check for returning url - ITaskReturnUrl returnUrlTask = typeInstance as LegacyDialogTask; - if (returnUrlTask != null) - { - // if castable to LegacyDialogTask: add in additionalValues - ((LegacyDialogTask) returnUrlTask).AdditionalValues = additionalValues; - } - else - { - // otherwise cast to returnUrl interface - returnUrlTask = typeInstance as ITaskReturnUrl; - } - - typeInstance.Save(); - - return returnUrlTask != null - ? returnUrlTask.ReturnUrl - : ""; - } - - private static XmlDocument GetXmlDoc() - { - // Load task settings - var createDef = new XmlDocument(); - using (var defReader = new XmlTextReader(IOHelper.MapPath(SystemFiles.CreateUiXml))) - { - createDef.Load(defReader); - defReader.Close(); - return createDef; - } - } - } -} diff --git a/src/Umbraco.Web/_Legacy/UI/LegacyDialogTask.cs b/src/Umbraco.Web/_Legacy/UI/LegacyDialogTask.cs deleted file mode 100644 index 1b040970dd..0000000000 --- a/src/Umbraco.Web/_Legacy/UI/LegacyDialogTask.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Authentication; -using Umbraco.Core; -using Umbraco.Core.Models.Membership; -using Umbraco.Web.Composing; -using Umbraco.Web.UI; - -namespace Umbraco.Web._Legacy.UI -{ - /// - /// An abstract class that is used to implement all secure ITasks - /// - /// - /// In the near future we will overhaul how create dialogs work and how deletions work as well. In the meantime - /// if you ever need to create an ITask you should just inherit from this class and do not manually implement - /// ITask or ITaskReturnUrl. If you do, you MUST also implement IAppTask which associates an ITask to an app - /// so we can validate the current user's security with the implementation. If you do not do this then your - /// implementation will not be secure. It means that if someone is logged in and doesn't have access to a - /// specific app, they'd still be able to execute code to create/delete for any ITask regardless of what app - /// they have access to. - /// - [Obsolete("ITask is used for legacy webforms back office editors, change to using the v7 angular approach")] - public abstract class LegacyDialogTask : ITaskReturnUrl, IAssignedApp - { - public virtual int ParentID { get; set; } - public int TypeID { get; set; } - public string Alias { get; set; } - - /// - /// Base class first performs authentication for the current app before proceeding - /// - /// - public bool Save() - { - if (ValidateUserForApplication()) - { - return PerformSave(); - } - throw new AuthenticationException("The current user does not have access to the required application that this task belongs to"); - } - - public abstract bool PerformSave(); - - /// - /// Base class first performs authentication for the current app before proceeding - /// - /// - public bool Delete() - { - if (ValidateUserForApplication()) - { - return PerformDelete(); - } - throw new AuthenticationException("The current user does not have access to the required application that this task belongs to"); - } - - public abstract bool PerformDelete(); - - /// - /// Gets/sets the user object for this Task - /// - /// - /// accessible by inheritors but can only be set internally - /// - protected internal IUser User { get; internal set; } - - /// - /// Implemented explicitly as we don't want to expose this - /// - int ITask.UserId - { - set { User = Current.Services.UserService.GetUserById(value); } - } - - /// - /// Checks if the currently assigned user has access to the assigned app - /// - /// - protected internal bool ValidateUserForApplication() - { - if (User == null) - throw new InvalidOperationException("Cannot authenticate, no User object assigned"); - - return User.AllowedSections.Any(app => app.InvariantEquals(AssignedApp)); - } - - public abstract string ReturnUrl { get; } - public abstract string AssignedApp { get; } - - public IDictionary AdditionalValues { get; set; } - } -}