Merge branch 'temp8' into feature-angular-stylesheets-editing-in-tabs

This commit is contained in:
Kenn Jacobsen
2018-11-02 08:46:57 +01:00
191 changed files with 2369 additions and 5031 deletions

View File

@@ -0,0 +1,21 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when a domain is being assigned to a document
/// </summary>
public class ActionAssignDomain : IAction
{
public const char ActionLetter = 'I';
public char Letter => ActionLetter;
public string Alias => "assignDomain";
public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory;
public string Icon => "home";
public bool ShowInNotifier => false;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,27 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is used as a security constraint that grants a user the ability to view nodes in a tree
/// that has permissions applied to it.
/// </summary>
/// <remarks>
/// This action should not be invoked. It is used as the minimum required permission to view nodes in the content tree. By
/// granting a user this permission, the user is able to see the node in the tree but not edit the document. This may be used by other trees
/// that support permissions in the future.
/// </remarks>
public class ActionBrowse : IAction
{
public const char ActionLetter = 'F';
public char Letter => ActionLetter;
public bool ShowInNotifier => false;
public bool CanBePermissionAssigned => true;
public string Icon => "";
public string Alias => "browse";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
}
}

View File

@@ -0,0 +1,20 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when the document type of a piece of content is changed
/// </summary>
public class ActionChangeDocType : IAction
{
public char Letter => '7';
public string Alias => "changeDocType";
public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory;
public string Icon => "axis-rotation-2";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -3,8 +3,10 @@ using System.Globalization;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Web._Legacy.Actions
namespace Umbraco.Web.Actions
{
public class ActionCollection : BuilderCollectionBase<IAction>
{
@@ -15,7 +17,7 @@ namespace Umbraco.Web._Legacy.Actions
internal T GetAction<T>()
where T : IAction
{
return this.OfType<T>().SingleOrDefault();
return this.OfType<T>().FirstOrDefault();
}
internal IEnumerable<IAction> GetByLetters(IEnumerable<string> letters)
@@ -25,5 +27,15 @@ namespace Umbraco.Web._Legacy.Actions
.WhereNotNull()
.ToArray();
}
internal IReadOnlyList<IAction> FromEntityPermission(EntityPermission entityPermission)
{
return entityPermission.AssignedPermissions
.Where(x => x.Length == 1)
.Select(x => x.ToCharArray()[0])
.SelectMany(c => this.Where(x => x.Letter == c))
.Where(action => action != null)
.ToList();
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using LightInject;
using Umbraco.Core.Composing;
namespace Umbraco.Web.Actions
{
internal class ActionCollectionBuilder : LazyCollectionBuilderBase<ActionCollectionBuilder, ActionCollection, IAction>
{
public ActionCollectionBuilder(IServiceContainer container)
: base(container)
{ }
protected override ActionCollectionBuilder This => this;
protected override IEnumerable<IAction> CreateItems(params object[] args)
{
var items = base.CreateItems(args).ToList();
//validate the items, no actions should exist that do not either expose notifications or permissions
var invalid = items.Where(x => !x.CanBePermissionAssigned && !x.ShowInNotifier).ToList();
if (invalid.Count > 0)
{
throw new InvalidOperationException($"Invalid actions '{string.Join(", ", invalid.Select(x => x.Alias))}'. All {typeof(IAction)} implementations must be true for either {nameof(IAction.CanBePermissionAssigned)} or {nameof(IAction.ShowInNotifier)}");
}
return items;
}
}
}

View File

@@ -0,0 +1,20 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when copying a document, media, member
/// </summary>
public class ActionCopy : IAction
{
public char Letter => 'O';
public string Alias => "copy";
public string Category => Constants.Conventions.PermissionCategories.StructureCategory;
public string Icon => "documents";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web.Actions
{
public class ActionCreateBlueprintFromContent : IAction
{
public char Letter => 'ï';
public bool ShowInNotifier => false;
public bool CanBePermissionAssigned => true;
public string Icon => "blueprint";
public string Alias => "createblueprint";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
}
}

View File

@@ -0,0 +1,23 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when a document, media, member is deleted
/// </summary>
public class ActionDelete : IAction
{
public const string ActionAlias = "delete";
public const char ActionLetter = 'D';
public char Letter => ActionLetter;
public string Alias => ActionAlias;
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
public string Icon => "delete";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,22 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked upon creation of a document, media, member
/// </summary>
public class ActionMove : IAction
{
public const char ActionLetter = 'M';
public char Letter => ActionLetter;
public string Alias => "move";
public string Category => Constants.Conventions.PermissionCategories.StructureCategory;
public string Icon => "enter";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,23 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked upon creation of a document
/// </summary>
public class ActionNew : IAction
{
public const string ActionAlias = "create";
public const char ActionLetter = 'C';
public char Letter => ActionLetter;
public string Alias => ActionAlias;
public string Icon => "add";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
}
}

View File

@@ -0,0 +1,20 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when a document is protected or unprotected
/// </summary>
public class ActionProtect : IAction
{
public char Letter => 'P';
public string Alias => "protect";
public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory;
public string Icon => "lock";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,21 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when a document is being published
/// </summary>
public class ActionPublish : IAction
{
public const char ActionLetter = 'U';
public char Letter => ActionLetter;
public string Alias => "publish";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
public string Icon => string.Empty;
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,20 @@

namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when the content/media item is to be restored from the recycle bin
/// </summary>
public class ActionRestore : IAction
{
public const string ActionAlias = "restore";
public char Letter => 'V';
public string Alias => ActionAlias;
public string Category => null;
public string Icon => "undo";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => false;
}
}

View File

@@ -0,0 +1,20 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when rights are changed on a document
/// </summary>
public class ActionRights : IAction
{
public char Letter => 'R';
public string Alias => "rights";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
public string Icon => "vcard";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,22 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when copying a document is being rolled back
/// </summary>
public class ActionRollback : IAction
{
public const char ActionLetter = 'K';
public char Letter => ActionLetter;
public string Alias => "rollback";
public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory;
public string Icon => "undo";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,19 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when children to a document, media, member is being sorted
/// </summary>
public class ActionSort : IAction
{
public char Letter => 'S';
public string Alias => "sort";
public string Category => Constants.Conventions.PermissionCategories.StructureCategory;
public string Icon => "navigation-vertical";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,22 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when children to a document is being sent to published (by an editor without publishrights)
/// </summary>
public class ActionToPublish : IAction
{
public const char ActionLetter = 'H';
public char Letter => ActionLetter;
public string Alias => "sendtopublish";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
public string Icon => "outbox";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,21 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when a document is being unpublished
/// </summary>
public class ActionUnpublish : IAction
{
public char Letter => 'Z';
public string Alias => "unpublish";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
public string Icon => "circle-dotted";
public bool ShowInNotifier => false;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,22 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.Actions
{
/// <summary>
/// This action is invoked when copying a document or media
/// </summary>
public class ActionUpdate : IAction
{
public const char ActionLetter = 'A';
public char Letter => ActionLetter;
public string Alias => "update";
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
public string Icon => "save";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => true;
}
}

View File

@@ -0,0 +1,46 @@
using Umbraco.Core.Composing;
namespace Umbraco.Web.Actions
{
/// <summary>
/// Defines a back office action that can be permission assigned or subscribed to for notifications
/// </summary>
/// <remarks>
/// If an IAction returns false for both ShowInNotifier and CanBePermissionAssigned then the IAction should not exist
/// </remarks>
public interface IAction : IDiscoverable
{
/// <summary>
/// The letter used to assign a permission (must be unique)
/// </summary>
char Letter { get; }
/// <summary>
/// Whether to allow subscribing to notifications for this action
/// </summary>
bool ShowInNotifier { get; }
/// <summary>
/// Whether to allow assigning permissions based on this action
/// </summary>
bool CanBePermissionAssigned { get; }
/// <summary>
/// The icon to display for this action
/// </summary>
string Icon { get; }
/// <summary>
/// The alias for this action (must be unique)
/// </summary>
string Alias { get; }
/// <summary>
/// The category used for this action
/// </summary>
/// <remarks>
/// Used in the UI when assigning permissions
/// </remarks>
string Category { get; }
}
}

View File

@@ -5,23 +5,24 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
namespace Umbraco.Web.Components
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public sealed class NotificationsComponent : UmbracoComponentBase, IUmbracoCoreComponent
{
public void Initialize(INotificationService notificationService)
public void Initialize(INotificationService notificationService, ActionCollection actions)
{
ContentService.SentToPublish += (sender, args) =>
notificationService.SendNotification(args.Entity, ActionToPublish.Instance);
notificationService.SendNotification(args.Entity, actions.GetAction<ActionToPublish>());
//Send notifications for the published action
ContentService.Published += (sender, args) =>
{
foreach (var content in args.PublishedEntities)
notificationService.SendNotification(content, ActionPublish.Instance);
notificationService.SendNotification(content, actions.GetAction<ActionToPublish>());
};
//Send notifications for the update and created actions
@@ -45,22 +46,22 @@ namespace Umbraco.Web.Components
updatedEntities.Add(entity);
}
}
notificationService.SendNotification(newEntities, ActionNew.Instance);
notificationService.SendNotification(updatedEntities, ActionUpdate.Instance);
notificationService.SendNotification(newEntities, actions.GetAction<ActionNew>());
notificationService.SendNotification(updatedEntities, actions.GetAction<ActionUpdate>());
};
//Send notifications for the delete action
ContentService.Deleted += (sender, args) =>
{
foreach (var content in args.DeletedEntities)
notificationService.SendNotification(content, ActionDelete.Instance);
notificationService.SendNotification(content, actions.GetAction<ActionDelete>());
};
//Send notifications for the unpublish action
ContentService.Unpublished += (sender, args) =>
{
foreach (var content in args.PublishedEntities)
notificationService.SendNotification(content, ActionUnpublish.Instance);
notificationService.SendNotification(content, actions.GetAction<ActionUnpublish>());
};
}
}

View File

@@ -19,6 +19,7 @@ using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Core._Legacy.PackageActions;
using Umbraco.Web.Actions;
using Umbraco.Web.Cache;
using Umbraco.Web.Editors;
using Umbraco.Web.HealthCheck;
@@ -27,7 +28,7 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.WebApi;
using Umbraco.Web._Legacy.Actions;
using CoreCurrent = Umbraco.Core.Composing.Current;
namespace Umbraco.Web.Composing

View File

@@ -3,13 +3,13 @@ using LightInject;
using Umbraco.Core.Composing;
using Current = Umbraco.Web.Composing.Current;
using Umbraco.Core.Macros;
using Umbraco.Web.Actions;
using Umbraco.Web.Editors;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Media;
using Umbraco.Web.Mvc;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.ContentApps;
// the namespace here is intentional - although defined in Umbraco.Web assembly,

View File

@@ -3,18 +3,15 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using LightInject;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
@@ -22,18 +19,13 @@ using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.Trees;
using Umbraco.Web.UI.JavaScript;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Features;
using Umbraco.Web.Security;
using Action = Umbraco.Web._Legacy.Actions.Action;
using Constants = Umbraco.Core.Constants;
using JArray = Newtonsoft.Json.Linq.JArray;
@@ -197,11 +189,8 @@ namespace Umbraco.Web.Editors
{
var initJs = new JsInitialization(_manifestParser);
var initCss = new CssInitialization(_manifestParser);
//get the legacy ActionJs file references to append as well
var legacyActionJsRef = GetLegacyActionJs(LegacyJsActionType.JsUrl);
var files = initJs.OptimizeBackOfficeScriptFiles(HttpContext, JsInitialization.GetDefaultInitialization(), legacyActionJsRef);
var files = initJs.OptimizeBackOfficeScriptFiles(HttpContext, JsInitialization.GetDefaultInitialization());
var result = JsInitialization.GetJavascriptInitialization(HttpContext, files, "umbraco");
result += initCss.GetStylesheetInitialization(HttpContext);
@@ -519,50 +508,7 @@ namespace Umbraco.Web.Editors
}
return true;
}
internal static IEnumerable<string> GetLegacyActionJsForActions(LegacyJsActionType type, IEnumerable<string> values)
{
var blockList = new List<string>();
var urlList = new List<string>();
foreach (var jsFile in values)
{
var isJsPath = jsFile.DetectIsJavaScriptPath();
if (isJsPath.Success)
{
urlList.Add(isJsPath.Result);
}
else
{
blockList.Add(isJsPath.Result);
}
}
switch (type)
{
case LegacyJsActionType.JsBlock:
return blockList;
case LegacyJsActionType.JsUrl:
return urlList;
}
return blockList;
}
/// <summary>
/// Renders out all JavaScript references that have been declared in IActions
/// </summary>
private static IEnumerable<string> GetLegacyActionJs(LegacyJsActionType type)
{
return GetLegacyActionJsForActions(type, Action.GetJavaScriptFileReferences());
}
internal enum LegacyJsActionType
{
JsBlock,
JsUrl
}
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))

View File

@@ -30,10 +30,11 @@ using Umbraco.Core.Models.Validation;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
using Umbraco.Web.WebServices;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
using Language = Umbraco.Web.Models.ContentEditing.Language;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Actions;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Editors.Binders;
using Umbraco.Web.Editors.Filters;
@@ -456,7 +457,7 @@ namespace Umbraco.Web.Editors
public PagedResult<ContentItemBasic<ContentPropertyBasic>> GetChildren(
int id,
string includeProperties,
int pageNumber = 0, //TODO: This should be '1' as it's not the index
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
@@ -483,7 +484,8 @@ namespace Umbraco.Web.Editors
}
else
{
children = Services.ContentService.GetChildren(id).ToList();
//better to not use this without paging where possible, currently only the sort dialog does
children = Services.ContentService.GetPagedChildren(id, 0, int.MaxValue, out var total).ToList();
totalChildren = children.Count;
}
@@ -931,14 +933,14 @@ namespace Umbraco.Web.Editors
var errMsg = Services.TextService.Localize(localizationKey, new[] { _allLangs.Value[culture].CultureName });
ModelState.AddModelError(key, errMsg);
}
/// <summary>
/// Publishes a document with a given ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <remarks>
/// The CanAccessContentAuthorize attribute will deny access to this method if the current user
/// The EnsureUserPermissionForContent attribute will deny access to this method if the current user
/// does not have Publish access to this node.
/// </remarks>
///
@@ -1076,7 +1078,7 @@ namespace Umbraco.Web.Editors
if (sorted.ParentId > 0)
{
Services.NotificationService.SendNotification(contentService.GetById(sorted.ParentId), ActionSort.Instance, UmbracoContext, Services.TextService, GlobalSettings);
Services.NotificationService.SendNotification(contentService.GetById(sorted.ParentId), Current.Actions.GetAction<ActionSort>(), UmbracoContext, Services.TextService, GlobalSettings);
}
return Request.CreateResponse(HttpStatusCode.OK);
@@ -1223,7 +1225,7 @@ namespace Umbraco.Web.Editors
var permission = Services.UserService.GetPermissions(Security.CurrentUser, node.Path);
if (permission.AssignedPermissions.Contains(ActionAssignDomain.Instance.Letter.ToString(), StringComparer.Ordinal) == false)
if (permission.AssignedPermissions.Contains(ActionAssignDomain.ActionLetter.ToString(), StringComparer.Ordinal) == false)
{
var response = Request.CreateResponse(HttpStatusCode.BadRequest);
response.Content = new StringContent("You do not have permission to assign domains on that node.");
@@ -1317,7 +1319,7 @@ namespace Umbraco.Web.Editors
xnames.Add(xcontent.Name);
if (xcontent.ParentId < -1)
xnames.Add("Recycle Bin");
xcontent = xcontent.Parent(Services.ContentService);
xcontent = Services.ContentService.GetParent(xcontent);
}
xnames.Reverse();
domainModel.Other = "/" + string.Join("/", xnames);
@@ -1760,6 +1762,7 @@ namespace Umbraco.Web.Editors
: content.Variants.FirstOrDefault(x => x.Language.IsoCode == culture);
}
[EnsureUserPermissionForContent("contentId", ActionRollback.ActionLetter)]
[HttpPost]
public HttpResponseMessage PostRollbackContent(int contentId, int versionId, string culture = "*")
{

View File

@@ -9,11 +9,12 @@ using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Security;
using Umbraco.Web.WebApi;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Editors.Filters
{
@@ -94,24 +95,24 @@ namespace Umbraco.Web.Editors.Filters
switch (contentItem.Action)
{
case ContentSaveAction.Save:
permissionToCheck.Add(ActionUpdate.Instance.Letter);
permissionToCheck.Add(ActionUpdate.ActionLetter);
contentToCheck = contentItem.PersistedContent;
contentIdToCheck = contentToCheck.Id;
break;
case ContentSaveAction.Publish:
permissionToCheck.Add(ActionPublish.Instance.Letter);
permissionToCheck.Add(ActionPublish.ActionLetter);
contentToCheck = contentItem.PersistedContent;
contentIdToCheck = contentToCheck.Id;
break;
case ContentSaveAction.SendPublish:
permissionToCheck.Add(ActionToPublish.Instance.Letter);
permissionToCheck.Add(ActionToPublish.ActionLetter);
contentToCheck = contentItem.PersistedContent;
contentIdToCheck = contentToCheck.Id;
break;
case ContentSaveAction.SaveNew:
//Save new requires ActionNew
permissionToCheck.Add(ActionNew.Instance.Letter);
permissionToCheck.Add(ActionNew.ActionLetter);
if (contentItem.ParentId != Constants.System.Root)
{
@@ -126,8 +127,8 @@ namespace Umbraco.Web.Editors.Filters
case ContentSaveAction.SendPublishNew:
//Send new requires both ActionToPublish AND ActionNew
permissionToCheck.Add(ActionNew.Instance.Letter);
permissionToCheck.Add(ActionToPublish.Instance.Letter);
permissionToCheck.Add(ActionNew.ActionLetter);
permissionToCheck.Add(ActionToPublish.ActionLetter);
if (contentItem.ParentId != Constants.System.Root)
{
contentToCheck = _contentService.GetById(contentItem.ParentId);
@@ -142,8 +143,8 @@ namespace Umbraco.Web.Editors.Filters
//Publish new requires both ActionNew AND ActionPublish
//TODO: Shoudn't publish also require ActionUpdate since it will definitely perform an update to publish but maybe that's just implied
permissionToCheck.Add(ActionNew.Instance.Letter);
permissionToCheck.Add(ActionPublish.Instance.Letter);
permissionToCheck.Add(ActionNew.ActionLetter);
permissionToCheck.Add(ActionPublish.ActionLetter);
if (contentItem.ParentId != Constants.System.Root)
{

View File

@@ -209,7 +209,10 @@ namespace Umbraco.Web.Editors
}
long total;
var children = Services.MediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total, "Name", Direction.Ascending, true, null, folderTypes.ToArray());
var children = Services.MediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total,
//lookup these content types
SqlContext.Query<IMedia>().Where(x => folderTypes.Contains(x.ContentTypeId)),
Ordering.By("Name", Direction.Ascending));
return new PagedResult<ContentItemBasic<ContentPropertyBasic>>(total, pageNumber, pageSize)
{
@@ -271,7 +274,7 @@ namespace Umbraco.Web.Editors
// else proceed as usual
long totalChildren;
IMedia[] children;
List<IMedia> children;
if (pageNumber > 0 && pageSize > 0)
{
IQuery<IMedia> queryFilter = null;
@@ -286,13 +289,14 @@ namespace Umbraco.Web.Editors
.GetPagedChildren(
id, (pageNumber - 1), pageSize,
out totalChildren,
orderBy, orderDirection, orderBySystemField,
queryFilter).ToArray();
queryFilter,
Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField)).ToList();
}
else
{
children = Services.MediaService.GetChildren(id).ToArray();
totalChildren = children.Length;
//better to not use this without paging where possible, currently only the sort dialog does
children = Services.MediaService.GetPagedChildren(id, 0, int.MaxValue, out var total).ToList();
totalChildren = children.Count;
}
if (totalChildren == 0)
@@ -663,7 +667,8 @@ namespace Umbraco.Web.Editors
" returned null");
//look for matching folder
folderMediaItem = mediaRoot.Children(Services.MediaService).FirstOrDefault(x => x.Name == folderName && x.ContentType.Alias == Constants.Conventions.MediaTypes.Folder);
folderMediaItem = FindInChildren(mediaRoot.Id, folderName, Constants.Conventions.MediaTypes.Folder);
if (folderMediaItem == null)
{
//if null, create a folder
@@ -753,6 +758,21 @@ namespace Umbraco.Web.Editors
return Request.CreateResponse(HttpStatusCode.OK, tempFiles);
}
private IMedia FindInChildren(int mediaId, string nameToFind, string contentTypeAlias)
{
const int pageSize = 500;
var page = 0;
var total = long.MaxValue;
while (page * pageSize < total)
{
var children = Services.MediaService.GetPagedChildren(mediaId, page, pageSize, out total,
SqlContext.Query<IMedia>().Where(x => x.Name == nameToFind));
foreach (var c in children)
return c; //return first one if any are found
}
return null;
}
/// <summary>
/// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT
/// </summary>

View File

@@ -52,6 +52,18 @@ namespace Umbraco.Web.Models.Mapping
variant.Name = source.GetCultureName(x.IsoCode);
}
//Put the default language first in the list & then sort rest by a-z
var defaultLang = variants.SingleOrDefault(x => x.Language.IsDefault);
//Remove the default lang from the list for now
variants.Remove(defaultLang);
//Sort the remaining languages a-z
variants = variants.OrderBy(x => x.Name).ToList();
//Insert the default lang as the first item
variants.Insert(0, defaultLang);
return variants;
}
return result;

View File

@@ -28,7 +28,21 @@ namespace Umbraco.Web.Models.Mapping
{
public IEnumerable<Language> Convert(IEnumerable<ILanguage> source, IEnumerable<Language> destination, ResolutionContext context)
{
return source.Select(x => context.Mapper.Map<ILanguage, Language>(x, null, context)).OrderBy(x => x.Name);
var langs = source.Select(x => context.Mapper.Map<ILanguage, Language>(x, null, context)).ToList();
//Put the default language first in the list & then sort rest by a-z
var defaultLang = langs.SingleOrDefault(x => x.IsDefault);
//Remove the default lang from the list for now
langs.Remove(defaultLang);
//Sort the remaining languages a-z
langs = langs.OrderBy(x => x.Name).ToList();
//Insert the default lang as the first item
langs.Insert(0, defaultLang);
return langs;
}
}
}

View File

@@ -6,8 +6,9 @@ using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Models.Mapping
{
@@ -37,13 +38,11 @@ namespace Umbraco.Web.Models.Mapping
private Permission GetPermission(IAction action, IUserGroup source)
{
var result = new Permission();
var attribute = action.GetType().GetCustomAttribute<ActionMetadataAttribute>(false);
result.Category = attribute == null
result.Category = action.Category.IsNullOrWhiteSpace()
? _textService.Localize($"actionCategories/{Constants.Conventions.PermissionCategories.OtherCategory}")
: _textService.Localize($"actionCategories/{attribute.Category}");
result.Name = attribute == null || attribute.Name.IsNullOrWhiteSpace()
? _textService.Localize($"actions/{action.Alias}")
: attribute.Name;
: _textService.Localize($"actionCategories/{action.Category}");
result.Name = _textService.Localize($"actions/{action.Alias}");
result.Description = _textService.Localize($"actionDescriptions/{action.Alias}");
result.Icon = action.Icon;
result.Checked = source.Permissions != null && source.Permissions.Contains(action.Letter.ToString(CultureInfo.InvariantCulture));

View File

@@ -11,7 +11,8 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
namespace Umbraco.Web.Models.Mapping
{

View File

@@ -1,41 +1,55 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// A menu item that represents some JS that needs to execute when the menu item is clicked.
/// </summary>
/// <remarks>
/// These types of menu items are rare but they do exist. Things like refresh node simply execute
/// JS and don't launch a dialog.
///
/// Each action menu item describes what angular service that it's method exists in and what the method name is.
///
/// An action menu item must describe the angular service name for which it's method exists. It may also define what the
/// method name is that will be called in this service but if one is not specified then we will assume the method name is the
/// same as the Type name of the current action menu class.
/// </remarks>
/// <inheritdoc />
/// <summary>
/// A menu item that represents some JS that needs to execute when the menu item is clicked.
/// </summary>
/// <remarks>
/// These types of menu items are rare but they do exist. Things like refresh node simply execute
/// JS and don't launch a dialog.
/// Each action menu item describes what angular service that it's method exists in and what the method name is.
/// An action menu item must describe the angular service name for which it's method exists. It may also define what the
/// method name is that will be called in this service but if one is not specified then we will assume the method name is the
/// same as the Type name of the current action menu class.
/// </remarks>
public abstract class ActionMenuItem : MenuItem
{
protected ActionMenuItem()
: base()
{
var attribute = GetType().GetCustomAttribute<ActionMenuItemAttribute>(false);
if (attribute == null)
{
throw new InvalidOperationException("All " + typeof (ActionMenuItem).FullName + " instances must be attributed with " + typeof (ActionMenuItemAttribute).FullName);
}
/// <summary>
/// The angular service name containing the <see cref="AngularServiceMethodName"/>
/// </summary>
public abstract string AngularServiceName { get; }
/// <summary>
/// The angular service method name to call for this menu item
/// </summary>
public virtual string AngularServiceMethodName { get; } = null;
protected ActionMenuItem(string alias, string name) : base(alias, name)
{
Initialize();
}
protected ActionMenuItem(string alias, ILocalizedTextService textService) : base(alias, textService)
{
Initialize();
}
private void Initialize()
{
//add the current type to the metadata
if (attribute.MethodName.IsNullOrWhiteSpace())
if (AngularServiceMethodName.IsNullOrWhiteSpace())
{
//if no method name is supplied we will assume that the menu action is the type name of the current menu class
AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, this.GetType().Name));
ExecuteJsMethod($"{AngularServiceName}.{this.GetType().Name}");
}
else
{
AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, attribute.MethodName));
ExecuteJsMethod($"{AngularServiceName}.{AngularServiceMethodName}");
}
}
}

View File

@@ -1,39 +0,0 @@
using System;
using Umbraco.Core.Exceptions;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// The attribute to assign to any ActionMenuItem objects.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class ActionMenuItemAttribute : Attribute
{
/// <summary>
/// This constructor defines both the angular service and method name to use
/// </summary>
/// <param name="serviceName"></param>
/// <param name="methodName"></param>
public ActionMenuItemAttribute(string serviceName, string methodName)
{
if (string.IsNullOrWhiteSpace(serviceName)) throw new ArgumentNullOrEmptyException(nameof(serviceName));
if (string.IsNullOrWhiteSpace(methodName)) throw new ArgumentNullOrEmptyException(nameof(methodName));
MethodName = methodName;
ServiceName = serviceName;
}
/// <summary>
/// This constructor will assume that the method name equals the type name of the action menu class
/// </summary>
/// <param name="serviceName"></param>
public ActionMenuItemAttribute(string serviceName)
{
if (string.IsNullOrWhiteSpace(serviceName)) throw new ArgumentNullOrEmptyException(nameof(serviceName));
MethodName = "";
ServiceName = serviceName;
}
public string MethodName { get; }
public string ServiceName { get; }
}
}

View File

@@ -1,10 +1,27 @@
namespace Umbraco.Web.Models.Trees
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// Represents the refresh node menu item
/// </summary>
[ActionMenuItem("umbracoMenuActions")]
public sealed class CreateChildEntity : ActionMenuItem
{
public override string AngularServiceName => "umbracoMenuActions";
public CreateChildEntity(string name, bool seperatorBefore = false)
: base(ActionNew.ActionAlias, name)
{
Icon = "add"; Name = name;
SeperatorBefore = seperatorBefore;
}
public CreateChildEntity(ILocalizedTextService textService, bool seperatorBefore = false)
: base(ActionNew.ActionAlias, textService)
{
Icon = "add";
SeperatorBefore = seperatorBefore;
}
}
}

View File

@@ -1,15 +0,0 @@
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// Represents the disable user menu item
/// </summary>
[ActionMenuItem("umbracoMenuActions")]
public sealed class DisableUser : ActionMenuItem
{
public DisableUser()
{
Alias = "disable";
Icon = "remove";
}
}
}

View File

@@ -1,9 +1,17 @@
namespace Umbraco.Web.Models.Trees
using Umbraco.Core.Services;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// Represents the export member menu item
/// </summary>
[ActionMenuItem("umbracoMenuActions")]
public sealed class ExportMember : ActionMenuItem
{ }
{
public override string AngularServiceName => "umbracoMenuActions";
public ExportMember(ILocalizedTextService textService) : base("export", textService)
{
Icon = "download-alt";
}
}
}

View File

@@ -5,8 +5,9 @@ using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Models.Trees
{
@@ -30,15 +31,27 @@ namespace Umbraco.Web.Models.Trees
Name = name;
}
public MenuItem(IAction legacyMenu, string name = "")
public MenuItem(string alias, ILocalizedTextService textService)
: this()
{
Name = name.IsNullOrWhiteSpace() ? legacyMenu.Alias : name;
Alias = legacyMenu.Alias;
Alias = alias;
Name = textService.Localize($"actions/{Alias}");
}
/// <summary>
/// Create a menu item based on an <see cref="IAction"/> definition
/// </summary>
/// <param name="action"></param>
/// <param name="name"></param>
public MenuItem(IAction action, string name = "")
: this()
{
Name = name.IsNullOrWhiteSpace() ? action.Alias : name;
Alias = action.Alias;
SeperatorBefore = false;
Icon = legacyMenu.Icon;
Action = legacyMenu;
OpensDialog = legacyMenu.OpensDialog;
Icon = action.Icon;
Action = action;
}
#endregion
@@ -73,6 +86,9 @@ namespace Umbraco.Web.Models.Trees
[DataMember(Name = "cssclass")]
public string Icon { get; set; }
/// <summary>
/// Used in the UI to inform the user that the menu item will open a dialog/confirmation
/// </summary>
[DataMember(Name = "opensDialog")]
public bool OpensDialog { get; set; }
@@ -128,7 +144,7 @@ namespace Umbraco.Web.Models.Trees
/// Adds the required meta data to the menu item so that angular knows to attempt to call the Js method.
/// </summary>
/// <param name="jsToExecute"></param>
public void ExecuteLegacyJs(string jsToExecute)
public void ExecuteJsMethod(string jsToExecute)
{
SetJsAction(jsToExecute);
}
@@ -206,7 +222,7 @@ namespace Umbraco.Web.Models.Trees
}
}
}
#endregion
}

View File

@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Models.Trees
{
@@ -24,7 +26,7 @@ namespace Umbraco.Web.Models.Trees
}
/// <summary>
/// Adds a menu item
/// Adds a menu item based on a <see cref="IAction"/>
/// </summary>
/// <param name="action"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
@@ -32,78 +34,20 @@ namespace Umbraco.Web.Models.Trees
{
var item = new MenuItem(action, name);
DetectLegacyActionMenu(action.GetType(), item);
Add(item);
return item;
}
/// <summary>
/// Adds a menu item
/// </summary>
/// <typeparam name="TMenuItem"></typeparam>
/// <typeparam name="TAction"></typeparam>
/// <param name="hasSeparator"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="additionalData"></param>
/// <returns></returns>
public TMenuItem Add<TMenuItem, TAction>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
where TAction : IAction
where TMenuItem : MenuItem, new()
{
var item = CreateMenuItem<TAction>(name, hasSeparator, additionalData);
if (item == null) return null;
var customMenuItem = new TMenuItem
{
Name = item.Name,
Alias = item.Alias,
SeperatorBefore = hasSeparator,
Icon = item.Icon,
Action = item.Action
};
Add(customMenuItem);
return customMenuItem;
}
/// <summary>
/// Adds a menu item
/// </summary>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <typeparam name="T"></typeparam>
public MenuItem Add<T>(string name)
where T : IAction
{
return Add<T>(name, false, null);
}
/// <summary>
/// Adds a menu item with a key value pair which is merged to the AdditionalData bag
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="hasSeparator"></param>
public MenuItem Add<T>(string name, string key, string value, bool hasSeparator = false)
where T : IAction
{
return Add<T>(name, hasSeparator, new Dictionary<string, object> { { key, value } });
}
/// <summary>
/// Adds a menu item with a dictionary which is merged to the AdditionalData bag
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hasSeparator"></param>
/// /// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="additionalData"></param>
public MenuItem Add<T>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
public MenuItem Add<T>(string name, bool hasSeparator = false)
where T : IAction
{
var item = CreateMenuItem<T>(name, hasSeparator, additionalData);
var item = CreateMenuItem<T>(name, hasSeparator);
if (item != null)
{
Add(item);
@@ -113,69 +57,51 @@ namespace Umbraco.Web.Models.Trees
}
/// <summary>
///
/// Adds a menu item with a dictionary which is merged to the AdditionalData bag
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hasSeparator"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="additionalData"></param>
/// <returns></returns>
internal MenuItem CreateMenuItem<T>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
/// <param name="textService">The <see cref="ILocalizedTextService"/> used to localize the action name based on it's alias</param>
/// <param name="opensDialog"></param>
public MenuItem Add<T>(ILocalizedTextService textService, bool hasSeparator = false, bool opensDialog = false)
where T : IAction
{
var item = Current.Actions.GetAction<T>();
var item = CreateMenuItem<T>(textService, hasSeparator);
if (item != null)
{
var menuItem = new MenuItem(item, name)
{
SeperatorBefore = hasSeparator
};
if (additionalData != null)
{
foreach (var i in additionalData)
{
menuItem.AdditionalData[i.Key] = i.Value;
}
}
DetectLegacyActionMenu(typeof(T), menuItem);
//TODO: Once we implement 'real' menu items, not just IActions we can implement this since
// people may need to pass specific data to their menu items
////validate the data in the meta data bag
//item.ValidateRequiredData(AdditionalData);
return menuItem;
Add(item);
return item;
}
return null;
}
/// <summary>
/// Checks if the IAction type passed in is attributed with LegacyActionMenuItemAttribute and if so
/// ensures that the correct action metadata is added.
/// </summary>
/// <param name="actionType"></param>
/// <param name="menuItem"></param>
private void DetectLegacyActionMenu(Type actionType, MenuItem menuItem)
internal MenuItem CreateMenuItem<T>(string name, bool hasSeparator = false)
where T : IAction
{
//This checks for legacy IActions that have the LegacyActionMenuItemAttribute which is a legacy hack
// to make old IAction actions work in v7 by mapping to the JS used by the new menu items
var attribute = actionType.GetCustomAttribute<LegacyActionMenuItemAttribute>(false);
if (attribute != null)
var item = Current.Actions.GetAction<T>();
if (item == null) return null;
var menuItem = new MenuItem(item, name)
{
//add the current type to the metadata
if (attribute.MethodName.IsNullOrWhiteSpace())
{
//if no method name is supplied we will assume that the menu action is the type name of the current menu class
menuItem.AdditionalData.Add(MenuItem.JsActionKey, string.Format("{0}.{1}", attribute.ServiceName, this.GetType().Name));
}
else
{
menuItem.AdditionalData.Add(MenuItem.JsActionKey, string.Format("{0}.{1}", attribute.ServiceName, attribute.MethodName));
}
}
SeperatorBefore = hasSeparator
};
return menuItem;
}
internal MenuItem CreateMenuItem<T>(ILocalizedTextService textService, bool hasSeparator = false, bool opensDialog = false)
where T : IAction
{
var item = Current.Actions.GetAction<T>();
if (item == null) return null;
var menuItem = new MenuItem(item, textService.Localize($"actions/{item.Alias}"))
{
SeperatorBefore = hasSeparator,
OpensDialog = opensDialog
};
return menuItem;
}
}
}

View File

@@ -1,10 +1,27 @@
namespace Umbraco.Web.Models.Trees
using Umbraco.Core.Services;
namespace Umbraco.Web.Models.Trees
{
/// <inheritdoc />
/// <summary>
/// Represents the refresh node menu item
/// </summary>
[ActionMenuItem("umbracoMenuActions")]
public sealed class RefreshNode : ActionMenuItem
{
public override string AngularServiceName => "umbracoMenuActions";
public RefreshNode(string name, bool seperatorBefore = false)
: base("refreshNode", name)
{
Icon = "refresh";
SeperatorBefore = seperatorBefore;
}
public RefreshNode(ILocalizedTextService textService, bool seperatorBefore = false)
: base("refreshNode", textService)
{
Icon = "refresh";
SeperatorBefore = seperatorBefore;
}
}
}

View File

@@ -6,9 +6,10 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Core.Models;
using Umbraco.Web._Legacy.Actions;
using System.Collections.Generic;
using Umbraco.Core.Models.Entities;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
namespace Umbraco.Web

View File

@@ -31,6 +31,6 @@ namespace Umbraco.Web.PropertyEditors
protected override IConfigurationEditor CreateConfigurationEditor() => new ValueListConfigurationEditor(_textService);
/// <inheritdoc />
protected override IDataValueEditor CreateValueEditor() => new PublishValuesMultipleValueEditor(false, Attribute);
protected override IDataValueEditor CreateValueEditor() => new PublishValuesMultipleValueEditor(Logger, Attribute);
}
}

View File

@@ -18,7 +18,7 @@ namespace Umbraco.Web.PropertyEditors
protected override IDataValueEditor CreateValueEditor()
{
return new PublishValuesMultipleValueEditor(false, Attribute);
return new PublishValuesMultipleValueEditor(Logger, Attribute);
}
protected override IConfigurationEditor CreateConfigurationEditor() => new DropDownFlexibleConfigurationEditor(_textService);

View File

@@ -1,73 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Represents a configuration editor for the "drop down list multiple" property editor.
/// </summary>
/// <remarks>
/// <para>Ensures that 'multiple' is saved for the config in the db but is not a configuration field.</para>
/// <para>This is mostly to maintain backwards compatibility with old property editors. Devs can now simply
/// use the "drop down" property editor and check the "multiple" configuration checkbox</para>
/// <para>fixme what is multiple exactly?!</para>
/// </remarks>
internal class DropDownMultipleConfigurationEditor : ValueListConfigurationEditor
{
public DropDownMultipleConfigurationEditor(ILocalizedTextService textService)
: base(textService)
{
Fields.Add(new ConfigurationField
{
Key = "multiple",
Name = "multiple",
View = "hidden", // so it does not show in the configuration editor
HideLabel = true
});
}
// editor...
//
// receives:
// "preValues":[
// {
// "label":"Add prevalue",
// "description":"Add and remove values for the list",
// "hideLabel":false,
// "view":"multivalues",
// "config":{},
// "key":"items",
// "value":{"169":{"value":"a","sortOrder":1},"170":{"value":"b","sortOrder":2},"171":{"value":"c","sortOrder":3}}
// },
// {
// "label":"multiple",
// "description":null,
// "hideLabel":true,
// "view":"hidden",
// "config":{},
// "key":"multiple",
// "value":"1"
// }]
//
// posts ('d' being a new value):
// [{key: "items", value: [{value: "a", sortOrder: 1, id: "169"}, {value: "c", sortOrder: 3, id: "171"}, {value: "d"}]}, {key: "multiple", value: "1"}]
//
// the 'multiple' thing never goes to DB
// values go to DB with alias 0, 1, 2 + their ID + value
// the sort order that comes back makes no sense
//
// FromEditor can totally ignore 'multiple'
/// <inheritdoc/>
public override Dictionary<string, object> ToConfigurationEditor(ValueListConfiguration configuration)
{
var dictionary = base.ToConfigurationEditor(configuration);
// always add the multiple field, as 'true'
dictionary["multiple"] = 1;
return dictionary;
}
}
}

View File

@@ -1,30 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// A property editor to allow multiple selection of pre-defined items
/// </summary>
/// <remarks>
/// Due to maintaining backwards compatibility this data type stores the value as a string which is a comma separated value of the
/// ids of the individual items so we have logic in here to deal with that.
/// </remarks>
[DataEditor(Constants.PropertyEditors.Aliases.DropDownListMultiple, "Dropdown list multiple", "dropdown", Group = "lists", Icon="icon-bulleted-list", IsDeprecated = true)]
public class DropDownMultiplePropertyEditor : DropDownMultipleWithKeysPropertyEditor
{
/// <summary>
/// The constructor will setup the property editor based on the attribute if one is found
/// </summary>
public DropDownMultiplePropertyEditor(ILogger logger, ILocalizedTextService textService)
: base(logger, textService)
{ }
/// <inheritdoc />
protected override IDataValueEditor CreateValueEditor() => new PublishValuesMultipleValueEditor(false, Attribute);
}
}

View File

@@ -1,37 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Represents a property editor that allows multiple selection of pre-defined items.
/// </summary>
/// <remarks>
/// Due to backwards compatibility, this editor stores the value as a CSV string listing
/// the ids of individual items.
/// </remarks>
[DataEditor(Constants.PropertyEditors.Aliases.DropdownlistMultiplePublishKeys, "Dropdown list multiple, publish keys", "dropdown", Group = "lists", Icon = "icon-bulleted-list", IsDeprecated = true)]
public class DropDownMultipleWithKeysPropertyEditor : DropDownPropertyEditor
{
private readonly ILocalizedTextService _textService;
/// <summary>
/// Initializes a new instance of the <see cref="DropDownMultiplePropertyEditor"/> class.
/// </summary>
public DropDownMultipleWithKeysPropertyEditor(ILogger logger, ILocalizedTextService textService)
: base(logger, textService)
{
_textService = textService;
}
/// <inheritdoc />
protected override IDataValueEditor CreateValueEditor() => new PublishValuesMultipleValueEditor(true, Attribute);
/// <inheritdoc />
protected override IConfigurationEditor CreateConfigurationEditor() => new DropDownMultipleConfigurationEditor(_textService);
}
}

View File

@@ -1,37 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
using umbraco;
using ClientDependency.Core;
using Umbraco.Core.Services;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// A property editor to allow the individual selection of pre-defined items.
/// </summary>
/// <remarks>
/// Due to remaining backwards compatible, this stores the id of the drop down item in the database which is why it is marked
/// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the string value is published
/// in cache and not the int ID.
/// </remarks>
[DataEditor(Constants.PropertyEditors.Aliases.DropDownList, "Dropdown list", "dropdown", ValueType = ValueTypes.String, Group = "lists", Icon = "icon-indent", IsDeprecated = true)]
public class DropDownPropertyEditor : DropDownWithKeysPropertyEditor
{
/// <summary>
/// The constructor will setup the property editor based on the attribute if one is found
/// </summary>
public DropDownPropertyEditor(ILogger logger, ILocalizedTextService textService)
: base(logger, textService)
{ }
/// <summary>
/// We need to override the value editor so that we can ensure the string value is published in cache and not the integer ID value.
/// </summary>
/// <returns></returns>
protected override IDataValueEditor CreateValueEditor() => new PublishValueValueEditor(Attribute, Logger);
}
}

View File

@@ -1,36 +0,0 @@
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// A property editor to allow the individual selection of pre-defined items.
/// </summary>
/// <remarks>
/// Due to remaining backwards compatible, this stores the id of the drop down item in the database which is why it is marked
/// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published
/// in cache and not the string value.
/// </remarks>
[DataEditor(Constants.PropertyEditors.Aliases.DropdownlistPublishKeys, "Dropdown list, publishing keys", "dropdown", ValueType = ValueTypes.Integer, Group = "lists", Icon = "icon-indent", IsDeprecated = true)]
public class DropDownWithKeysPropertyEditor : DataEditor
{
private readonly ILocalizedTextService _textService;
/// <summary>
/// The constructor will setup the property editor based on the attribute if one is found
/// </summary>
public DropDownWithKeysPropertyEditor(ILogger logger, ILocalizedTextService textService)
: base(logger)
{
_textService = textService;
}
/// <summary>
/// Return a custom pre-value editor
/// </summary>
/// <returns></returns>
protected override IConfigurationEditor CreateConfigurationEditor() => new ValueListConfigurationEditor(_textService);
}
}

View File

@@ -1,57 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// A custom value editor for any property editor that stores a pre-value int id so that we can ensure that the 'value' not the ID get's put into cache
/// </summary>
/// <remarks>
/// This is required for legacy/backwards compatibility, otherwise we'd just store the string version and cache the string version without
/// needing additional lookups.
/// </remarks>
internal class PublishValueValueEditor : DataValueEditor
{
private readonly ILogger _logger;
internal PublishValueValueEditor(DataEditorAttribute attribute, ILogger logger)
: base(attribute)
{
_logger = logger;
}
/// <inheritdoc />
public override string ConvertDbToString(PropertyType propertyType, object value, IDataTypeService dataTypeService)
{
if (value == null)
return null;
// get the configuration items
// if none, fallback to base
var configuration = dataTypeService.GetDataType(propertyType.DataTypeId).ConfigurationAs<ValueListConfiguration>();
if (configuration == null)
return base.ConvertDbToString(propertyType, value, dataTypeService);
var items = configuration.Items;
var idAttempt = value.TryConvertTo<int>();
if (idAttempt.Success)
{
var itemId = idAttempt.Result;
var item = items.FirstOrDefault(x => x.Id == itemId);
if (item != null) return item.Value;
_logger.Warn<PublishValueValueEditor>("Could not find a configuration item with ID " + itemId + " for property alias " + propertyType.Alias);
}
// fallback to default
return base.ConvertDbToString(propertyType, value, dataTypeService);
}
}
}

View File

@@ -11,58 +11,19 @@ using Umbraco.Web.Composing;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Custom value editor to handle posted json data and to return json data for the multiple selected items as well as ensuring
/// that the multiple selected int IDs are published to cache as a delimited string (values)
/// Custom value editor to handle posted json data and to return json data for the multiple selected items
/// </summary>
/// <remarks>
/// This is re-used by editors such as the multiple drop down list or check box list
/// </remarks>
internal class PublishValuesMultipleValueEditor : PublishValueValueEditor
internal class PublishValuesMultipleValueEditor : DataValueEditor
{
private readonly bool _publishIds;
private readonly ILogger _logger;
internal PublishValuesMultipleValueEditor(bool publishIds, ILogger logger, DataEditorAttribute attribute)
: base(attribute, logger)
internal PublishValuesMultipleValueEditor(ILogger logger, DataEditorAttribute attribute)
: base(attribute)
{
_publishIds = publishIds;
}
public PublishValuesMultipleValueEditor(bool publishIds, DataEditorAttribute attribute)
: this(publishIds, Current.Logger, attribute)
{ }
/// <summary>
/// If publishing ids, we don't need to do anything, otherwise we need to look up the pre-values and get the string values
/// </summary>
/// <param name="propertyType"></param>
/// <param name="propertyValue"></param>
/// <param name="dataTypeService"></param>
/// <returns></returns>
public override string ConvertDbToString(PropertyType propertyType, object propertyValue, IDataTypeService dataTypeService)
{
if (propertyValue == null)
return null;
//publishing ids, so just need to return the value as-is
if (_publishIds)
{
return propertyValue.ToString();
}
// get the multiple ids
// if none, fallback to base
var selectedIds = propertyValue.ToString().Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
if (selectedIds.Any() == false)
return base.ConvertDbToString(propertyType, propertyValue, dataTypeService);
// get the configuration items
// if none, fallback to base
var configuration = dataTypeService.GetDataType(propertyType.DataTypeId).ConfigurationAs<ValueListConfiguration>();
if (configuration == null)
return base.ConvertDbToString(propertyType, propertyValue, dataTypeService);
var items = configuration.Items.Where(x => selectedIds.Contains(x.Id.ToInvariantString())).Select(x => x.Value);
return string.Join(",", items);
_logger = logger;
}
/// <summary>
@@ -81,7 +42,7 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// When multiple values are selected a json array will be posted back so we need to format for storage in
/// the database which is a comma separated ID value
/// the database which is a comma separated string value
/// </summary>
/// <param name="editorValue"></param>
/// <param name="currentValue"></param>

View File

@@ -8,19 +8,24 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// A property editor to allow the individual selection of pre-defined items.
/// </summary>
/// <remarks>
/// Due to remaining backwards compatible, this stores the id of the item in the database which is why it is marked
/// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published
/// in cache and not the string value.
/// </remarks>
[DataEditor(Constants.PropertyEditors.Aliases.RadioButtonList, "Radio button list", "radiobuttons", ValueType = ValueTypes.Integer, Group="lists", Icon="icon-target")]
public class RadioButtonsPropertyEditor : DropDownWithKeysPropertyEditor
public class RadioButtonsPropertyEditor : DataEditor
{
private readonly ILocalizedTextService _textService;
/// <summary>
/// The constructor will setup the property editor based on the attribute if one is found
/// </summary>
public RadioButtonsPropertyEditor(ILogger logger, ILocalizedTextService textService)
: base(logger, textService)
{ }
: base(logger)
{
_textService = textService;
}
/// <summary>
/// Return a custom pre-value editor
/// </summary>
/// <returns></returns>
protected override IConfigurationEditor CreateConfigurationEditor() => new ValueListConfigurationEditor(_textService);
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
@@ -16,7 +17,8 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
{
return source?.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return source?.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim()).ToArray()
?? Enumerable.Empty<string>();
}
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)

View File

@@ -129,7 +129,7 @@ namespace Umbraco.Web.Routing
var parent = content;
do
{
parent = parent.ParentId > 0 ? parent.Parent(contentService) : null;
parent = parent.ParentId > 0 ? contentService.GetParent(parent) : null;
}
while (parent != null && parent.Published && (!parent.ContentType.VariesByCulture() || parent.IsCulturePublished(culture)));

View File

@@ -31,6 +31,7 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Runtime;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Actions;
using Umbraco.Web.Cache;
using Umbraco.Web.Composing.CompositionRoots;
using Umbraco.Web.ContentApps;
@@ -53,7 +54,7 @@ using Umbraco.Web.Tour;
using Umbraco.Web.Trees;
using Umbraco.Web.UI.JavaScript;
using Umbraco.Web.WebApi;
using Umbraco.Web._Legacy.Actions;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Web.Runtime
@@ -139,7 +140,7 @@ namespace Umbraco.Web.Runtime
Current.DefaultRenderMvcControllerType = typeof(RenderMvcController); // fixme WRONG!
composition.Container.RegisterCollectionBuilder<ActionCollectionBuilder>()
.SetProducer(() => typeLoader.GetActions());
.Add(() => typeLoader.GetTypes<IAction>());
var surfaceControllerTypes = new SurfaceControllerTypeCollection(typeLoader.GetSurfaceControllers());
composition.Container.RegisterInstance(surfaceControllerTypes);

View File

@@ -26,6 +26,7 @@ using Umbraco.Web.Cache;
using Umbraco.Web.Composing;
using Umbraco.Web.PropertyEditors;
using Umbraco.Examine;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Web.Search
{
@@ -102,13 +103,10 @@ namespace Umbraco.Web.Search
// bind to distributed cache events - this ensures that this logic occurs on ALL servers
// that are taking part in a load balanced environment.
ContentCacheRefresher.CacheUpdated += ContentCacheRefresherUpdated;
ContentTypeCacheRefresher.CacheUpdated += ContentTypeCacheRefresherUpdated; ;
MediaCacheRefresher.CacheUpdated += MediaCacheRefresherUpdated;
MemberCacheRefresher.CacheUpdated += MemberCacheRefresherUpdated;
// fixme - content type?
// events handling removed in ef013f9d3b945d0a48a306ff1afbd49c10c3fff8
// because, could not make sense of it?
EnsureUnlocked(profilingLogger.Logger, examineManager);
RebuildIndexesOnStartup(profilingLogger.Logger);
@@ -307,16 +305,191 @@ namespace Umbraco.Web.Search
// branch
if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
var descendants = mediaService.GetDescendants(media);
foreach (var descendant in descendants)
const int pageSize = 500;
var page = 0;
var total = long.MaxValue;
while (page * pageSize < total)
{
ReIndexForMedia(descendant, descendant.Trashed == false);
var descendants = mediaService.GetPagedDescendants(media.Id, page++, pageSize, out total);
foreach (var descendant in descendants)
{
ReIndexForMedia(descendant, descendant.Trashed == false);
}
}
}
}
}
}
/// <summary>
/// Updates indexes based on content type changes
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void ContentTypeCacheRefresherUpdated(ContentTypeCacheRefresher sender, CacheRefresherEventArgs args)
{
if (Suspendable.ExamineEvents.CanIndex == false)
return;
if (args.MessageType != MessageType.RefreshByPayload)
throw new NotSupportedException();
var changedIds = new Dictionary<string, (List<int> removedIds, List<int> refreshedIds, List<int> otherIds)>();
foreach (var payload in (ContentTypeCacheRefresher.JsonPayload[])args.MessageObject)
{
if (!changedIds.TryGetValue(payload.ItemType, out var idLists))
{
idLists = (removedIds: new List<int>(), refreshedIds: new List<int>(), otherIds: new List<int>());
changedIds.Add(payload.ItemType, idLists);
}
if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.Remove))
idLists.removedIds.Add(payload.Id);
else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshMain))
idLists.refreshedIds.Add(payload.Id);
else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshOther))
idLists.otherIds.Add(payload.Id);
}
const int pageSize = 500;
foreach(var ci in changedIds)
{
if (ci.Value.refreshedIds.Count > 0 || ci.Value.otherIds.Count > 0)
{
switch(ci.Key)
{
case var itemType when itemType == typeof(IContentType).Name:
RefreshContentOfContentTypes(ci.Value.refreshedIds.Concat(ci.Value.otherIds).Distinct().ToArray());
break;
case var itemType when itemType == typeof(IMediaType).Name:
RefreshMediaOfMediaTypes(ci.Value.refreshedIds.Concat(ci.Value.otherIds).Distinct().ToArray());
break;
case var itemType when itemType == typeof(IMemberType).Name:
RefreshMemberOfMemberTypes(ci.Value.refreshedIds.Concat(ci.Value.otherIds).Distinct().ToArray());
break;
}
}
//Delete all content of this content/media/member type that is in any content indexer by looking up matched examine docs
foreach (var id in ci.Value.removedIds)
{
foreach (var index in _examineManager.IndexProviders.Values.OfType<UmbracoExamineIndexer>())
{
var searcher = index.GetSearcher();
var page = 0;
var total = long.MaxValue;
while (page * pageSize < total)
{
//paging with examine, see https://shazwazza.com/post/paging-with-examine/
var results = searcher.Search(
searcher.CreateCriteria().Field("nodeType", id).Compile(),
maxResults: pageSize * (page + 1));
total = results.TotalItemCount;
var paged = results.Skip(page * pageSize);
foreach (var item in paged)
if (int.TryParse(item.Id, out var contentId))
DeleteIndexForEntity(contentId, false);
}
}
}
}
}
private void RefreshMemberOfMemberTypes(int[] memberTypeIds)
{
const int pageSize = 500;
var memberTypes = _services.MemberTypeService.GetAll(memberTypeIds);
foreach(var memberType in memberTypes)
{
var page = 0;
var total = long.MaxValue;
while (page * pageSize < total)
{
var memberToRefresh = _services.MemberService.GetAll(
page++, pageSize, out total, "LoginName", Direction.Ascending,
memberType.Alias);
foreach (var c in memberToRefresh)
{
ReIndexForMember(c);
}
}
}
}
private void RefreshMediaOfMediaTypes(int[] mediaTypeIds)
{
const int pageSize = 500;
var page = 0;
var total = long.MaxValue;
while (page * pageSize < total)
{
var mediaToRefresh = _services.MediaService.GetPagedOfTypes(
//Re-index all content of these types
mediaTypeIds,
page++, pageSize, out total, null,
Ordering.By("Path", Direction.Ascending));
foreach (var c in mediaToRefresh)
{
ReIndexForMedia(c, c.Trashed == false);
}
}
}
private void RefreshContentOfContentTypes(int[] contentTypeIds)
{
const int pageSize = 500;
var page = 0;
var total = long.MaxValue;
while (page * pageSize < total)
{
var contentToRefresh = _services.ContentService.GetPagedOfTypes(
//Re-index all content of these types
contentTypeIds,
page++, pageSize, out total, null,
//order by shallowest to deepest, this allows us to check it's published state without checking every item
Ordering.By("Path", Direction.Ascending));
//track which Ids have their paths are published
var publishChecked = new Dictionary<int, bool>();
foreach (var c in contentToRefresh)
{
IContent published = null;
if (c.Published)
{
if (publishChecked.TryGetValue(c.ParentId, out var isPublished))
{
//if the parent's published path has already been verified then this is published
if (isPublished)
published = c;
}
else
{
//nothing by parent id, so query the service and cache the result for the next child to check against
isPublished = _services.ContentService.IsPathPublished(c);
publishChecked[c.Id] = isPublished;
if (isPublished)
published = c;
}
}
ReIndexForContent(c, published);
}
}
}
/// <summary>
/// Updates indexes based on content changes
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void ContentCacheRefresherUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args)
{
if (Suspendable.ExamineEvents.CanIndex == false)
@@ -340,6 +513,8 @@ namespace Umbraco.Web.Search
// ExamineEvents does not support RefreshAll
// just ignore that payload
// so what?!
//fixme: Rebuild the index at this point?
}
else // RefreshNode or RefreshBranch (maybe trashed)
{
@@ -355,7 +530,7 @@ namespace Umbraco.Web.Search
}
IContent published = null;
if (content.Published && ((ContentService)contentService).IsPathPublished(content))
if (content.Published && contentService.IsPathPublished(content))
published = content;
// just that content
@@ -365,19 +540,28 @@ namespace Umbraco.Web.Search
if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
var masked = published == null ? null : new List<int>();
var descendants = contentService.GetDescendants(content);
foreach (var descendant in descendants)
const int pageSize = 500;
var page = 0;
var total = long.MaxValue;
while(page * pageSize < total)
{
published = null;
if (masked != null) // else everything is masked
{
if (masked.Contains(descendant.ParentId) || !descendant.Published)
masked.Add(descendant.Id);
else
published = descendant;
}
var descendants = contentService.GetPagedDescendants(content.Id, page++, pageSize, out total,
//order by shallowest to deepest, this allows us to check it's published state without checking every item
ordering: Ordering.By("Path", Direction.Ascending));
ReIndexForContent(descendant, published);
foreach (var descendant in descendants)
{
published = null;
if (masked != null) // else everything is masked
{
if (masked.Contains(descendant.ParentId) || !descendant.Published)
masked.Add(descendant.Id);
else
published = descendant;
}
ReIndexForContent(descendant, published);
}
}
}
}

View File

@@ -4,10 +4,11 @@ using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -92,9 +93,8 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(
$"actions/{ActionRefresh.Instance.Alias}"), true);
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
var cte = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentType);
@@ -102,15 +102,15 @@ namespace Umbraco.Web.Trees
if (cte != null)
{
var ct = Services.ContentTypeService.Get(cte.Id);
var createItem = menu.Items.Add<ActionCreateBlueprintFromContent>(Services.TextService.Localize($"actions/{ActionCreateBlueprintFromContent.Instance.Alias}"));
var createItem = menu.Items.Add<ActionCreateBlueprintFromContent>(Services.TextService, opensDialog: true);
createItem.NavigateToRoute("/settings/contentBlueprints/edit/-1?create=true&doctype=" + ct.Alias);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize($"actions/{ActionRefresh.Instance.Alias}"), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
return menu;
}

View File

@@ -8,11 +8,12 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Search;
using Constants = Umbraco.Core.Constants;
@@ -114,23 +115,21 @@ namespace Umbraco.Web.Trees
// if the user's start node is not the root then the only menu item to display is refresh
if (UserStartNodes.Contains(Constants.System.Root) == false)
{
menu.Items.Add<RefreshNode, ActionRefresh>(
Services.TextService.Localize(string.Concat("actions/", ActionRefresh.Instance.Alias)),
true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
// we need to get the default permissions as you can't set permissions on the very root node
var permission = Services.UserService.GetPermissions(Security.CurrentUser, Constants.System.Root).First();
var nodeActions = global::Umbraco.Web._Legacy.Actions.Action.FromEntityPermission(permission)
var nodeActions = Current.Actions.FromEntityPermission(permission)
.Select(x => new MenuItem(x));
//these two are the standard items
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
menu.Items.Add<ActionSort>(Services.TextService.Localize("actions", ActionSort.Instance.Alias), true);
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionSort>(Services.TextService, true);
//filter the standard items
FilterUserAllowedMenuItems(menu, nodeActions);
@@ -143,7 +142,7 @@ namespace Umbraco.Web.Trees
// add default actions for *all* users
// fixme - temp disable RePublish as the page itself (republish.aspx) has been temp disabled
//menu.Items.Add<ActionRePublish>(Services.TextService.Localize("actions", ActionRePublish.Instance.Alias)).ConvertLegacyMenuItem(null, "content", "content");
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -165,9 +164,7 @@ namespace Umbraco.Web.Trees
if (Security.CurrentUser.HasPathAccess(item, Services.EntityService, RecycleBinId) == false)
{
var menu = new MenuItemCollection();
menu.Items.Add<RefreshNode, ActionRefresh>(
Services.TextService.Localize(string.Concat("actions/", ActionRefresh.Instance.Alias)),
true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -182,7 +179,7 @@ namespace Umbraco.Web.Trees
else
{
//set the default to create
nodeMenu.DefaultMenuAlias = ActionNew.Instance.Alias;
nodeMenu.DefaultMenuAlias = ActionNew.ActionAlias;
}
var allowedMenuItems = GetAllowedUserMenuItemsForNode(item);
@@ -228,25 +225,25 @@ namespace Umbraco.Web.Trees
protected MenuItemCollection GetAllNodeMenuItems(IUmbracoEntity item)
{
var menu = new MenuItemCollection();
AddActionNode<ActionNew>(item, menu);
AddActionNode<ActionDelete>(item, menu);
AddActionNode<ActionCreateBlueprintFromContent>(item, menu);
//need to ensure some of these are converted to the legacy system - until we upgrade them all to be angularized.
AddActionNode<ActionMove>(item, menu, true);
AddActionNode<ActionCopy>(item, menu);
AddActionNode<ActionNew>(item, menu, opensDialog: true);
AddActionNode<ActionDelete>(item, menu, opensDialog: true);
AddActionNode<ActionCreateBlueprintFromContent>(item, menu, opensDialog: true);
AddActionNode<ActionMove>(item, menu, true, opensDialog: true);
AddActionNode<ActionCopy>(item, menu, opensDialog: true);
AddActionNode<ActionSort>(item, menu, true);
AddActionNode<ActionAssignDomain>(item, menu, opensDialog: true);
AddActionNode<ActionRights>(item, menu, opensDialog: true);
//fixme - conver this editor to angular
AddActionNode<ActionProtect>(item, menu, true, convert: true, opensDialog: true);
AddActionNode<ActionToPublish>(item, menu, convert: true);
AddActionNode<ActionAssignDomain>(item, menu);
AddActionNode<ActionRights>(item, menu, convert: true);
AddActionNode<ActionProtect>(item, menu, true, true);
AddActionNode<ActionNotify>(item, menu, true);
menu.Items.Add(new MenuItem("notify", Services.TextService)
{
Icon = "megaphone",
SeperatorBefore = true,
OpensDialog = true
});
AddActionNode<RefreshNode, ActionRefresh>(item, menu, true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -259,10 +256,10 @@ namespace Umbraco.Web.Trees
protected MenuItemCollection GetNodeMenuItemsForDeletedContent(IUmbracoEntity item)
{
var menu = new MenuItemCollection();
menu.Items.Add<ActionRestore>(Services.TextService.Localize("actions", ActionRestore.Instance.Alias));
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
menu.Items.Add<ActionRestore>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -306,19 +303,14 @@ namespace Umbraco.Web.Trees
entity.Name = "[[" + entity.Id + "]]";
}
private void AddActionNode<TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false)
//fixme: Remove the need for converting to legacy
private void AddActionNode<TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false, bool opensDialog = false)
where TAction : IAction
{
//fixme: Inject
var menuItem = menu.Items.Add<TAction>(Services.TextService.Localize("actions", Current.Actions.GetAction<TAction>().Alias), hasSeparator);
if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content");
}
private void AddActionNode<TItem, TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false)
where TItem : MenuItem, new()
where TAction : IAction
{
var menuItem = menu.Items.Add<TItem, TAction>(Services.TextService.Localize("actions", Current.Actions.GetAction<TAction>().Alias), hasSeparator);
if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content");
menuItem.OpensDialog = opensDialog;
}
public IEnumerable<SearchResultItem> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)

View File

@@ -14,7 +14,9 @@ using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using System.Globalization;
using Umbraco.Core.Models.Entities;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Trees
{
@@ -347,8 +349,12 @@ namespace Umbraco.Web.Trees
if (RecycleBinId.ToInvariantString() == id)
{
var menu = new MenuItemCollection();
menu.Items.Add<ActionEmptyTranscan>(Services.TextService.Localize("actions/emptyTrashcan"));
menu.Items.Add<ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new MenuItem("emptyRecycleBin", Services.TextService)
{
Icon = "trash",
OpensDialog = true
});
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -381,13 +387,16 @@ namespace Umbraco.Web.Trees
internal IEnumerable<MenuItem> GetAllowedUserMenuItemsForNode(IUmbracoEntity dd)
{
var permission = Services.UserService.GetPermissions(Security.CurrentUser, dd.Path);
var actions = global::Umbraco.Web._Legacy.Actions.Action.FromEntityPermission(permission)
//fixme: inject
var actions = Current.Actions.FromEntityPermission(permission)
.ToList();
var actionDelete = Current.Actions.GetAction<ActionDelete>();
// A user is allowed to delete their own stuff
var tryGetCurrentUserId = Security.GetUserId();
if (tryGetCurrentUserId && dd.CreatorId == tryGetCurrentUserId.Result && actions.Contains(ActionDelete.Instance) == false)
actions.Add(ActionDelete.Instance);
if (tryGetCurrentUserId && dd.CreatorId == tryGetCurrentUserId.Result && actions.Contains(actionDelete) == false)
actions.Add(actionDelete);
return actions.Select(x => new MenuItem(x));
}

View File

@@ -7,7 +7,8 @@ using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
@@ -77,12 +78,18 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionImport>(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new MenuItem("importDocumentType", Services.TextService)
{
Icon = "page-up",
SeperatorBefore = true,
OpensDialog = true
});
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -90,11 +97,11 @@ namespace Umbraco.Web.Trees
if (container != null)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new MenuItem("rename", Services.TextService.Localize(String.Format("actions/{0}", "rename")))
menu.Items.Add(new MenuItem("rename", Services.TextService)
{
Icon = "icon icon-edit"
});
@@ -102,11 +109,9 @@ namespace Umbraco.Web.Trees
if (container.HasChildren == false)
{
//can delete doc type
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
}
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
}
else
{
@@ -115,18 +120,23 @@ namespace Umbraco.Web.Trees
if (enableInheritedDocumentTypes)
{
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
}
//no move action if this is a child doc type
if (parent == null)
{
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), true);
menu.Items.Add<ActionMove>(Services.TextService, true, opensDialog: true);
}
menu.Items.Add<ActionCopy>(Services.TextService.Localize(string.Format("actions/{0}", ActionCopy.Instance.Alias)));
menu.Items.Add<ActionExport>(Services.TextService.Localize(string.Format("actions/{0}", ActionExport.Instance.Alias)), true);
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
menu.Items.Add<ActionCopy>(Services.TextService, opensDialog: true);
menu.Items.Add(new MenuItem("export", Services.TextService)
{
Icon = "download-alt",
SeperatorBefore = true,
OpensDialog = true
});
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
if (enableInheritedDocumentTypes)
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
}
return menu;

View File

@@ -9,9 +9,10 @@ using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Search;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -100,11 +101,11 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -112,9 +113,9 @@ namespace Umbraco.Web.Trees
if (container != null)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new MenuItem("rename", Services.TextService.Localize("actions/rename"))
{
@@ -124,19 +125,18 @@ namespace Umbraco.Web.Trees
if (container.HasChildren == false)
{
//can delete data type
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
}
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(
$"actions/{ActionRefresh.Instance.Alias}"), hasSeparator: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
}
else
{
var nonDeletableSystemDataTypeIds = GetNonDeletableSystemDataTypeIds();
if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id)) == false)
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), hasSeparator: true);
menu.Items.Add<ActionMove>(Services.TextService, hasSeparator: true, opensDialog: true);
}
return menu;

View File

@@ -3,7 +3,8 @@ using System.Linq;
using System.Net.Http.Formatting;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
@@ -95,14 +96,12 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
if (id != Constants.System.Root.ToInvariantString())
menu.Items.Add<ActionDelete>(Services.TextService.Localize(
$"actions/{ActionDelete.Instance.Alias}"), true);
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(
$"actions/{ActionRefresh.Instance.Alias}"), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}

View File

@@ -7,8 +7,9 @@ using System.Web;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -79,11 +80,11 @@ namespace Umbraco.Web.Trees
var menu = new MenuItemCollection();
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
//create action
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -93,9 +94,9 @@ namespace Umbraco.Web.Trees
var menu = new MenuItemCollection();
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
//create action
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any();
@@ -103,11 +104,11 @@ namespace Umbraco.Web.Trees
if (hasChildren == false)
{
//delete action
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
}
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -117,7 +118,7 @@ namespace Umbraco.Web.Trees
var menu = new MenuItemCollection();
//if it's not a directory then we only allow to delete the item
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
return menu;
}

View File

@@ -6,7 +6,8 @@ using System.Web.Http.Routing;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.Trees;
@@ -17,6 +18,8 @@ namespace Umbraco.Web.Trees
/// </summary>
internal class LegacyTreeDataConverter
{
//fixme: remove this whole class when everything is angularized
/// <summary>
/// This will look at the legacy IAction's JsFunctionName and convert it to a confirmation dialog view if possible
/// </summary>
@@ -24,14 +27,9 @@ namespace Umbraco.Web.Trees
/// <returns></returns>
internal static Attempt<string> GetLegacyConfirmView(IAction action)
{
if (action.JsFunctionName.IsNullOrWhiteSpace())
switch (action)
{
return Attempt<string>.Fail();
}
switch (action.JsFunctionName)
{
case "UmbClientMgr.appActions().actionDelete()":
case ActionDelete actionDelete:
return Attempt.Succeed(
UmbracoConfig.For.GlobalSettings().Path.EnsureEndsWith('/') + "views/common/dialogs/legacydelete.html");
}
@@ -49,64 +47,18 @@ namespace Umbraco.Web.Trees
/// <param name="nodeType"></param>
internal static Attempt<LegacyUrlAction> GetUrlAndTitleFromLegacyAction(IAction action, string nodeId, string nodeType, string nodeName, string currentSection)
{
if (action.JsFunctionName.IsNullOrWhiteSpace())
switch (action)
{
return Attempt<LegacyUrlAction>.Fail();
}
switch (action.JsFunctionName)
{
case "UmbClientMgr.appActions().actionNew()":
case ActionNew actionNew:
return Attempt.Succeed(
new LegacyUrlAction(
"create.aspx?nodeId=" + nodeId + "&nodeType=" + nodeType + "&nodeName=" + nodeName + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/create")));
case "UmbClientMgr.appActions().actionNewFolder()":
return Attempt.Succeed(
new LegacyUrlAction(
"createFolder.aspx?nodeId=" + nodeId + "&nodeType=" + nodeType + "&nodeName=" + nodeName + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/create")));
case "UmbClientMgr.appActions().actionProtect()":
case ActionProtect actionProtect:
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/protectPage.aspx?mode=cut&nodeId=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/protect")));
case "UmbClientMgr.appActions().actionRollback()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/rollback.aspx?nodeId=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/rollback")));
case "UmbClientMgr.appActions().actionNotify()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/notifications.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/notify")));
case "UmbClientMgr.appActions().actionPublish()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/publish.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/publish")));
case "UmbClientMgr.appActions().actionChangeDocType()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/ChangeDocType.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/changeDocType")));
case "UmbClientMgr.appActions().actionToPublish()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/SendPublish.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/sendtopublish")));
case "UmbClientMgr.appActions().actionRePublish()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/republish.aspx?rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/republish")));
case "UmbClientMgr.appActions().actionSendToTranslate()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/sendToTranslation.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/sendToTranslate")));
}
return Attempt<LegacyUrlAction>.Fail();
}

View File

@@ -8,7 +8,8 @@ using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -58,13 +59,13 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
//Create the normal create action
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias))
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true)
//Since we haven't implemented anything for macros in angular, this needs to be converted to
//use the legacy format
.ConvertLegacyMenuItem(null, "initmacros", queryStrings.GetValue<string>("application"));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -74,7 +75,7 @@ namespace Umbraco.Web.Trees
if (macro == null) return new MenuItemCollection();
//add delete option for all macros
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias))
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true)
//Since we haven't implemented anything for macros in angular, this needs to be converted to
//use the legacy format
.ConvertLegacyMenuItem(new EntitySlim

View File

@@ -8,10 +8,12 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Search;
using Constants = Umbraco.Core.Constants;
@@ -81,28 +83,25 @@ namespace Umbraco.Web.Trees
var menu = new MenuItemCollection();
//set the default
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
if (id == Constants.System.Root.ToInvariantString())
{
// if the user's start node is not the root then the only menu item to display is refresh
if (UserStartNodes.Contains(Constants.System.Root) == false)
{
menu.Items.Add<RefreshNode, ActionRefresh>(
Services.TextService.Localize(string.Concat("actions/", ActionRefresh.Instance.Alias)),
true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
menu.Items.Add<ActionSort>(Services.TextService.Localize("actions", ActionSort.Instance.Alias), true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionSort>(Services.TextService, true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
int iid;
if (int.TryParse(id, out iid) == false)
if (int.TryParse(id, out var iid) == false)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
@@ -115,29 +114,30 @@ namespace Umbraco.Web.Trees
//if the user has no path access for this node, all they can do is refresh
if (Security.CurrentUser.HasPathAccess(item, Services.EntityService, RecycleBinId) == false)
{
menu.Items.Add<RefreshNode, ActionRefresh>(
Services.TextService.Localize(string.Concat("actions/", ActionRefresh.Instance.Alias)),
true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
//return a normal node menu:
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
menu.Items.Add<ActionMove>(Services.TextService.Localize("actions", ActionMove.Instance.Alias));
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
menu.Items.Add<ActionSort>(Services.TextService.Localize("actions", ActionSort.Instance.Alias));
menu.Items.Add<ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionSort>(Services.TextService);
menu.Items.Add(new RefreshNode(Services.TextService, true));
//if the media item is in the recycle bin, don't have a default menu, just show the regular menu
if (item.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Contains(RecycleBinId.ToInvariantString()))
{
menu.DefaultMenuAlias = null;
menu.Items.Insert(2, new MenuItem(ActionRestore.Instance, Services.TextService.Localize("actions", ActionRestore.Instance.Alias)));
menu.Items.Insert(2, new MenuItem(ActionRestore.ActionAlias, Services.TextService)
{
OpensDialog = true
});
}
else
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
}
return menu;

View File

@@ -9,8 +9,9 @@ using Umbraco.Core.Models;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Search;
namespace Umbraco.Web.Trees
@@ -70,12 +71,11 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(
$"actions/{ActionRefresh.Instance.Alias}"));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService));
return menu;
}
@@ -83,9 +83,9 @@ namespace Umbraco.Web.Trees
if (container != null)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add(new MenuItem("rename", Services.TextService.Localize("actions/rename"))
{
@@ -95,10 +95,9 @@ namespace Umbraco.Web.Trees
if (container.HasChildren == false)
{
//can delete doc type
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
}
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(
$"actions/{ActionRefresh.Instance.Alias}"), hasSeparator: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
}
else
{
@@ -107,29 +106,28 @@ namespace Umbraco.Web.Trees
if (enableInheritedMediaTypes)
{
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
//no move action if this is a child doc type
if (parent == null)
{
menu.Items.Add<ActionMove>(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), true);
menu.Items.Add<ActionMove>(Services.TextService, true, opensDialog: true);
}
}
else
{
menu.Items.Add<ActionMove>(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"));
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
//no move action if this is a child doc type
if (parent == null)
{
menu.Items.Add<ActionMove>(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), true);
menu.Items.Add<ActionMove>(Services.TextService, true, opensDialog: true);
}
}
menu.Items.Add<ActionCopy>(Services.TextService.Localize($"actions/{ActionCopy.Instance.Alias}"));
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
menu.Items.Add<ActionCopy>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
if (enableInheritedMediaTypes)
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(
$"actions/{ActionRefresh.Instance.Alias}"), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
}
return menu;

View File

@@ -10,10 +10,11 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Security;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Search;
using Constants = Umbraco.Core.Constants;
@@ -155,36 +156,35 @@ namespace Umbraco.Web.Trees
if (_provider.IsUmbracoMembershipProvider())
{
//set default
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.DefaultMenuAlias = ActionNew.ActionAlias;
//Create the normal create action
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
}
else
{
//Create a custom create action - this does not launch a dialog, it just navigates to the create screen
// we'll create it based on the ActionNew so it maintains the same icon properties, name, etc...
var createMenuItem = new MenuItem(ActionNew.Instance);
var createMenuItem = new MenuItem(ActionNew.ActionAlias, Services.TextService)
{
Icon = "add",
OpensDialog = true
};
//we want to go to this route: /member/member/edit/-1?create=true
createMenuItem.NavigateToRoute("/member/member/edit/-1?create=true");
menu.Items.Add(createMenuItem);
}
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
//add delete option for all members
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
if (Security.CurrentUser.HasAccessToSensitiveData())
{
menu.Items.Add(new ExportMember
{
Name = Services.TextService.Localize("actions/export"),
Icon = "download-alt",
Alias = "export"
});
menu.Items.Add(new ExportMember(Services.TextService));
}

View File

@@ -2,7 +2,8 @@
using System.Net.Http.Formatting;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
namespace Umbraco.Web.Trees
@@ -25,14 +26,14 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
// root actions
menu.Items.Add<CreateChildEntity, ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new CreateChildEntity(Services.TextService));
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
else
{
//delete member type/group
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
}
return menu;

View File

@@ -8,7 +8,8 @@ using Umbraco.Web.WebApi.Filters;
using umbraco;
using umbraco.cms.businesslogic.packager;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -83,21 +84,20 @@ namespace Umbraco.Web.Trees
// Root actions
if (id == "-1")
{
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"))
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true)
.ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue<string>("application"));
}
else if (id == "created")
{
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"))
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true)
.ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue<string>("application"));
menu.Items.Add<RefreshNode, ActionRefresh>(
Services.TextService.Localize($"actions/{ActionRefresh.Instance.Alias}"), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
}
else
{
//it's a package node
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
}
return menu;

View File

@@ -4,10 +4,11 @@ using System.Net.Http.Formatting;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Core.Services;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Web.Actions;
namespace Umbraco.Web.Trees
{
@@ -24,12 +25,10 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
//Create the normal create action
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias))
//Since we haven't implemented anything for relationtypes in angular, this needs to be converted to
//use the legacy format
.ConvertLegacyMenuItem(null, "initrelationTypes", queryStrings.GetValue<string>("application"));
var addMenuItem = menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
addMenuItem.LaunchDialogUrl("developer/RelationTypes/NewRelationType.aspx", "Create New RelationType");
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -38,7 +37,7 @@ namespace Umbraco.Web.Trees
if (relationType == null) return new MenuItemCollection();
//add delete option for all macros
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias))
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true)
//Since we haven't implemented anything for relationtypes in angular, this needs to be converted to
//use the legacy format
.ConvertLegacyMenuItem(new EntitySlim

View File

@@ -8,12 +8,13 @@ using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.Search;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -69,13 +70,13 @@ namespace Umbraco.Web.Trees
var menu = new MenuItemCollection();
//Create the normal create action
var item = menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
var item = menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
item.NavigateToRoute($"{queryStrings.GetValue<string>("application")}/templates/edit/{id}?create=true");
if (id == Constants.System.Root.ToInvariantString())
{
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -88,11 +89,11 @@ namespace Umbraco.Web.Trees
if (template.IsMasterTemplate == false)
{
//add delete option if it doesn't have children
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias), true);
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
}
//add refresh
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;

View File

@@ -3,10 +3,11 @@ using System.Linq;
using System.Net.Http.Formatting;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -43,7 +44,7 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.Root.ToInvariantString())
{
// root actions
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}

View File

@@ -4,7 +4,7 @@ using Umbraco.Core.Services;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees

View File

@@ -5,7 +5,7 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.Trees;
using Umbraco.Web.WebApi;
using Umbraco.Core.Composing;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web
{
@@ -14,15 +14,6 @@ namespace Umbraco.Web
/// </summary>
public static class TypeLoaderExtensions
{
/// <summary>
/// Returns all available IAction in application
/// </summary>
/// <returns></returns>
internal static IEnumerable<Type> GetActions(this TypeLoader mgr)
{
return mgr.GetTypes<IAction>();
}
/// <summary>
/// Returns all available TreeApiController's in application that are attribute with TreeAttribute
/// </summary>
@@ -43,15 +34,5 @@ namespace Umbraco.Web
return mgr.GetTypes<UmbracoApiController>();
}
/// <summary>
/// Returns all available ISearchableTrees in application
/// </summary>
/// <param name="mgr"></param>
/// <returns></returns>
internal static IEnumerable<Type> GetSearchableTrees(this TypeLoader mgr)
{
return mgr.GetTypes<ISearchableTree>();
}
}
}

View File

@@ -11,9 +11,10 @@ using Umbraco.Core.Exceptions;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Security;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing;
using Umbraco.Web.Security;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.UI.Pages
{

View File

@@ -360,7 +360,6 @@
<Compile Include="PropertyEditors\DropDownFlexibleConfiguration.cs" />
<Compile Include="PropertyEditors\DropDownFlexiblePropertyEditor.cs" />
<Compile Include="PropertyEditors\DropDownFlexibleConfigurationEditor.cs" />
<Compile Include="PropertyEditors\DropDownMultipleConfigurationEditor.cs" />
<Compile Include="PropertyEditors\EmailAddressConfigurationEditor.cs" />
<Compile Include="PropertyEditors\EmailAddressConfiguration.cs" />
<Compile Include="PropertyEditors\GridConfiguration.cs" />
@@ -428,7 +427,6 @@
<Compile Include="PublishedCache\NuCache\PublishedSnapshot.cs" />
<Compile Include="PublishedCache\PublishedElement.cs" />
<Compile Include="PublishedCache\PublishedElementPropertyBase.cs" />
<Compile Include="Models\Trees\DisableUser.cs" />
<Compile Include="PropertyEditors\ValueConverters\ContentPickerValueConverter.cs" />
<Compile Include="PublishedCache\PublishedSnapshotServiceBase.cs" />
<Compile Include="PublishedCache\IDomainCache.cs" />
@@ -531,39 +529,26 @@
<Compile Include="Runtime\WebRuntimeComponent.cs" />
<Compile Include="Editors\PublishedStatusController.cs" />
<Compile Include="Editors\NuCacheStatusController.cs" />
<Compile Include="_Legacy\Actions\Action.cs" />
<Compile Include="_Legacy\Actions\ActionAssignDomain.cs" />
<Compile Include="_Legacy\Actions\ActionBrowse.cs" />
<Compile Include="_Legacy\Actions\ActionChangeDocType.cs" />
<Compile Include="_Legacy\Actions\ActionCollection.cs" />
<Compile Include="_Legacy\Actions\ActionCollectionBuilder.cs" />
<Compile Include="_Legacy\Actions\ActionCopy.cs" />
<Compile Include="_Legacy\Actions\ActionCreateBlueprintFromContent.cs" />
<Compile Include="_Legacy\Actions\ActionDelete.cs" />
<Compile Include="_Legacy\Actions\ActionEmptyTranscan.cs" />
<Compile Include="_Legacy\Actions\ActionExport.cs" />
<Compile Include="_Legacy\Actions\ActionImport.cs" />
<Compile Include="_Legacy\Actions\ActionMove.cs" />
<Compile Include="_Legacy\Actions\ActionNew.cs" />
<Compile Include="_Legacy\Actions\ActionNotify.cs" />
<Compile Include="_Legacy\Actions\ActionNull.cs" />
<Compile Include="_Legacy\Actions\ActionPackage.cs" />
<Compile Include="_Legacy\Actions\ActionPackageCreate.cs" />
<Compile Include="_Legacy\Actions\ActionProtect.cs" />
<Compile Include="_Legacy\Actions\ActionPublish.cs" />
<Compile Include="_Legacy\Actions\ActionRefresh.cs" />
<Compile Include="_Legacy\Actions\ActionRePublish.cs" />
<Compile Include="_Legacy\Actions\ActionRestore.cs" />
<Compile Include="_Legacy\Actions\ActionRights.cs" />
<Compile Include="_Legacy\Actions\ActionRollback.cs" />
<Compile Include="_Legacy\Actions\ActionSort.cs" />
<Compile Include="_Legacy\Actions\ActionToPublish.cs" />
<Compile Include="_Legacy\Actions\ActionTranslate.cs" />
<Compile Include="_Legacy\Actions\ActionUnpublish.cs" />
<Compile Include="_Legacy\Actions\ActionUpdate.cs" />
<Compile Include="_Legacy\Actions\ContextMenuSeperator.cs" />
<Compile Include="_Legacy\Actions\IAction.cs" />
<Compile Include="_Legacy\Actions\LegacyActionMenuItemAttribute.cs" />
<Compile Include="Actions\ActionAssignDomain.cs" />
<Compile Include="Actions\ActionBrowse.cs" />
<Compile Include="Actions\ActionChangeDocType.cs" />
<Compile Include="Actions\ActionCollection.cs" />
<Compile Include="Actions\ActionCollectionBuilder.cs" />
<Compile Include="Actions\ActionCopy.cs" />
<Compile Include="Actions\ActionCreateBlueprintFromContent.cs" />
<Compile Include="Actions\ActionDelete.cs" />
<Compile Include="Actions\ActionMove.cs" />
<Compile Include="Actions\ActionNew.cs" />
<Compile Include="Actions\ActionProtect.cs" />
<Compile Include="Actions\ActionPublish.cs" />
<Compile Include="Actions\ActionRestore.cs" />
<Compile Include="Actions\ActionRights.cs" />
<Compile Include="Actions\ActionRollback.cs" />
<Compile Include="Actions\ActionSort.cs" />
<Compile Include="Actions\ActionToPublish.cs" />
<Compile Include="Actions\ActionUnpublish.cs" />
<Compile Include="Actions\ActionUpdate.cs" />
<Compile Include="Actions\IAction.cs" />
<Compile Include="Models\ContentEditing\EntityBasic.cs" />
<Compile Include="Models\Trees\ApplicationAttribute.cs" />
<Compile Include="Models\Trees\ApplicationDefinitions.cs" />
@@ -813,11 +798,9 @@
<Compile Include="PropertyEditors\DatePropertyEditor.cs" />
<Compile Include="PropertyEditors\DateTimePropertyEditor.cs" />
<Compile Include="PropertyEditors\DateTimeValidator.cs" />
<Compile Include="PropertyEditors\DropDownMultiplePropertyEditor.cs" />
<Compile Include="PropertyEditors\IntegerPropertyEditor.cs" />
<Compile Include="PropertyEditors\MultipleTextStringPropertyEditor.cs" />
<Compile Include="PropertyEditors\PublishValuesMultipleValueEditor.cs" />
<Compile Include="PropertyEditors\DropDownMultipleWithKeysPropertyEditor.cs" />
<Compile Include="PropertyEditors\RadioButtonsPropertyEditor.cs" />
<Compile Include="PropertyEditors\RichTextPreValueController.cs" />
<Compile Include="PropertyEditors\RichTextConfigurationEditor.cs" />
@@ -827,9 +810,6 @@
<Compile Include="PropertyEditors\UserPickerPropertyEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\RelatedLinksValueConverter.cs" />
<Compile Include="PropertyEditors\ValueListConfigurationEditor.cs" />
<Compile Include="PropertyEditors\DropDownPropertyEditor.cs" />
<Compile Include="PropertyEditors\PublishValueValueEditor.cs" />
<Compile Include="PropertyEditors\DropDownWithKeysPropertyEditor.cs" />
<Compile Include="PublishedContentQuery.cs" />
<Compile Include="ImageCropperTemplateExtensions.cs" />
<Compile Include="Mvc\UmbracoVirtualNodeRouteHandler.cs" />
@@ -953,7 +933,6 @@
<Compile Include="PropertyEditors\TrueFalsePropertyEditor.cs" />
<Compile Include="Trees\MediaTreeController.cs" />
<Compile Include="Models\Trees\ActionMenuItem.cs" />
<Compile Include="Models\Trees\ActionMenuItemAttribute.cs" />
<Compile Include="Trees\ActionUrlMethod.cs" />
<Compile Include="Trees\ContentTreeControllerBase.cs" />
<Compile Include="Trees\ISearchableTree.cs" />
@@ -1269,12 +1248,6 @@
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\NewRelationType.aspx.designer.cs">
<DependentUpon>NewRelationType.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\RelationTypesWebService.asmx.cs">
<DependentUpon>RelationTypesWebService.asmx</DependentUpon>
<SubType>Component</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\TreeMenu\ActionDeleteRelationType.cs" />
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\TreeMenu\ActionNewRelationType.cs" />
<Compile Include="umbraco.presentation\umbraco\dialogs\insertMasterpageContent.aspx.cs">
<DependentUpon>insertMasterpageContent.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -1378,7 +1351,6 @@
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\NewRelationType.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\RelationTypesWebService.asmx" />
<Content Include="umbraco.presentation\umbraco\dashboard\FeedProxy.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\insertMasterpageContent.aspx">
<SubType>ASPXCodeBehind</SubType>

View File

@@ -5,9 +5,10 @@ using System.Web.Http.Filters;
using Umbraco.Core.Exceptions;
using Umbraco.Web.Composing;
using Umbraco.Web.Editors;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Web.Actions;
namespace Umbraco.Web.WebApi.Filters
{
@@ -39,7 +40,7 @@ namespace Umbraco.Web.WebApi.Filters
{
if (string.IsNullOrEmpty(paramName)) throw new ArgumentNullOrEmptyException(nameof(paramName));
_paramName = paramName;
_permissionToCheck = ActionBrowse.Instance.Letter;
_permissionToCheck = ActionBrowse.ActionLetter;
}
public EnsureUserPermissionForContentAttribute(string paramName, char permissionToCheck)

View File

@@ -8,7 +8,8 @@ using Umbraco.Core.Services;
using Umbraco.Core;
using Umbraco.Web.Composing;
using Umbraco.Core.Models;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Actions;
namespace Umbraco.Web.WebApi.Filters
{
@@ -25,7 +26,7 @@ namespace Umbraco.Web.WebApi.Filters
public FilterAllowedOutgoingContentAttribute(Type outgoingType)
: this(outgoingType, Current.Services.UserService, Current.Services.EntityService)
{
_permissionToCheck = ActionBrowse.Instance.Letter;
_permissionToCheck = ActionBrowse.ActionLetter;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck)
@@ -37,7 +38,7 @@ namespace Umbraco.Web.WebApi.Filters
public FilterAllowedOutgoingContentAttribute(Type outgoingType, string propertyName)
: this(outgoingType, propertyName, Current.Services.UserService, Current.Services.EntityService)
{
_permissionToCheck = ActionBrowse.Instance.Letter;
_permissionToCheck = ActionBrowse.ActionLetter;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, IUserService userService, IEntityService entityService)
@@ -45,7 +46,7 @@ namespace Umbraco.Web.WebApi.Filters
{
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
_permissionToCheck = ActionBrowse.Instance.Letter;
_permissionToCheck = ActionBrowse.ActionLetter;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck, IUserService userService, IEntityService entityService)
@@ -65,7 +66,7 @@ namespace Umbraco.Web.WebApi.Filters
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
_userService = userService;
_entityService = entityService;
_permissionToCheck = ActionBrowse.Instance.Letter;
_permissionToCheck = ActionBrowse.ActionLetter;
}
protected override void FilterItems(IUser user, IList items)

View File

@@ -1,193 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
using Umbraco.Web.Composing;
using Umbraco.Core.Services;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// Actions and Actionhandlers are a key concept to umbraco and a developer whom wish to apply
/// businessrules whenever data is changed within umbraco, by implementing the IActionHandler
/// interface it's possible to invoke methods (foreign to umbraco) - this can be used whenever
/// there is a specific rule which needs to be applied to content.
///
/// The Action class itself has responsibility for registering actions and actionhandlers,
/// and contains methods which will be invoked whenever a change is made to ex. a document, media or member
///
/// An action/actionhandler will automatically be registered, using reflection
/// which is enabling thirdparty developers to extend the core functionality of
/// umbraco without changing the codebase.
/// </summary>
[Obsolete("Actions and ActionHandlers are obsolete and should no longer be used")]
public class Action
{
private static readonly Dictionary<string, string> ActionJs = new Dictionary<string, string>();
/// <summary>
/// Jacascript for the contextmenu
/// Suggestion: this method should be moved to the presentation layer.
/// </summary>
/// <param name="language"></param>
/// <returns>String representation</returns>
public string ReturnJavascript(string language)
{
return findActions(language);
}
/// <summary>
/// Returns a list of JavaScript file paths.
/// </summary>
/// <returns></returns>
public static List<string> GetJavaScriptFileReferences()
{
return Current.Actions
.Where(x => !string.IsNullOrWhiteSpace(x.JsSource))
.Select(x => x.JsSource).ToList();
//return ActionJsReference;
}
/// <summary>
/// Javascript menuitems - tree contextmenu
/// Umbraco console
///
/// Suggestion: this method should be moved to the presentation layer.
/// </summary>
/// <param name="language"></param>
/// <returns></returns>
private static string findActions(string language)
{
if (!ActionJs.ContainsKey(language))
{
string _actionJsList = "";
foreach (IAction action in Current.Actions)
{
// Adding try/catch so this rutine doesn't fail if one of the actions fail
// Add to language JsList
try
{
// NH: Add support for css sprites
string icon = action.Icon;
if (!string.IsNullOrEmpty(icon) && icon.StartsWith("."))
icon = icon.Substring(1, icon.Length - 1);
else
icon = "images/" + icon;
_actionJsList += string.Format(",\n\tmenuItem(\"{0}\", \"{1}\", \"{2}\", \"{3}\")",
action.Letter, icon, Current.Services.TextService.Localize("actions/"+ action.Alias, new[] { language }), action.JsFunctionName);
}
catch (Exception ex)
{
Current.Logger.Error<Action>(ex, "Error registrering action to javascript");
}
}
if (_actionJsList.Length > 0)
_actionJsList = _actionJsList.Substring(2, _actionJsList.Length - 2);
_actionJsList = "\nvar menuMethods = new Array(\n" + _actionJsList + "\n)\n";
ActionJs.Add(language, _actionJsList);
}
return ActionJs[language];
}
internal static List<IAction> FromEntityPermission(EntityPermission entityPermission)
{
List<IAction> list = new List<IAction>();
foreach (var c in entityPermission.AssignedPermissions.Where(x => x.Length == 1).Select(x => x.ToCharArray()[0]))
{
IAction action = Current.Actions.ToList().Find(
delegate (IAction a)
{
return a.Letter == c;
}
);
if (action != null)
list.Add(action);
}
return list;
}
/// <summary>
/// Returns a list of IActions that are permission assignable
/// </summary>
/// <returns></returns>
public static List<IAction> GetPermissionAssignable()
{
return Current.Actions.ToList().FindAll(x => x.CanBePermissionAssigned);
}
/// <summary>
/// Check if the current IAction is using legacy javascript methods
/// </summary>
/// <param name="action"></param>
/// <returns>false if the Iaction is incompatible with 4.5</returns>
public static bool ValidateActionJs(IAction action)
{
return !action.JsFunctionName.Contains("+");
}
/// <summary>
/// Method to convert the old modal calls to the new ones
/// </summary>
/// <param name="javascript"></param>
/// <returns></returns>
public static string ConvertLegacyJs(string javascript)
{
MatchCollection tags =
Regex.Matches(javascript, "openModal[^;]*;", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
foreach (Match tag in tags)
{
string[] function = tag.Value.Split(',');
if (function.Length > 0)
{
string newFunction = "UmbClientMgr.openModalWindow" + function[0].Substring(9).Replace("parent.nodeID", "UmbClientMgr.mainTree().getActionNode().nodeId").Replace("nodeID", "UmbClientMgr.mainTree().getActionNode().nodeId").Replace("parent.returnRandom()", "'" + Guid.NewGuid().ToString() + "'");
newFunction += ", " + function[1];
newFunction += ", true";
newFunction += ", " + function[2];
newFunction += ", " + function[3];
javascript = javascript.Replace(tag.Value, newFunction);
}
}
return javascript;
}
}
/// <summary>
/// This class is used to manipulate IActions that are implemented in a wrong way
/// For instance incompatible trees with 4.0 vs 4.5
/// </summary>
public class PlaceboAction : IAction
{
public char Letter { get; set; }
public bool ShowInNotifier { get; set; }
public bool CanBePermissionAssigned { get; set; }
public string Icon { get; set; }
public string Alias { get; set; }
public string JsFunctionName { get; set; }
public string JsSource { get; set; }
public bool OpensDialog { get; set; }
public PlaceboAction() { }
public PlaceboAction(IAction legacyAction)
{
Letter = legacyAction.Letter;
ShowInNotifier = legacyAction.ShowInNotifier;
CanBePermissionAssigned = legacyAction.CanBePermissionAssigned;
Icon = legacyAction.Icon;
Alias = legacyAction.Alias;
JsFunctionName = legacyAction.JsFunctionName;
JsSource = legacyAction.JsSource;
OpensDialog = legacyAction.OpensDialog;
}
}
}

View File

@@ -1,77 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when a domain is being assigned to a document
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.AdministrationCategory)]
public class ActionAssignDomain : IAction
{
public static ActionAssignDomain Instance { get; } = new ActionAssignDomain();
#region IAction Members
public char Letter
{
get
{
return 'I';
}
}
public string JsFunctionName
{
get
{
return null;
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "assignDomain";
}
}
public string Icon
{
get
{
return "home";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,67 +0,0 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is used as a security constraint that grants a user the ability to view nodes in a tree
/// that has permissions applied to it.
/// </summary>
/// <remarks>
/// This action should not be invoked. It is used as the minimum required permission to view nodes in the content tree. By
/// granting a user this permission, the user is able to see the node in the tree but not edit the document. This may be used by other trees
/// that support permissions in the future.
/// </remarks>
[ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)]
public class ActionBrowse : IAction
{
//create singleton
private static readonly ActionBrowse instance = new ActionBrowse();
private ActionBrowse() { }
public static ActionBrowse Instance
{
get { return instance; }
}
#region IAction Members
public char Letter
{
get { return 'F'; }
}
public bool ShowInNotifier
{
get { return false; }
}
public bool CanBePermissionAssigned
{
get { return true; }
}
public string Icon
{
get { return ""; }
}
public string Alias
{
get { return "browse"; }
}
public string JsFunctionName
{
get { return ""; }
}
public string JsSource
{
get { return ""; }
}
public bool OpensDialog => false;
#endregion
}
}

View File

@@ -1,91 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when the document type of a piece of content is changed
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.AdministrationCategory)]
public class ActionChangeDocType : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionChangeDocType m_instance = new ActionChangeDocType();
#pragma warning restore 612,618
public static ActionChangeDocType Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return '7';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionChangeDocType()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "changeDocType";
}
}
public string Icon
{
get
{
return "axis-rotation-2";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using LightInject;
using Umbraco.Core.Composing;
namespace Umbraco.Web._Legacy.Actions
{
internal class ActionCollectionBuilder : ICollectionBuilder<ActionCollection, IAction>
{
private static Func<IEnumerable<Type>> _producer;
// for tests only - does not register the collection
public ActionCollectionBuilder()
{ }
public ActionCollectionBuilder(IServiceContainer container)
{
var collectionLifetime = CollectionLifetime;
// register the collection - special lifetime
// the lifetime here is custom ResettablePerContainerLifetime which will manage one
// single instance of the collection (much alike PerContainerLifetime) but can be resetted
// to force a new collection to be created.
// this is needed because of the weird things we do during install, where we'd use the
// infamous DirtyBackdoorToConfiguration to reset the ActionResolver way after Resolution
// had frozen. This has been replaced by the possibility here to set the producer at any
// time - but the builder is internal - and all this will be gone eventually.
container.Register(factory => factory.GetInstance<ActionCollectionBuilder>().CreateCollection(), collectionLifetime);
}
public ActionCollection CreateCollection()
{
var actions = new List<IAction>();
foreach (var type in _producer())
{
var getter = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
var instance = getter == null
? Activator.CreateInstance(type) as IAction
: getter.GetValue(null, null) as IAction;
if (instance == null) continue;
actions.Add(instance);
}
return new ActionCollection(actions);
}
public void SetProducer(Func<IEnumerable<Type>> producer)
{
_producer = producer;
CollectionLifetime.Reset();
}
private ResettablePerContainerLifetime CollectionLifetime { get; } = new ResettablePerContainerLifetime();
private class ResettablePerContainerLifetime : ILifetime
{
private object _instance;
public object GetInstance(Func<object> createInstance, Scope scope)
{
// not dealing with disposable instances, actions are not disposable
return _instance ?? (_instance = createInstance());
}
public void Reset()
{
_instance = null;
}
}
}
}

View File

@@ -1,91 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when copying a document, media, member
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.StructureCategory)]
public class ActionCopy : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionCopy m_instance = new ActionCopy();
#pragma warning restore 612,618
public static ActionCopy Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'O';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionCopy()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "copy";
}
}
public string Icon
{
get
{
return "documents";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,33 +0,0 @@
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
[ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)]
public class ActionCreateBlueprintFromContent : IAction
{
private static readonly ActionCreateBlueprintFromContent instance = new ActionCreateBlueprintFromContent();
public static ActionCreateBlueprintFromContent Instance
{
get { return instance; }
}
public char Letter { get; private set; }
public bool ShowInNotifier { get; private set; }
public bool CanBePermissionAssigned { get; private set; }
public string Icon { get; private set; }
public string Alias { get; private set; }
public string JsFunctionName { get; private set; }
public string JsSource { get; private set; }
public bool OpensDialog => true;
public ActionCreateBlueprintFromContent()
{
Letter = 'ï';
CanBePermissionAssigned = true;
Icon = "blueprint";
Alias = "createblueprint";
}
}
}

View File

@@ -1,85 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when a document, media, member is deleted
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)]
public class ActionDelete : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionDelete m_instance = new ActionDelete();
#pragma warning restore 612,618
public static ActionDelete Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'D';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionDelete()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "delete";
}
}
public string Icon
{
get
{
return "delete";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,80 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when the trash can is emptied
/// </summary>
public class ActionEmptyTranscan : IAction
{
//create singleton
private static readonly ActionEmptyTranscan InnerInstance = new ActionEmptyTranscan();
public static ActionEmptyTranscan Instance
{
get { return InnerInstance; }
}
#region IAction Members
public char Letter
{
get
{
return 'N';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionEmptyTranscan()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "emptyRecycleBin";
}
}
public string Icon
{
get
{
return "trash";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,78 +0,0 @@
using System;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when exporting a document type
/// </summary>
public class ActionExport : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionExport m_instance = new ActionExport();
#pragma warning restore 612,618
public static ActionExport Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return '9';
}
}
public string JsFunctionName
{
get { return ""; }
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "export";
}
}
public string Icon
{
get
{
return "download-alt";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,79 +0,0 @@
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when importing a document type
/// </summary>
public class ActionImport : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionImport m_instance = new ActionImport();
#pragma warning restore 612,618
public static ActionImport Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return '8';
}
}
public string JsFunctionName
{
get
{
return "";
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "importDocumentType";
}
}
public string Icon
{
get
{
return "page-up";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,91 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked upon creation of a document, media, member
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.StructureCategory)]
public class ActionMove : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionMove m_instance = new ActionMove();
#pragma warning restore 612,618
public static ActionMove Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'M';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionMove()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "move";
}
}
public string Icon
{
get
{
return "enter";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,77 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked upon creation of a document
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)]
public class ActionNew : IAction
{
public static ActionNew Instance { get; } = new ActionNew();
#region IAction Members
public char Letter
{
get
{
return 'C';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionNew()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "create";
}
}
public string Icon
{
get
{
return "add";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,84 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when a notification is sent
/// </summary>
public class ActionNotify : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionNotify m_instance = new ActionNotify();
#pragma warning restore 612,618
public static ActionNotify Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'T';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionNotify()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "notify";
}
}
public string Icon
{
get
{
return "megaphone";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,58 +0,0 @@
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This permission is assigned to a node when there are no permissions assigned to the node.
/// This is used internally to assign no permissions to a node for a user and shouldn't be used in code.
/// </summary>
public class ActionNull : IAction
{
//create singleton
private static readonly ActionNull instance = new ActionNull();
private ActionNull() { }
public static ActionNull Instance
{
get { return instance; }
}
#region IAction Members
public char Letter
{
get { return '-'; }
}
public bool ShowInNotifier
{
get { return false; }
}
public bool CanBePermissionAssigned
{
get { return false; }
}
public string Icon
{
get { return string.Empty; }
}
public string Alias
{
get { return string.Empty; }
}
public string JsFunctionName
{
get { return string.Empty; }
}
public string JsSource
{
get { return string.Empty; }
}
public bool OpensDialog => false;
#endregion
}
}

View File

@@ -1,82 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked upon creation of a document, media, member
/// </summary>
public class ActionPackage : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionPackage m_instance = new ActionPackage();
#pragma warning restore 612,618
public static ActionPackage Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'X';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionPackage()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return "";
}
}
public string Alias
{
get
{
return "importPackage";
}
}
public string Icon
{
get
{
return "gift";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => false;
#endregion
}
}

View File

@@ -1,82 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked upon creation of a document, media, member
/// </summary>
public class ActionPackageCreate : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionPackageCreate m_instance = new ActionPackageCreate();
#pragma warning restore 612,618
public static ActionPackageCreate Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'Y';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionPackageCreate()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "createPackage";
}
}
public string Icon
{
get
{
return "gift";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,91 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when a document is protected or unprotected
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.AdministrationCategory)]
public class ActionProtect : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionProtect m_instance = new ActionProtect();
#pragma warning restore 612,618
public static ActionProtect Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'P';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionProtect()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "protect";
}
}
public string Icon
{
get
{
return "lock";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,85 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when a document is being published
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)]
public class ActionPublish : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionPublish m_instance = new ActionPublish();
#pragma warning restore 612,618
public static ActionPublish Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'U';
}
}
public string JsFunctionName
{
get
{
return string.Empty;
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "publish";
}
}
public string Icon
{
get
{
return string.Empty;
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,82 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when all documents are being republished
/// </summary>
public class ActionRePublish : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionRePublish m_instance = new ActionRePublish();
#pragma warning restore 612,618
public static ActionRePublish Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'B';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionRePublish()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "republish";
}
}
public string Icon
{
get
{
return "globe";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,89 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when a node reloads its children
/// Concerns only the tree itself and thus you should not handle
/// this action from without umbraco.
/// </summary>
[LegacyActionMenuItem("umbracoMenuActions", "RefreshNode")]
public class ActionRefresh : IAction
{
//create singleton
private static readonly ActionRefresh InnerInstance = new ActionRefresh();
public static ActionRefresh Instance
{
get { return InnerInstance; }
}
#region IAction Members
public char Letter
{
get
{
return 'L';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionRefresh()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "refreshNode";
}
}
public string Icon
{
get
{
return "refresh";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return false;
}
}
public bool OpensDialog => false;
#endregion
}
}

View File

@@ -1,34 +0,0 @@
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when the content/media item is to be restored from the recycle bin
/// </summary>
public class ActionRestore : IAction
{
//create singleton
private ActionRestore() { }
public static ActionRestore Instance { get; } = new ActionRestore();
#region IAction Members
public char Letter => 'V';
public string JsFunctionName => null;
public string JsSource => null;
public string Alias => "restore";
public string Icon => "undo";
public bool ShowInNotifier => true;
public bool CanBePermissionAssigned => false;
public bool OpensDialog => true;
#endregion
}
}

View File

@@ -1,91 +0,0 @@
using System;
using Umbraco.Web.UI.Pages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when rights are changed on a document
/// </summary>
[ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)]
public class ActionRights : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionRights m_instance = new ActionRights();
#pragma warning restore 612,618
public static ActionRights Instance
{
get { return m_instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'R';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionRights()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "rights";
}
}
public string Icon
{
get
{
return "vcard";
}
}
public bool ShowInNotifier
{
get
{
return true;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
public bool OpensDialog => true;
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More