diff --git a/src/Umbraco.Core/CodeAnnotations/ActionMetadataAttribute.cs b/src/Umbraco.Core/CodeAnnotations/ActionMetadataAttribute.cs deleted file mode 100644 index 9ef87e9a5f..0000000000 --- a/src/Umbraco.Core/CodeAnnotations/ActionMetadataAttribute.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Umbraco.Core.Exceptions; - -namespace Umbraco.Core.CodeAnnotations -{ - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - internal class ActionMetadataAttribute : Attribute - { - public string Category { get; } - public string Name { get; } - - /// - /// Constructor used to assign a Category, since no name is assigned it will try to be translated from the language files based on the action's alias - /// - /// - public ActionMetadataAttribute(string category) - { - if (string.IsNullOrWhiteSpace(category)) throw new ArgumentNullOrEmptyException(nameof(category)); - Category = category; - } - - /// - /// Constructor used to assign an explicit name and category - /// - /// - /// - public ActionMetadataAttribute(string category, string name) - { - if (string.IsNullOrWhiteSpace(category)) throw new ArgumentNullOrEmptyException(nameof(category)); - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); - Category = category; - Name = name; - } - } -} diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 4f88c2b803..910717304c 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -37,101 +37,6 @@ namespace Umbraco.Core return dirty.WasPropertyDirty("Published") && entity.Published; } - /// - /// Returns a list of the current contents ancestors, not including the content itself. - /// - /// Current content - /// - /// An enumerable list of objects - public static IEnumerable Ancestors(this IContent content, IContentService contentService) - { - return contentService.GetAncestors(content); - } - - /// - /// Returns a list of the current contents children. - /// - /// Current content - /// - /// An enumerable list of objects - public static IEnumerable Children(this IContent content, IContentService contentService) - { - return contentService.GetChildren(content.Id); - } - - /// - /// Returns a list of the current contents descendants, not including the content itself. - /// - /// Current content - /// - /// An enumerable list of objects - public static IEnumerable Descendants(this IContent content, IContentService contentService) - { - return contentService.GetDescendants(content); - } - - /// - /// Returns the parent of the current content. - /// - /// Current content - /// - /// An object - public static IContent Parent(this IContent content, IContentService contentService) - { - return contentService.GetById(content.ParentId); - } - - #endregion - - #region IMedia - - /// - /// Returns a list of the current medias ancestors, not including the media itself. - /// - /// Current media - /// - /// An enumerable list of objects - public static IEnumerable Ancestors(this IMedia media, IMediaService mediaService) - { - return mediaService.GetAncestors(media); - } - - - /// - /// Returns a list of the current medias children. - /// - /// Current media - /// - /// An enumerable list of objects - public static IEnumerable Children(this IMedia media, IMediaService mediaService) - { - return mediaService.GetChildren(media.Id); - } - - - /// - /// Returns a list of the current medias descendants, not including the media itself. - /// - /// Current media - /// - /// An enumerable list of objects - public static IEnumerable Descendants(this IMedia media, IMediaService mediaService) - { - return mediaService.GetDescendants(media); - } - - - /// - /// Returns the parent of the current media. - /// - /// Current media - /// - /// An object - public static IMedia Parent(this IMedia media, IMediaService mediaService) - { - return mediaService.GetById(media.ParentId); - } - #endregion /// @@ -179,29 +84,7 @@ namespace Umbraco.Core } return false; } - - /// - /// Returns the children for the content base item - /// - /// - /// - /// - /// - /// This is a bit of a hack because we need to type check! - /// - internal static IEnumerable Children(IContentBase content, ServiceContext services) - { - if (content is IContent) - { - return services.ContentService.GetChildren(content.Id); - } - if (content is IMedia) - { - return services.MediaService.GetChildren(content.Id); - } - return null; - } - + /// /// Returns properties that do not belong to a group /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index f3afe99b28..b3a7c31e54 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private string VariantNameSqlExpression => SqlContext.VisitDto((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql; - protected virtual Sql GetBaseQuery(QueryType queryType, bool current) + protected Sql GetBaseQuery(QueryType queryType, bool current) { var sql = SqlContext.Sql(); diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index e418c8d3e6..5b64584dc6 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Services IEnumerable urlSegmentProviders, IContent content, bool published, - bool withDescendants = false) // fixme take care of usage! + bool withDescendants = false) //fixme take care of usage! only used for the packager { if (contentService == null) throw new ArgumentNullException(nameof(contentService)); if (dataTypeService == null) throw new ArgumentNullException(nameof(dataTypeService)); @@ -58,9 +58,15 @@ namespace Umbraco.Core.Services if (withDescendants) { - var descendants = contentService.GetDescendants(content).ToArray(); - var currentChildren = descendants.Where(x => x.ParentId == content.Id); - SerializeDescendants(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, descendants, currentChildren, xml, published); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) + { + var children = contentService.GetPagedChildren(content.Id, page++, pageSize, out total); + SerializeChildren(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, children, xml, published); + } + } return xml; @@ -103,9 +109,14 @@ namespace Umbraco.Core.Services if (withDescendants) { - var descendants = mediaService.GetDescendants(media).ToArray(); - var currentChildren = descendants.Where(x => x.ParentId == media.Id); - SerializeDescendants(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, descendants, currentChildren, xml); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while (page * pageSize < total) + { + var children = mediaService.GetPagedChildren(media.Id, page++, pageSize, out total); + SerializeChildren(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, children, xml); + } } return xml; @@ -451,7 +462,7 @@ namespace Umbraco.Core.Services } // exports an IContent item descendants. - private static void SerializeDescendants(IContentService contentService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IContent[] originalDescendants, IEnumerable children, XElement xml, bool published) + private static void SerializeChildren(IContentService contentService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IEnumerable children, XElement xml, bool published) { foreach (var child in children) { @@ -459,17 +470,20 @@ namespace Umbraco.Core.Services var childXml = Serialize(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, child, published); xml.Add(childXml); - // capture id (out of closure) and get the grandChildren (children of the child) - var parentId = child.Id; - var grandChildren = originalDescendants.Where(x => x.ParentId == parentId); - - // recurse - SerializeDescendants(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, originalDescendants, grandChildren, childXml, published); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) + { + var grandChildren = contentService.GetPagedChildren(child.Id, page++, pageSize, out total); + // recurse + SerializeChildren(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, grandChildren, childXml, published); + } } } // exports an IMedia item descendants. - private static void SerializeDescendants(IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IMedia[] originalDescendants, IEnumerable children, XElement xml) + private static void SerializeChildren(IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IEnumerable children, XElement xml) { foreach (var child in children) { @@ -477,12 +491,15 @@ namespace Umbraco.Core.Services var childXml = Serialize(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, child); xml.Add(childXml); - // capture id (out of closure) and get the grandChildren (children of the child) - var parentId = child.Id; - var grandChildren = originalDescendants.Where(x => x.ParentId == parentId); - - // recurse - SerializeDescendants(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, originalDescendants, grandChildren, childXml); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while (page * pageSize < total) + { + var grandChildren = mediaService.GetPagedChildren(child.Id, page++, pageSize, out total); + // recurse + SerializeChildren(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, grandChildren, childXml); + } } } } diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 7371686c7c..6cfc923ebe 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -78,26 +78,11 @@ namespace Umbraco.Core.Services /// IEnumerable GetByIds(IEnumerable ids); - /// - /// Gets documents of a given document type. - /// - IEnumerable GetByType(int documentTypeId); - /// /// Gets documents at a given level. /// IEnumerable GetByLevel(int level); - /// - /// Gets child documents of a given parent. - /// - IEnumerable GetChildren(int parentId); - - /// - /// Gets child documents of a document, (partially) matching a name. - /// - IEnumerable GetChildren(int parentId, string name); - /// /// Gets the parent of a document. /// @@ -118,16 +103,6 @@ namespace Umbraco.Core.Services /// IEnumerable GetAncestors(IContent content); - /// - /// Gets descendant documents of a document. - /// - IEnumerable GetDescendants(int id); - - /// - /// Gets descendant documents of a document. - /// - IEnumerable GetDescendants(IContent content); - /// /// Gets all versions of a document. /// @@ -169,19 +144,8 @@ namespace Umbraco.Core.Services /// /// Gets documents in the recycle bin. /// - IEnumerable GetContentInRecycleBin(); - - /// - /// Gets child documents of a parent. - /// - /// The parent identifier. - /// The page number. - /// The page size. - /// Total number of documents. - /// Search text filter. - /// Ordering infos. - IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - string filter = null, Ordering ordering = null); + IEnumerable GetPagedContentInRecycleBin(long pageIndex, int pageSize, out long totalRecords, + IQuery filter = null, Ordering ordering = null); /// /// Gets child documents of a parent. @@ -193,20 +157,7 @@ namespace Umbraco.Core.Services /// Query filter. /// Ordering infos. IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering ordering = null); - - /// - /// Gets descendant documents of a given parent. - /// - /// The parent identifier. - /// The page number. - /// The page size. - /// Total number of documents. - /// A field to order by. - /// The ordering direction. - /// Search text filter. - IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = ""); + IQuery filter = null, Ordering ordering = null); /// /// Gets descendant documents of a given parent. @@ -220,7 +171,31 @@ namespace Umbraco.Core.Services /// A flag indicating whether the ordering field is a system field. /// Query filter. IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter); + IQuery filter = null, Ordering ordering = null); + + /// + /// Gets paged documents of a content content + /// + /// The page number. + /// The page number. + /// The page size. + /// Total number of documents. + /// Search text filter. + /// Ordering infos. + IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords, + IQuery filter, Ordering ordering = null); + + /// + /// Gets paged documents for specified content types + /// + /// The page number. + /// The page number. + /// The page size. + /// Total number of documents. + /// Search text filter. + /// Ordering infos. + IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, + IQuery filter, Ordering ordering = null); /// /// Counts documents of a given document type. diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index 31c2e74fd4..9cc559ccd5 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -78,27 +78,6 @@ namespace Umbraco.Core.Services /// IMedia GetById(int id); - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// An Enumerable list of objects - IEnumerable GetChildren(int id); - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// Page number - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Search text filter - /// An Enumerable list of objects - IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = ""); - /// /// Gets a collection of objects by Parent Id /// @@ -112,37 +91,7 @@ namespace Umbraco.Core.Services /// /// An Enumerable list of objects IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter); - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// Page number - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Flag to indicate when ordering by system field - /// Search text filter - /// A list of content type Ids to filter the list by - /// An Enumerable list of objects - IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter); - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Descendants from - /// Page number - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Search text filter - /// An Enumerable list of objects - IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = ""); + IQuery filter = null, Ordering ordering = null); /// /// Gets a collection of objects by Parent Id @@ -157,21 +106,31 @@ namespace Umbraco.Core.Services /// /// An Enumerable list of objects IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter); + IQuery filter = null, Ordering ordering = null); /// - /// Gets descendants of a object by its Id + /// Gets paged documents of a content content /// - /// Id of the Parent to retrieve descendants from - /// An Enumerable flat list of objects - IEnumerable GetDescendants(int id); + /// The page number. + /// The page number. + /// The page size. + /// Total number of documents. + /// Search text filter. + /// Ordering infos. + IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords, + IQuery filter = null, Ordering ordering = null); /// - /// Gets a collection of objects by the Id of the + /// Gets paged documents for specified content types /// - /// Id of the - /// An Enumerable list of objects - IEnumerable GetMediaOfMediaType(int id); + /// The page number. + /// The page number. + /// The page size. + /// Total number of documents. + /// Search text filter. + /// Ordering infos. + IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, + IQuery filter = null, Ordering ordering = null); /// /// Gets a collection of objects, which reside at the first level / root @@ -183,7 +142,8 @@ namespace Umbraco.Core.Services /// Gets a collection of an objects, which resides in the Recycle Bin /// /// An Enumerable list of objects - IEnumerable GetMediaInRecycleBin(); + IEnumerable GetPagedMediaInRecycleBin(long pageIndex, int pageSize, out long totalRecords, + IQuery filter = null, Ordering ordering = null); /// /// Moves an object to a new location @@ -321,13 +281,6 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects IEnumerable GetAncestors(IMedia media); - /// - /// Gets descendants of a object by its Id - /// - /// The Parent object to retrieve descendants from - /// An Enumerable flat list of objects - IEnumerable GetDescendants(IMedia media); - /// /// Gets the parent of the current media as an item. /// diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index 9bb8e6720e..386c76db88 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -405,28 +405,40 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets a collection of objects by the Id of the - /// - /// Id of the - /// An Enumerable list of objects - public IEnumerable GetByType(int id) + /// + public IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords + , IQuery filter = null, Ordering ordering = null) { + if(pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); + if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + + if (ordering == null) + ordering = Ordering.By("sortOrder"); + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); - var query = Query().Where(x => x.ContentTypeId == id); - return _documentRepository.Get(query); + return _documentRepository.GetPage( + Query().Where(x => x.ContentTypeId == contentTypeId), + pageIndex, pageSize, out totalRecords, filter, ordering); } } - internal IEnumerable GetPublishedContentOfContentType(int id) + /// + public IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, IQuery filter, Ordering ordering = null) { + if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); + if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + + if (ordering == null) + ordering = Ordering.By("sortOrder"); + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); - var query = Query().Where(x => x.ContentTypeId == id); - return _documentRepository.Get(query); + return _documentRepository.GetPage( + Query().Where(x => contentTypeIds.Contains(x.ContentTypeId)), + pageIndex, pageSize, out totalRecords, filter, ordering); } } @@ -536,21 +548,6 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// An Enumerable list of objects - public IEnumerable GetChildren(int id) - { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.ContentTree); - var query = Query().Where(x => x.ParentId == id); - return _documentRepository.Get(query).OrderBy(x => x.SortOrder); - } - } - /// /// Gets a collection of published objects by Parent Id /// @@ -568,18 +565,7 @@ namespace Umbraco.Core.Services.Implement /// public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, - string filter = null, Ordering ordering = null) - { - var filterQuery = filter.IsNullOrWhiteSpace() - ? null - : Query().Where(x => x.Name.Contains(filter)); - - return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, filterQuery, ordering); - } - - /// - public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, - IQuery filter, Ordering ordering = null) + IQuery filter = null, Ordering ordering = null) { if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); @@ -597,27 +583,16 @@ namespace Umbraco.Core.Services.Implement } /// - public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") + public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, + IQuery filter = null, Ordering ordering = null) { - var filterQuery = filter.IsNullOrWhiteSpace() - ? null - : Query().Where(x => x.Name.Contains(filter)); - - return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery); - } - - /// - public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter) - { - if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); - if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + if (ordering == null) + ordering = Ordering.By("Path"); using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); - var query = Query(); - //if the id is System Root, then just get all if (id != Constants.System.Root) { @@ -627,65 +602,24 @@ namespace Umbraco.Core.Services.Implement totalChildren = 0; return Enumerable.Empty(); } - query.Where(x => x.Path.SqlStartsWith($"{contentPath[0].Path},", TextColumnType.NVarchar)); + return GetPagedDescendantsLocked(contentPath[0].Path, pageIndex, pageSize, out totalChildren, filter, ordering); } - - return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField)); + return GetPagedDescendantsLocked(null, pageIndex, pageSize, out totalChildren, filter, ordering); } } - /// - /// Gets a collection of objects by its name or partial name - /// - /// Id of the Parent to retrieve Children from - /// Full or partial name of the children - /// An Enumerable list of objects - public IEnumerable GetChildren(int parentId, string name) + private IEnumerable GetPagedDescendantsLocked(string contentPath, long pageIndex, int pageSize, out long totalChildren, + IQuery filter, Ordering ordering) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.ContentTree); - var query = Query().Where(x => x.ParentId == parentId && x.Name.Contains(name)); - return _documentRepository.Get(query); - } - } + if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); + if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + if (ordering == null) throw new ArgumentNullException(nameof(ordering)); - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Descendants from - /// An Enumerable list of objects - public IEnumerable GetDescendants(int id) - { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.ContentTree); - var content = GetById(id); - if (content == null) - { - scope.Complete(); // else causes rollback - return Enumerable.Empty(); - } - var pathMatch = content.Path + ","; - var query = Query().Where(x => x.Id != content.Id && x.Path.StartsWith(pathMatch)); - return _documentRepository.Get(query); - } - } + var query = Query(); + if (!contentPath.IsNullOrWhiteSpace()) + query.Where(x => x.Path.SqlStartsWith($"{contentPath},", TextColumnType.NVarchar)); - /// - /// Gets a collection of objects by Parent Id - /// - /// item to retrieve Descendants from - /// An Enumerable list of objects - public IEnumerable GetDescendants(IContent content) - { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.ContentTree); - var pathMatch = content.Path + ","; - var query = Query().Where(x => x.Id != content.Id && x.Path.StartsWith(pathMatch)); - return _documentRepository.Get(query); - } + return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering); } /// @@ -772,13 +706,17 @@ namespace Umbraco.Core.Services.Implement /// Gets a collection of an objects, which resides in the Recycle Bin /// /// An Enumerable list of objects - public IEnumerable GetContentInRecycleBin() + public IEnumerable GetPagedContentInRecycleBin(long pageIndex, int pageSize, out long totalRecords, + IQuery filter = null, Ordering ordering = null) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { + if (ordering == null) + ordering = Ordering.By("Path"); + scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.Path.StartsWith(Constants.System.RecycleBinContentPathPrefix)); - return _documentRepository.Get(query); + return _documentRepository.GetPage(query, pageIndex, pageSize, out totalRecords, filter, ordering); } } @@ -871,7 +809,7 @@ namespace Umbraco.Core.Services.Implement var langs = string.Join(", ", _languageRepository.GetMany() .Where(x => culturesChanging.InvariantContains(x.IsoCode)) .Select(x => x.CultureName)); - Audit(AuditType.SaveVariant, userId, content.Id, $"Saved languagues: {langs}", langs); + Audit(AuditType.SaveVariant, userId, content.Id, $"Saved languages: {langs}", langs); } else Audit(AuditType.Save, userId, content.Id); @@ -1355,27 +1293,35 @@ namespace Umbraco.Core.Services.Implement // if one fails, abort its branch var exclude = new HashSet(); - //fixme: should be paged to not overwhelm the database (timeouts) - foreach (var d in GetDescendants(document)) + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while (page * pageSize < total) { - // if parent is excluded, exclude document and ignore - // if not forcing, and not publishing, exclude document and ignore - if (exclude.Contains(d.ParentId) || !force && !d.Published) + var descendants = GetPagedDescendants(document.Id, page++, pageSize, out total); + + foreach (var d in descendants) { + // if parent is excluded, exclude document and ignore + // if not forcing, and not publishing, exclude document and ignore + if (exclude.Contains(d.ParentId) || !force && !d.Published) + { + exclude.Add(d.Id); + continue; + } + + // no need to check path here, + // 1. because we know the parent is path-published (we just published it) + // 2. because it would not work as nothing's been written out to the db until the uow completes + result = SaveAndPublishBranchOne(scope, d, editing, publishCultures, false, publishedDocuments, evtMsgs, userId); + results.Add(result); + if (result.Success) continue; + + // abort branch exclude.Add(d.Id); - continue; } - - // no need to check path here, - // 1. because we know the parent is path-published (we just published it) - // 2. because it would not work as nothing's been written out to the db until the uow completes - result = SaveAndPublishBranchOne(scope, d, editing, publishCultures, false, publishedDocuments, evtMsgs, userId); - results.Add(result); - if (result.Success) continue; - - // abort branch - exclude.Add(d.Id); } + scope.Events.Dispatch(TreeChanged, this, new TreeChange(document, TreeChangeTypes.RefreshBranch).ToEventArgs()); scope.Events.Dispatch(Published, this, new PublishEventArgs(publishedDocuments, false, false), "Published"); @@ -1458,25 +1404,8 @@ namespace Umbraco.Core.Services.Implement private void DeleteLocked(IScope scope, IContent content) { - // then recursively delete descendants, bottom-up - // just repository.Delete + an event - var stack = new Stack(); - stack.Push(content); - var level = 1; - while (stack.Count > 0) + void DoDelete(IContent c) { - var c = stack.Peek(); - IContent[] cc; - if (c.Level == level) - while ((cc = c.Children(this).ToArray()).Length > 0) - { - foreach (var ci in cc) - stack.Push(ci); - c = cc[cc.Length - 1]; - } - c = stack.Pop(); - level = c.Level; - _documentRepository.Delete(c); var args = new DeleteEventArgs(c, false); // raise event & get flagged files scope.Events.Dispatch(Deleted, this, args, nameof(Deleted)); @@ -1485,6 +1414,18 @@ namespace Umbraco.Core.Services.Implement _mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files (file, e) => Logger.Error(e, "An error occurred while deleting file attached to nodes: {File}", file)); } + + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while (page * pageSize < total) + { + //get descendants - ordered from deepest to shallowest + var descendants = GetPagedDescendants(content.Id, page, pageSize, out total, ordering: Ordering.By("Path", Direction.Descending)); + foreach (var c in descendants) + DoDelete(c); + } + DoDelete(content); } //TODO: @@ -1694,8 +1635,8 @@ namespace Umbraco.Core.Services.Implement moves.Add(Tuple.Create(content, content.Path)); // capture original path - // get before moving, in case uow is immediate - var descendants = GetDescendants(content); + //need to store the original path to lookup descendants based on it below + var originalPath = content.Path; // these will be updated by the repo because we changed parentId //content.Path = (parent == null ? "-1" : parent.Path) + "," + content.Id; @@ -1708,22 +1649,28 @@ namespace Umbraco.Core.Services.Implement //paths[content.Id] = content.Path; paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : "-1") : parent.Path) + "," + content.Id; - foreach (var descendant in descendants) + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) { - moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path + var descendants = GetPagedDescendantsLocked(originalPath, page++, pageSize, out total, null, Ordering.By("Path", Direction.Ascending)); + foreach (var descendant in descendants) + { + moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path - // update path and level since we do not update parentId - if (paths.ContainsKey(descendant.ParentId) == false) - Console.WriteLine("oops on " + descendant.ParentId + " for " + content.Path + " " + parent?.Path); - descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id; - Console.WriteLine("path " + descendant.Id + " = " + paths[descendant.Id]); - descendant.Level += levelDelta; - PerformMoveContentLocked(descendant, userId, trash); + // update path and level since we do not update parentId + descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id; + descendant.Level += levelDelta; + PerformMoveContentLocked(descendant, userId, trash); + } } + } private void PerformMoveContentLocked(IContent content, int userId, bool? trash) { + //fixme no casting if (trash.HasValue) ((ContentBase) content).Trashed = trash.Value; content.WriterId = userId; _documentRepository.Save(content); @@ -1852,29 +1799,36 @@ namespace Umbraco.Core.Services.Implement if (recursive) // process descendants { - foreach (var descendant in GetDescendants(content)) + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) { - // if parent has not been copied, skip, else gets its copy id - if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue; + var descendants = GetPagedDescendants(content.Id, page++, pageSize, out total); + foreach (var descendant in descendants) + { + // if parent has not been copied, skip, else gets its copy id + if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue; - var descendantCopy = descendant.DeepCloneWithResetIdentities(); - descendantCopy.ParentId = parentId; + var descendantCopy = descendant.DeepCloneWithResetIdentities(); + descendantCopy.ParentId = parentId; - if (scope.Events.DispatchCancelable(Copying, this, new CopyEventArgs(descendant, descendantCopy, parentId))) - continue; + if (scope.Events.DispatchCancelable(Copying, this, new CopyEventArgs(descendant, descendantCopy, parentId))) + continue; - // a copy is not published (but not really unpublishing either) - // update the create author and last edit author - if (descendantCopy.Published) - ((Content) descendantCopy).Published = false; - descendantCopy.CreatorId = userId; - descendantCopy.WriterId = userId; + // a copy is not published (but not really unpublishing either) + // update the create author and last edit author + if (descendantCopy.Published) + ((Content)descendantCopy).Published = false; + descendantCopy.CreatorId = userId; + descendantCopy.WriterId = userId; - // save and flush (see above) - _documentRepository.Save(descendantCopy); + // save and flush (see above) + _documentRepository.Save(descendantCopy); - copies.Add(Tuple.Create(descendant, descendantCopy)); - idmap[descendant.Id] = descendantCopy.Id; + copies.Add(Tuple.Create(descendant, descendantCopy)); + idmap[descendant.Id] = descendantCopy.Id; + } } } diff --git a/src/Umbraco.Core/Services/Implement/MediaService.cs b/src/Umbraco.Core/Services/Implement/MediaService.cs index da04f41e18..5f35e35acf 100644 --- a/src/Umbraco.Core/Services/Implement/MediaService.cs +++ b/src/Umbraco.Core/Services/Implement/MediaService.cs @@ -364,18 +364,39 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets a collection of objects by the Id of the - /// - /// Id of the - /// An Enumerable list of objects - public IEnumerable GetMediaOfMediaType(int id) + /// + public IEnumerable GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords, IQuery filter = null, Ordering ordering = null) { + if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); + if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + + if (ordering == null) + ordering = Ordering.By("sortOrder"); + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - scope.ReadLock(Constants.Locks.MediaTree); - var query = Query().Where(x => x.ContentTypeId == id); - return _mediaRepository.Get(query); + scope.ReadLock(Constants.Locks.ContentTree); + return _mediaRepository.GetPage( + Query().Where(x => x.ContentTypeId == contentTypeId), + pageIndex, pageSize, out totalRecords, filter, ordering); + } + } + + /// + public IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, IQuery filter = null, Ordering ordering = null) + { + if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); + if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + + if (ordering == null) + ordering = Ordering.By("sortOrder"); + + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + { + scope.ReadLock(Constants.Locks.ContentTree); + return _mediaRepository.GetPage( + Query().Where(x => contentTypeIds.Contains(x.ContentTypeId)), + pageIndex, pageSize, out totalRecords, filter, ordering); } } @@ -460,149 +481,36 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// An Enumerable list of objects - public IEnumerable GetChildren(int id) - { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.MediaTree); - var query = Query().Where(x => x.ParentId == id); - return _mediaRepository.Get(query).OrderBy(x => x.SortOrder); - } - } - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// Page index (zero based) - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Search text filter - /// An Enumerable list of objects - public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, string filter = "") - { - var filterQuery = filter.IsNullOrWhiteSpace() - ? null - : Query().Where(x => x.Name.Contains(filter)); - - return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery); - } - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// Page index (zero based) - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Flag to indicate when ordering by system field - /// - /// An Enumerable list of objects - public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter) + /// + public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, + IQuery filter = null, Ordering ordering = null) { if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + if (ordering == null) + ordering = Ordering.By("sortOrder"); + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.MediaTree); var query = Query().Where(x => x.ParentId == id); - return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField)); + return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering); } } - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// Page number - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Flag to indicate when ordering by system field - /// Search text filter - /// A list of content type Ids to filter the list by - /// An Enumerable list of objects - public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter) + /// + public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, + IQuery filter = null, Ordering ordering = null) { - if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); - if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + if (ordering == null) + ordering = Ordering.By("Path"); using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.MediaTree); - var query = Query(); - // always check for a parent - else it will also get decendants (and then you should use the GetPagedDescendants method) - - query.Where(x => x.ParentId == id); - - if (contentTypeFilter != null && contentTypeFilter.Length > 0) - { - query.Where(x => contentTypeFilter.Contains(x.ContentTypeId)); - } - - var filterQuery = filter.IsNullOrWhiteSpace() - ? null - : Query().Where(x => x.Name.Contains(filter)); - return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filterQuery, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField)); - } - } - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Descendants from - /// Page number - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Search text filter - /// An Enumerable list of objects - public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") - { - var filterQuery = filter.IsNullOrWhiteSpace() - ? null - : Query().Where(x => x.Name.Contains(filter)); - - return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery); - } - - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Descendants from - /// Page number - /// Page size - /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Flag to indicate when ordering by system field - /// - /// An Enumerable list of objects - public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter) - { - if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); - if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); - - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.MediaTree); - - var query = Query(); - //if the id is System Root, then just get all if (id != Constants.System.Root) { @@ -612,47 +520,24 @@ namespace Umbraco.Core.Services.Implement totalChildren = 0; return Enumerable.Empty(); } - query.Where(x => x.Path.SqlStartsWith(mediaPath[0].Path + ",", TextColumnType.NVarchar)); + return GetPagedDescendantsLocked(mediaPath[0].Path, pageIndex, pageSize, out totalChildren, filter, ordering); } - - return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField)); + return GetPagedDescendantsLocked(null, pageIndex, pageSize, out totalChildren, filter, ordering); } } - /// - /// Gets descendants of a object by its Id - /// - /// Id of the Parent to retrieve descendants from - /// An Enumerable flat list of objects - public IEnumerable GetDescendants(int id) + private IEnumerable GetPagedDescendantsLocked(string mediaPath, long pageIndex, int pageSize, out long totalChildren, + IQuery filter, Ordering ordering) { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.MediaTree); - var media = GetById(id); - if (media == null) - return Enumerable.Empty(); + if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); + if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); + if (ordering == null) throw new ArgumentNullException(nameof(ordering)); - var pathMatch = media.Path + ","; - var query = Query().Where(x => x.Id != media.Id && x.Path.StartsWith(pathMatch)); - return _mediaRepository.Get(query); - } - } + var query = Query(); + if (!mediaPath.IsNullOrWhiteSpace()) + query.Where(x => x.Path.SqlStartsWith(mediaPath + ",", TextColumnType.NVarchar)); - /// - /// Gets descendants of a object by its Id - /// - /// The Parent object to retrieve descendants from - /// An Enumerable flat list of objects - public IEnumerable GetDescendants(IMedia media) - { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - scope.ReadLock(Constants.Locks.MediaTree); - var pathMatch = media.Path + ","; - var query = Query().Where(x => x.Id != media.Id && x.Path.StartsWith(pathMatch)); - return _mediaRepository.Get(query); - } + return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering); } /// @@ -694,17 +579,18 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets a collection of an objects, which resides in the Recycle Bin - /// - /// An Enumerable list of objects - public IEnumerable GetMediaInRecycleBin() + /// + public IEnumerable GetPagedMediaInRecycleBin(long pageIndex, int pageSize, out long totalRecords, + IQuery filter = null, Ordering ordering = null) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { + if (ordering == null) + ordering = Ordering.By("Path"); + scope.ReadLock(Constants.Locks.MediaTree); var query = Query().Where(x => x.Path.StartsWith(Constants.System.RecycleBinMediaPathPrefix)); - return _mediaRepository.Get(query); + return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalRecords, filter, ordering); } } @@ -865,25 +751,8 @@ namespace Umbraco.Core.Services.Implement private void DeleteLocked(IScope scope, IMedia media) { - // then recursively delete descendants, bottom-up - // just repository.Delete + an event - var stack = new Stack(); - stack.Push(media); - var level = 1; - while (stack.Count > 0) + void DoDelete(IMedia c) { - var c = stack.Peek(); - IMedia[] cc; - if (c.Level == level) - while ((cc = c.Children(this).ToArray()).Length > 0) - { - foreach (var ci in cc) - stack.Push(ci); - c = cc[cc.Length - 1]; - } - c = stack.Pop(); - level = c.Level; - _mediaRepository.Delete(c); var args = new DeleteEventArgs(c, false); // raise event & get flagged files scope.Events.Dispatch(Deleted, this, args); @@ -891,6 +760,18 @@ namespace Umbraco.Core.Services.Implement _mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files (file, e) => Logger.Error(e, "An error occurred while deleting file attached to nodes: {File}", file)); } + + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) + { + //get descendants - ordered from deepest to shallowest + var descendants = GetPagedDescendants(media.Id, page, pageSize, out total, ordering: Ordering.By("Path", Direction.Descending)); + foreach (var c in descendants) + DoDelete(c); + } + DoDelete(media); } //TODO: @@ -1100,8 +981,8 @@ namespace Umbraco.Core.Services.Implement moves.Add(Tuple.Create(media, media.Path)); // capture original path - // get before moving, in case uow is immediate - var descendants = GetDescendants(media); + //need to store the original path to lookup descendants based on it below + var originalPath = media.Path; // these will be updated by the repo because we changed parentId //media.Path = (parent == null ? "-1" : parent.Path) + "," + media.Id; @@ -1114,14 +995,21 @@ namespace Umbraco.Core.Services.Implement //paths[media.Id] = media.Path; paths[media.Id] = (parent == null ? (parentId == Constants.System.RecycleBinMedia ? "-1,-21" : "-1") : parent.Path) + "," + media.Id; - foreach (var descendant in descendants) + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while (page * pageSize < total) { - moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path + var descendants = GetPagedDescendantsLocked(originalPath, page++, pageSize, out total, null, Ordering.By("Path", Direction.Ascending)); + foreach (var descendant in descendants) + { + moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path - // update path and level since we do not update parentId - descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id; - descendant.Level += levelDelta; - PerformMoveMediaLocked(descendant, userId, trash); + // update path and level since we do not update parentId + descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id; + descendant.Level += levelDelta; + PerformMoveMediaLocked(descendant, userId, trash); + } } } diff --git a/src/Umbraco.Core/Services/Implement/MemberService.cs b/src/Umbraco.Core/Services/Implement/MemberService.cs index 3fd714f974..5a644cfec1 100644 --- a/src/Umbraco.Core/Services/Implement/MemberService.cs +++ b/src/Umbraco.Core/Services/Implement/MemberService.cs @@ -393,12 +393,14 @@ namespace Umbraco.Core.Services.Implement // fixme get rid of string filter? - public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "") + public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, + string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "") { return GetAll(pageIndex, pageSize, out totalRecords, orderBy, orderDirection, true, memberTypeAlias, filter); } - public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, bool orderBySystemField, string memberTypeAlias, string filter) + public IEnumerable GetAll(long pageIndex, int pageSize, out long totalRecords, + string orderBy, Direction orderDirection, bool orderBySystemField, string memberTypeAlias, string filter) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 45f8b5ec52..acda9ef589 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -143,7 +143,6 @@ - diff --git a/src/Umbraco.Examine/UmbracoContentIndexer.cs b/src/Umbraco.Examine/UmbracoContentIndexer.cs index 94982c8591..fab9f226a4 100644 --- a/src/Umbraco.Examine/UmbracoContentIndexer.cs +++ b/src/Umbraco.Examine/UmbracoContentIndexer.cs @@ -258,7 +258,8 @@ namespace Umbraco.Examine else { //add the published filter - descendants = ContentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total, "Path", Direction.Ascending, true, _publishedQuery); + descendants = ContentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total, + _publishedQuery, Ordering.By("Path", Direction.Ascending)); } //if specific types are declared we need to post filter them diff --git a/src/Umbraco.Examine/UmbracoExamineIndexer.cs b/src/Umbraco.Examine/UmbracoExamineIndexer.cs index 64fd7b5c71..a4c1fb4336 100644 --- a/src/Umbraco.Examine/UmbracoExamineIndexer.cs +++ b/src/Umbraco.Examine/UmbracoExamineIndexer.cs @@ -418,7 +418,7 @@ namespace Umbraco.Examine //icon if (e.IndexItem.ValueSet.Values.TryGetValue("icon", out var icon) && e.IndexItem.ValueSet.Values.ContainsKey(IconFieldName) == false) { - e.IndexItem.ValueSet.Values[IconFieldName] = new List { icon }; + e.IndexItem.ValueSet.Values[IconFieldName] = icon; } } diff --git a/src/Umbraco.Examine/UmbracoMemberIndexer.cs b/src/Umbraco.Examine/UmbracoMemberIndexer.cs index b7cbcc19bc..82bf3b9cf6 100644 --- a/src/Umbraco.Examine/UmbracoMemberIndexer.cs +++ b/src/Umbraco.Examine/UmbracoMemberIndexer.cs @@ -175,13 +175,17 @@ namespace Umbraco.Examine if (e.IndexItem.ValueSet.Values.TryGetValue("key", out var key) && e.IndexItem.ValueSet.Values.ContainsKey("__key") == false) { //double __ prefix means it will be indexed as culture invariant - e.IndexItem.ValueSet.Values["__key"] = new List { key }; + e.IndexItem.ValueSet.Values["__key"] = key; } if (e.IndexItem.ValueSet.Values.TryGetValue("email", out var email) && e.IndexItem.ValueSet.Values.ContainsKey("_searchEmail") == false) { - //will be indexed as full text (the default anaylyzer) - e.IndexItem.ValueSet.Values["_searchEmail"] = new List { email?.ToString().Replace(".", " ").Replace("@", " ") }; + if (email.Count > 0) + { + //will be indexed as full text (the default anaylyzer) + e.IndexItem.ValueSet.Values["_searchEmail"] = new List { email[0]?.ToString().Replace(".", " ").Replace("@", " ") }; + } + } } diff --git a/src/Umbraco.Tests/Composing/ActionCollectionTests.cs b/src/Umbraco.Tests/Composing/ActionCollectionTests.cs deleted file mode 100644 index 46e4eee765..0000000000 --- a/src/Umbraco.Tests/Composing/ActionCollectionTests.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Linq; -using NUnit.Framework; -using Umbraco.Web; -using Umbraco.Web.UI.Pages; -using Umbraco.Web._Legacy.Actions; - -namespace Umbraco.Tests.Composing -{ - [TestFixture] - public class ActionCollectionTests : ComposingTestBase - { - [Test] - public void ActionCollectionBuilderWorks() - { - var collectionBuilder = new ActionCollectionBuilder(); - collectionBuilder.SetProducer(() => TypeLoader.GetActions()); - - var actions = collectionBuilder.CreateCollection(); - Assert.AreEqual(2, actions.Count()); - - // order is unspecified, but both must be there - var hasAction1 = actions.ElementAt(0) is SingletonAction || actions.ElementAt(1) is SingletonAction; - var hasAction2 = actions.ElementAt(0) is NonSingletonAction || actions.ElementAt(1) is NonSingletonAction; - Assert.IsTrue(hasAction1); - Assert.IsTrue(hasAction2); - - var singletonAction = (SingletonAction) (actions.ElementAt(0) is SingletonAction ? actions.ElementAt(0) : actions.ElementAt(1)); - - // ensure it is a singleton - Assert.AreSame(SingletonAction.Instance, singletonAction); - } - - #region Test Objects - - public class SingletonAction : IAction - { - public static SingletonAction Instance { get; } = new SingletonAction(); - - public char Letter => 'I'; - - public string JsFunctionName => $"{ClientTools.Scripts.GetAppActions}.actionAssignDomain()"; - - public string JsSource => null; - - public string Alias => "assignDomain"; - - public string Icon => ".sprDomain"; - - public bool ShowInNotifier => false; - - public bool CanBePermissionAssigned => true; - - public bool OpensDialog => true; - } - - public class NonSingletonAction : IAction - { - public char Letter => 'Q'; - - public string JsFunctionName => $"{ClientTools.Scripts.GetAppActions}.actionAssignDomain()"; - - public string JsSource => null; - - public string Alias => "asfasdf"; - - public string Icon => ".sprDomain"; - - public bool ShowInNotifier => false; - - public bool CanBePermissionAssigned => true; - - public bool OpensDialog => true; - } - - #endregion - } -} diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 829c488af3..07625db9bf 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -268,13 +268,6 @@ AnotherContentFinder Assert.AreEqual(2, foundTypes1.Count()); } - [Test] - public void Resolves_Actions() - { - var actions = _typeLoader.GetActions(); - Assert.AreEqual(33, actions.Count()); - } - [Test] public void GetDataEditors() { diff --git a/src/Umbraco.Tests/Integration/ContentEventsTests.cs b/src/Umbraco.Tests/Integration/ContentEventsTests.cs index 4ca63e9e96..af188c6a09 100644 --- a/src/Umbraco.Tests/Integration/ContentEventsTests.cs +++ b/src/Umbraco.Tests/Integration/ContentEventsTests.cs @@ -459,7 +459,7 @@ namespace Umbraco.Tests.Integration #region Utils private IEnumerable Children(IContent content) - => ServiceContext.ContentService.GetChildren(content.Id); + => ServiceContext.ContentService.GetPagedChildren(content.Id, 0, int.MaxValue, out var total); #endregion @@ -846,22 +846,18 @@ namespace Umbraco.Tests.Integration // force:true => all nodes are republished, refreshing all nodes - but only with changes - published w/out changes are not repub Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.u+p", _events[i++].ToString()); - //Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p+p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u+p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p+p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u+p", _events[i++].ToString()); - - // remember: ordered by level, sortOrder //Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p+p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u+p", _events[i++].ToString()); - //Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p+p", _events[i++].ToString()); - //Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p+p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u+p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u+p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u+p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u+p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p+p", _events[i++].ToString()); + //Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p+p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u+p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u+p", _events[i++].ToString()); + //Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p+p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[1].Id}.u+p", _events[i++].ToString()); - Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); // repub content1 } @@ -1073,17 +1069,18 @@ namespace Umbraco.Tests.Integration Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=m", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); + m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i].ToString()); } @@ -1706,16 +1703,16 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=m", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); @@ -1759,16 +1756,16 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); @@ -1816,16 +1813,16 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=m", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=m", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); @@ -1871,16 +1868,16 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); @@ -1925,16 +1922,16 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); @@ -1984,16 +1981,16 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1.Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[2].Id}.p=p", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[0].Id}.p=p", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content1C[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{content5C[0].Id}.p=m", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content1.Id}", _events[i++].ToString()); @@ -2098,16 +2095,16 @@ namespace Umbraco.Tests.Integration var m = 0; Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy.Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[1].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[2].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[3].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy2C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy3C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy4C[0].Id}.u=u", _events[i++].ToString()); - Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy5C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy2C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy3C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy3C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[2].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy4C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy4C[1].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copyC[3].Id}.u=u", _events[i++].ToString()); + Assert.AreEqual($"{m++:000}: ContentRepository/Refresh/{copy5C[0].Id}.u=u", _events[i++].ToString()); Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{copy5C[1].Id}.u=u", _events[i++].ToString()); m++; Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{copy.Id}", _events[i].ToString()); diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs b/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs index 21a75b2e24..570fbfb7e3 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs @@ -125,10 +125,6 @@ namespace Umbraco.Tests.Persistence.NPocoTests contentService.GetByLevel(2); - contentService.GetChildren(id1); - - contentService.GetDescendants(id2); - contentService.GetVersions(id3); contentService.GetRootContent(); @@ -137,8 +133,6 @@ namespace Umbraco.Tests.Persistence.NPocoTests contentService.GetContentForRelease(); - contentService.GetContentInRecycleBin(); - ((ContentService)contentService).GetPublishedDescendants(new Content("Test", -1, new ContentType(-1)) { Id = id1, diff --git a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs index 28021f1e22..4326eee273 100644 --- a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs @@ -105,7 +105,7 @@ namespace Umbraco.Tests.Services total.AddRange(ServiceContext.ContentService.GetRootContent()); foreach (var content in total.ToArray()) { - total.AddRange(ServiceContext.ContentService.GetDescendants(content)); + total.AddRange(ServiceContext.ContentService.GetPagedDescendants(content.Id, 0, int.MaxValue, out var _)); } TestProfiler.Disable(); Current.Logger.Info("Returned " + total.Count + " items"); diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index c5bbe197ef..d5d74ee754 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -35,7 +35,10 @@ namespace Umbraco.Tests.Services /// as well as configuration. /// [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] public class ContentServiceTests : TestWithSomeContentBase { //TODO Add test to verify there is only ONE newest document/content in {Constants.DatabaseSchema.Tables.Document} table after updating. @@ -1038,37 +1041,6 @@ namespace Umbraco.Tests.Services Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(2)); } - [Test] - public void Can_Get_Children_Of_Content_Id() - { - // Arrange - var contentService = ServiceContext.ContentService; - - // Act - var contents = contentService.GetChildren(NodeDto.NodeIdSeed + 2).ToList(); - - // Assert - Assert.That(contents, Is.Not.Null); - Assert.That(contents.Any(), Is.True); - Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(2)); - } - - [Test] - public void Can_Get_Descendents_Of_Content() - { - // Arrange - var contentService = ServiceContext.ContentService; - var hierarchy = CreateContentHierarchy(); - contentService.Save(hierarchy, 0); - - // Act - var contents = contentService.GetDescendants(NodeDto.NodeIdSeed + 2).ToList(); - - // Assert - Assert.That(contents, Is.Not.Null); - Assert.That(contents.Any(), Is.True); - Assert.That(contents.Count(), Is.EqualTo(52)); - } [Test] public void Can_Get_All_Versions_Of_Content() @@ -1200,7 +1172,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act - var contents = contentService.GetContentInRecycleBin().ToList(); + var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents, Is.Not.Null); @@ -1240,7 +1212,7 @@ namespace Umbraco.Tests.Services { // Arrange - var langUk = new Language("en-UK") { IsDefault = true }; + var langUk = new Language("en-GB") { IsDefault = true }; var langFr = new Language("fr-FR"); ServiceContext.LocalizationService.Save(langFr); @@ -1476,8 +1448,16 @@ namespace Umbraco.Tests.Services var parent = contentService.GetById(parentId); Console.WriteLine(" " + parent.Id); - foreach (var x in contentService.GetDescendants(parent)) - Console.WriteLine(" ".Substring(0, x.Level) + x.Id); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) + { + var descendants = contentService.GetPagedDescendants(parent.Id, page++, pageSize, out total); + foreach (var x in descendants) + Console.WriteLine(" ".Substring(0, x.Level) + x.Id); + } + Console.WriteLine(); // publish parent & its branch @@ -1492,7 +1472,7 @@ namespace Umbraco.Tests.Services Assert.IsTrue(parentPublished.All(x => x.Success)); Assert.IsTrue(parent.Published); - var children = contentService.GetChildren(parentId); + var children = contentService.GetPagedChildren(parentId, 0, 500, out var totalChildren); //we only want the first so page size, etc.. is abitrary // children are published including ... that was released 5 mins ago Assert.IsTrue(children.First(x => x.Id == NodeDto.NodeIdSeed + 4).Published); @@ -1738,7 +1718,7 @@ namespace Umbraco.Tests.Services // Act contentService.DeleteOfType(contentType.Id); var rootContent = contentService.GetRootContent(); - var contents = contentService.GetByType(contentType.Id); + var contents = contentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out var _, null); // Assert Assert.That(rootContent.Any(), Is.False); @@ -1785,7 +1765,13 @@ namespace Umbraco.Tests.Services contentService.Save(subsubpage, 0); var content = contentService.GetById(NodeDto.NodeIdSeed + 2); - var descendants = contentService.GetDescendants(content).ToList(); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + var descendants = new List(); + while(page * pageSize < total) + descendants.AddRange(contentService.GetPagedDescendants(content.Id, page++, pageSize, out total)); + Assert.AreNotEqual(-20, content.ParentId); Assert.IsFalse(content.Trashed); Assert.AreEqual(3, descendants.Count); @@ -1793,7 +1779,11 @@ namespace Umbraco.Tests.Services Assert.IsFalse(descendants.Any(x => x.Trashed)); contentService.MoveToRecycleBin(content, 0); - descendants = contentService.GetDescendants(content).ToList(); + + descendants.Clear(); + page = 0; + while (page * pageSize < total) + descendants.AddRange(contentService.GetPagedDescendants(content.Id, page++, pageSize, out total)); Assert.AreEqual(-20, content.ParentId); Assert.IsTrue(content.Trashed); @@ -1802,7 +1792,7 @@ namespace Umbraco.Tests.Services Assert.True(descendants.All(x => x.Trashed)); contentService.EmptyRecycleBin(); - var trashed = contentService.GetContentInRecycleBin(); + var trashed = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); Assert.IsEmpty(trashed); } @@ -1814,7 +1804,7 @@ namespace Umbraco.Tests.Services // Act contentService.EmptyRecycleBin(); - var contents = contentService.GetContentInRecycleBin(); + var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents.Any(), Is.False); @@ -1883,8 +1873,13 @@ namespace Umbraco.Tests.Services ServiceContext.ContentService.Save(childPage3); //Verify that the children have the inherited permissions - var descendants = ServiceContext.ContentService.GetDescendants(parentPage).ToArray(); - Assert.AreEqual(3, descendants.Length); + var descendants = new List(); + const int pageSize = 500; + var page = 0; + var total = long.MaxValue; + while(page * pageSize < total) + descendants.AddRange(ServiceContext.ContentService.GetPagedDescendants(parentPage.Id, page++, pageSize, out total)); + Assert.AreEqual(3, descendants.Count); foreach (var descendant in descendants) { @@ -1902,8 +1897,11 @@ namespace Umbraco.Tests.Services //Now copy, what should happen is the child pages will now have permissions inherited from the new parent var copy = ServiceContext.ContentService.Copy(childPage1, parentPage2.Id, false, true); - descendants = ServiceContext.ContentService.GetDescendants(parentPage2).ToArray(); - Assert.AreEqual(3, descendants.Length); + descendants.Clear(); + page = 0; + while (page * pageSize < total) + descendants.AddRange(ServiceContext.ContentService.GetPagedDescendants(parentPage2.Id, page++, pageSize, out total)); + Assert.AreEqual(3, descendants.Count); foreach (var descendant in descendants) { @@ -1984,7 +1982,7 @@ namespace Umbraco.Tests.Services // Act ServiceContext.ContentService.MoveToRecycleBin(content1); ServiceContext.ContentService.EmptyRecycleBin(); - var contents = ServiceContext.ContentService.GetContentInRecycleBin(); + var contents = ServiceContext.ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents.Any(), Is.False); @@ -2035,7 +2033,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; var temp = contentService.GetById(NodeDto.NodeIdSeed + 2); Assert.AreEqual("Home", temp.Name); - Assert.AreEqual(2, temp.Children(contentService).Count()); + Assert.AreEqual(2, contentService.CountChildren(temp.Id)); // Act var copy = contentService.Copy(temp, temp.ParentId, false, true, 0); @@ -2045,10 +2043,10 @@ namespace Umbraco.Tests.Services Assert.That(copy, Is.Not.Null); Assert.That(copy.Id, Is.Not.EqualTo(content.Id)); Assert.AreNotSame(content, copy); - Assert.AreEqual(2, copy.Children(contentService).Count()); + Assert.AreEqual(2, contentService.CountChildren(copy.Id)); var child = contentService.GetById(NodeDto.NodeIdSeed + 3); - var childCopy = copy.Children(contentService).First(); + var childCopy = contentService.GetPagedChildren(copy.Id, 0, 500, out var total).First(); Assert.AreEqual(childCopy.Name, child.Name); Assert.AreNotEqual(childCopy.Id, child.Id); Assert.AreNotEqual(childCopy.Key, child.Key); @@ -2061,7 +2059,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; var temp = contentService.GetById(NodeDto.NodeIdSeed + 2); Assert.AreEqual("Home", temp.Name); - Assert.AreEqual(2, temp.Children(contentService).Count()); + Assert.AreEqual(2, contentService.CountChildren(temp.Id)); // Act var copy = contentService.Copy(temp, temp.ParentId, false, false, 0); @@ -2071,7 +2069,7 @@ namespace Umbraco.Tests.Services Assert.That(copy, Is.Not.Null); Assert.That(copy.Id, Is.Not.EqualTo(content.Id)); Assert.AreNotSame(content, copy); - Assert.AreEqual(0, copy.Children(contentService).Count()); + Assert.AreEqual(0, contentService.CountChildren(copy.Id)); } [Test] @@ -2780,7 +2778,7 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - var langUk = new Language("en-UK") { IsDefault = true }; + var langUk = new Language("en-GB") { IsDefault = true }; var langFr = new Language("fr-FR"); languageService.Save(langFr); @@ -2815,7 +2813,7 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - var langUk = new Language("en-UK") { IsDefault = true }; + var langUk = new Language("en-GB") { IsDefault = true }; var langFr = new Language("fr-FR"); languageService.Save(langFr); @@ -2852,7 +2850,7 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - var langUk = new Language("en-UK") { IsDefault = true }; + var langUk = new Language("en-GB") { IsDefault = true }; var langFr = new Language("fr-FR"); var langDa = new Language("da-DK"); @@ -2944,7 +2942,7 @@ namespace Umbraco.Tests.Services private void WriteList(List list) { foreach (var content in list) - Console.WriteLine("[{0}] {1} {2} {3} {4}", content.Id, content.Name, content.GetCultureName("en-UK"), content.GetCultureName("fr-FR"), content.GetCultureName("da-DK")); + Console.WriteLine("[{0}] {1} {2} {3} {4}", content.Id, content.Name, content.GetCultureName("en-GB"), content.GetCultureName("fr-FR"), content.GetCultureName("da-DK")); Console.WriteLine("-"); } @@ -2956,7 +2954,7 @@ namespace Umbraco.Tests.Services //var langFr = new Language("fr-FR") { IsDefaultVariantLanguage = true }; var langXx = new Language("pt-PT") { IsDefault = true }; var langFr = new Language("fr-FR"); - var langUk = new Language("en-UK"); + var langUk = new Language("en-GB"); var langDe = new Language("de-DE"); languageService.Save(langFr); diff --git a/src/Umbraco.Tests/Services/MediaServiceTests.cs b/src/Umbraco.Tests/Services/MediaServiceTests.cs index 68fd2c3e11..b9e1fee0db 100644 --- a/src/Umbraco.Tests/Services/MediaServiceTests.cs +++ b/src/Umbraco.Tests/Services/MediaServiceTests.cs @@ -69,11 +69,15 @@ namespace Umbraco.Tests.Services } long total; - var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total, "SortOrder", Direction.Ascending, true, null, new[] { mediaType1.Id, mediaType2.Id }); + var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total, + SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), + Ordering.By("SortOrder", Direction.Ascending)); Assert.AreEqual(11, result.Count()); Assert.AreEqual(20, total); - result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total, "SortOrder", Direction.Ascending, true, null, new[] { mediaType1.Id, mediaType2.Id }); + result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total, + SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), + Ordering.By("SortOrder", Direction.Ascending)); Assert.AreEqual(9, result.Count()); Assert.AreEqual(20, total); } diff --git a/src/Umbraco.Tests/Services/PerformanceTests.cs b/src/Umbraco.Tests/Services/PerformanceTests.cs index 9b0117c266..900a466a1d 100644 --- a/src/Umbraco.Tests/Services/PerformanceTests.cs +++ b/src/Umbraco.Tests/Services/PerformanceTests.cs @@ -108,40 +108,6 @@ namespace Umbraco.Tests.Services } } - [Test] - public void Get_All_Published_Content_Of_Type() - { - var result = PrimeDbWithLotsOfContent(); - var contentSvc = (ContentService)ServiceContext.ContentService; - - var countOfPublished = result.Count(x => x.Published); - var contentTypeId = result.First().ContentTypeId; - - var proflog = GetTestProfilingLogger(); - using (proflog.DebugDuration("Getting published content of type normally")) - { - //do this 10x! - for (var i = 0; i < 10; i++) - { - - //get all content items that are published of this type - var published = contentSvc.GetByType(contentTypeId).Where(content => content.Published); - Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId)); - } - } - - using (proflog.DebugDuration("Getting published content of type optimized")) - { - - //do this 10x! - for (var i = 0; i < 10; i++) - { - //get all content items that are published of this type - var published = contentSvc.GetPublishedContentOfContentType(contentTypeId); - Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId)); - } - } - } [Test] public void Truncate_Insert_Vs_Update_Insert() diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs index 117b0f9103..cce54c81a4 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests/Services/UserServiceTests.cs @@ -14,7 +14,8 @@ using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Tests.Testing; -using Umbraco.Web._Legacy.Actions; +using Umbraco.Web.Actions; + namespace Umbraco.Tests.Services { @@ -70,12 +71,12 @@ namespace Umbraco.Tests.Services MockedContent.CreateSimpleContent(contentType) }; ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[2], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); // Act var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); @@ -103,12 +104,12 @@ namespace Umbraco.Tests.Services MockedContent.CreateSimpleContent(contentType) }; ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionMove.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(2), ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionMove.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content.ElementAt(2), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); // Act var permissions = userService.GetPermissions(userGroup, false, content[0].Id, content[1].Id, content[2].Id).ToArray(); @@ -136,11 +137,11 @@ namespace Umbraco.Tests.Services MockedContent.CreateSimpleContent(contentType) }; ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act var permissions = userService.GetPermissions(userGroup, true, content[0].Id, content[1].Id, content[2].Id) @@ -180,12 +181,12 @@ namespace Umbraco.Tests.Services }; ServiceContext.ContentService.Save(content); //assign permissions - we aren't assigning anything explicit for group3 and nothing explicit for content[2] /w group2 - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup2.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup2.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionDelete.Instance.Letter, new int[] { userGroup1.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup2.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup2.Id }); + ServiceContext.ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); // Act //we don't pass in any nodes so it will return all of them @@ -249,12 +250,12 @@ namespace Umbraco.Tests.Services MockedContent.CreateSimpleContent(contentType) }; ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionDelete.Instance.Letter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act //we don't pass in any nodes so it will return all of them @@ -412,11 +413,11 @@ namespace Umbraco.Tests.Services var child2 = MockedContent.CreateSimpleContent(contentType, "child2", child1); ServiceContext.ContentService.Save(child2); - ServiceContext.ContentService.SetPermission(parent, ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionDelete.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionMove.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionBrowse.Instance.Letter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionDelete.Instance.Letter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(parent, ActionMove.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ServiceContext.ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act var permissions = userService.GetPermissionsForPath(userGroup, child2.Path); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 7f68f22a27..d80802b1cf 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -36,9 +36,10 @@ using Umbraco.Web; using Umbraco.Web.Services; using Umbraco.Examine; using Umbraco.Tests.Testing.Objects.Accessors; +using Umbraco.Web.Actions; using Umbraco.Web.Composing.CompositionRoots; using Umbraco.Web.ContentApps; -using Umbraco.Web._Legacy.Actions; + using Current = Umbraco.Core.Composing.Current; using Umbraco.Web.Routing; @@ -205,9 +206,7 @@ namespace Umbraco.Tests.Testing Container.RegisterSingleton(f => runtimeStateMock.Object); // ah... - Container.RegisterCollectionBuilder() - .SetProducer(Enumerable.Empty); - + Container.RegisterCollectionBuilder(); Container.RegisterCollectionBuilder(); Container.RegisterSingleton(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index c62e79b4ef..156bc06a14 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -406,7 +406,6 @@ - diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index dedf04488c..8b57e10849 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -71,11 +71,7 @@ namespace Umbraco.Tests.UmbracoExamine contentService = Mock.Of( x => x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) - == - allRecs - && x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()) + It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny>(), It.IsAny()) == allRecs); } @@ -116,12 +112,7 @@ namespace Umbraco.Tests.UmbracoExamine mediaServiceMock .Setup(x => x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny()) - ).Returns(() => allRecs); - - mediaServiceMock - .Setup(x => x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()) + It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny>(), It.IsAny()) ).Returns(() => allRecs); //mediaServiceMock.Setup(service => service.GetPagedXmlEntries(It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs)) diff --git a/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs b/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs index 2d440b8453..768d1c735c 100644 --- a/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs +++ b/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs @@ -49,7 +49,7 @@ namespace Umbraco.Tests.UmbracoExamine .ToArray(); var contentService = Mock.Of( x => x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()) + It.IsAny(), It.IsAny(), It.IsAny(), out totalRecs, It.IsAny>(), It.IsAny()) == allRecs); diff --git a/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs b/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs index 850870f395..fa9335bc3f 100644 --- a/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs @@ -22,20 +22,5 @@ namespace Umbraco.Tests.Web.Controllers }; - [TestCaseSource("TestLegacyJsActionPaths")] - public void Separates_Legacy_JsActions_By_Block_Or_Url(object[] jsActions) - { - var jsBlocks = - BackOfficeController.GetLegacyActionJsForActions(BackOfficeController.LegacyJsActionType.JsBlock, - jsActions.Select(n => n.ToString())); - - var jsUrls = - BackOfficeController.GetLegacyActionJsForActions(BackOfficeController.LegacyJsActionType.JsUrl, - jsActions.Select(n => n.ToString())); - - Assert.That(jsBlocks.Count() == 4); - Assert.That(jsUrls.Count() == 3); - Assert.That(jsUrls.Last().StartsWith("~/") == false); - } } } diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs index f75371d203..26a7403dac 100644 --- a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs @@ -22,7 +22,7 @@ using Umbraco.Web; using Umbraco.Web.Editors; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.PublishedCache; -using Umbraco.Web._Legacy.Actions; + using Task = System.Threading.Tasks.Task; using Umbraco.Core.Dictionary; using Umbraco.Web.PropertyEditors; @@ -30,6 +30,7 @@ using System; using Umbraco.Web.WebApi; using Umbraco.Web.Trees; using System.Globalization; +using Umbraco.Web.Actions; namespace Umbraco.Tests.Web.Controllers { @@ -53,10 +54,10 @@ namespace Umbraco.Tests.Web.Controllers { new EntityPermission(0, 123, new[] { - ActionBrowse.Instance.Letter.ToString(), - ActionUpdate.Instance.Letter.ToString(), - ActionPublish.Instance.Letter.ToString(), - ActionNew.Instance.Letter.ToString() + ActionBrowse.ActionLetter.ToString(), + ActionUpdate.ActionLetter.ToString(), + ActionPublish.ActionLetter.ToString(), + ActionNew.ActionLetter.ToString() }), }))); diff --git a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js index bd7cf964d0..fbe73c4085 100644 --- a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js +++ b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js @@ -33,7 +33,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); * Returns the root angular scope */ function getRootScope() { - return angular.element(document.getElementById("umbracoMainPageBody")).scope(); + return top.$("#umbracoMainPageBody").scope(); } /** @@ -46,7 +46,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); * Returns the root angular injector */ function getRootInjector() { - return angular.element(document.getElementById("umbracoMainPageBody")).injector(); + return top.$("#umbracoMainPageBody").injector(); } @@ -327,7 +327,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); //add the callback to the jquery data for the modal so we can call it on close to support the legacy way dialogs worked. dialog.element.data("modalCb", onCloseCallback); //add the close triggers - if (angular.isArray(closeTriggers)) { + if (top.angular.isArray(closeTriggers)) { for (var i = 0; i < closeTriggers.length; i++) { var e = dialog.find(closeTriggers[i]); if (e.length > 0) { diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js index 64c2b127e9..2475353d94 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js @@ -23,7 +23,7 @@ * **/ -function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { +function contentResource($q, $http, $routeParams, umbDataFormatter, umbRequestHelper) { /** internal method process the saving of data and post processing the result */ function saveContentItem(content, action, files, restApiUrl, showNotifications) { @@ -607,7 +607,10 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { else if (options.orderDirection === "desc") { options.orderDirection = "Descending"; } - + if (!options.cultureName) { + // must send a culture to the content API to handle variant data correctly + options.cultureName = $routeParams.mculture; + } //converts the value to a js bool function toBool(v) { if (angular.isNumber(v)) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js index 3b605453c3..50a8760585 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js @@ -402,21 +402,34 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS throw "Cannot get a descendant node from a section container node without a treeAlias specified"; } - //if it is a section container, we need to find the tree to be searched - if (treeNode.isContainer) { - var foundRoot = null; - for (var c = 0; c < treeNode.children.length; c++) { - if (this.getTreeAlias(treeNode.children[c]) === treeAlias) { - foundRoot = treeNode.children[c]; - break; + //the treeNode passed in could be a section container, or it could be a section group + //in either case we need to go through the children until we can find the actual tree root with the treeAlias + var self = this; + function getTreeRoot(tn) { + //if it is a section container, we need to find the tree to be searched + if (tn.isContainer) { + for (var c = 0; c < tn.children.length; c++) { + if (tn.children[c].isContainer) { + //recurse + return getTreeRoot(tn.children[c]); + } + else if (self.getTreeAlias(tn.children[c]) === treeAlias) { + return tn.children[c]; + } } + return null; } - if (!foundRoot) { - throw "Could not find a tree in the current section with alias " + treeAlias; + else { + return tn; } - treeNode = foundRoot; } + var foundRoot = getTreeRoot(treeNode); + if (!foundRoot) { + throw "Could not find a tree in the current section with alias " + treeAlias; + } + treeNode = foundRoot; + //check this node if (treeNode.id === id) { return treeNode; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/legacydelete.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/legacydelete.controller.js new file mode 100644 index 0000000000..ed1af5af6c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/legacydelete.controller.js @@ -0,0 +1,34 @@ +/** + * @ngdoc controller + * @name Umbraco.Dialogs.LegacyDeleteController + * @function + * + * @description + * The controller for deleting content + */ +function LegacyDeleteController($scope, legacyResource, treeService, navigationService) { + + $scope.performDelete = function () { + + //mark it for deletion (used in the UI) + $scope.currentNode.loading = true; + + legacyResource.deleteItem({ + nodeId: $scope.currentNode.id, + nodeType: $scope.currentNode.nodeType, + alias: $scope.currentNode.name + }).then(function () { + $scope.currentNode.loading = false; + //TODO: Need to sync tree, etc... + treeService.removeNode($scope.currentNode); + navigationService.hideMenu(); + }); + + }; + + $scope.cancel = function () { + navigationService.hideDialog(); + }; +} + +angular.module("umbraco").controller("Umbraco.Dialogs.LegacyDeleteController", LegacyDeleteController); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/legacydelete.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/legacydelete.html new file mode 100644 index 0000000000..dda8f23b7d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/legacydelete.html @@ -0,0 +1,14 @@ +
+
+ +
+

+ Are you sure you want to delete {{currentNode.name}} ? +

+ + + + +
+
+
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 3dc5cd053a..d2867acfc9 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -324,8 +324,6 @@ - - ASPXCodeBehind diff --git a/src/Umbraco.Web.UI/Umbraco/developer/RelationTypes/TreeMenu/ActionDeleteRelationType.js b/src/Umbraco.Web.UI/Umbraco/developer/RelationTypes/TreeMenu/ActionDeleteRelationType.js deleted file mode 100644 index 30d6611ba9..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/RelationTypes/TreeMenu/ActionDeleteRelationType.js +++ /dev/null @@ -1,21 +0,0 @@ -function actionDeleteRelationType(relationTypeId, relationTypeName) { - - if (confirm('Are you sure you want to delete "' + relationTypeName + '"?')) { - $.ajax({ - type: "POST", - url: "developer/RelationTypes/RelationTypesWebService.asmx/DeleteRelationType", - data: "{ 'relationTypeId' : '" + relationTypeId + "' }", - contentType: "application/json; charset=utf-8", - dataType: "json", - success: function (data) { - UmbClientMgr.mainTree().refreshTree('relationTypes'); - UmbClientMgr.appActions().openDashboard('developer'); - }, - error: function (data) { } - }); - - } - -} - - diff --git a/src/Umbraco.Web.UI/Umbraco/developer/RelationTypes/TreeMenu/ActionNewRelationType.js b/src/Umbraco.Web.UI/Umbraco/developer/RelationTypes/TreeMenu/ActionNewRelationType.js deleted file mode 100644 index 322e4b9ace..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/RelationTypes/TreeMenu/ActionNewRelationType.js +++ /dev/null @@ -1,3 +0,0 @@ -function actionNewRelationType() { - UmbClientMgr.openModalWindow('developer/RelationTypes/NewRelationType.aspx', 'Create New RelationType', true, 400, 300, 0, 0); -} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs b/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs index 2297ea1aa7..8111410edd 100644 --- a/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs +++ b/src/Umbraco.Web.UI/Umbraco/dialogs/ChangeDocType.aspx.cs @@ -113,7 +113,8 @@ namespace Umbraco.Web.UI.Umbraco.Dialogs private IEnumerable RemoveInvalidByChildrenDocumentTypesFromAlternatives(IEnumerable documentTypes) { - var docTypeIdsOfChildren = _content.Children(Services.ContentService) + //fixme Should do proper paging here ... when this is refactored we will + var docTypeIdsOfChildren = Services.ContentService.GetPagedChildren(_content.Id, 0, int.MaxValue, out var total) .Select(x => x.ContentType.Id) .Distinct() .ToList(); diff --git a/src/Umbraco.Web/Actions/ActionAssignDomain.cs b/src/Umbraco.Web/Actions/ActionAssignDomain.cs new file mode 100644 index 0000000000..7dc3668e5d --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionAssignDomain.cs @@ -0,0 +1,21 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when a domain is being assigned to a document + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionBrowse.cs b/src/Umbraco.Web/Actions/ActionBrowse.cs new file mode 100644 index 0000000000..64882c142a --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionBrowse.cs @@ -0,0 +1,27 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; + + +namespace Umbraco.Web.Actions +{ + /// + /// 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. + /// + /// + /// 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. + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionChangeDocType.cs b/src/Umbraco.Web/Actions/ActionChangeDocType.cs new file mode 100644 index 0000000000..73772699d0 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionChangeDocType.cs @@ -0,0 +1,20 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when the document type of a piece of content is changed + /// + 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; + } +} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionCollection.cs b/src/Umbraco.Web/Actions/ActionCollection.cs similarity index 57% rename from src/Umbraco.Web/_Legacy/Actions/ActionCollection.cs rename to src/Umbraco.Web/Actions/ActionCollection.cs index 849fb3b619..64cf950c60 100644 --- a/src/Umbraco.Web/_Legacy/Actions/ActionCollection.cs +++ b/src/Umbraco.Web/Actions/ActionCollection.cs @@ -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 { @@ -15,7 +17,7 @@ namespace Umbraco.Web._Legacy.Actions internal T GetAction() where T : IAction { - return this.OfType().SingleOrDefault(); + return this.OfType().FirstOrDefault(); } internal IEnumerable GetByLetters(IEnumerable letters) @@ -25,5 +27,15 @@ namespace Umbraco.Web._Legacy.Actions .WhereNotNull() .ToArray(); } + + internal IReadOnlyList 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(); + } } } diff --git a/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs b/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs new file mode 100644 index 0000000000..6002c8d2b0 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs @@ -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 + { + public ActionCollectionBuilder(IServiceContainer container) + : base(container) + { } + + protected override ActionCollectionBuilder This => this; + + protected override IEnumerable 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; + } + } +} diff --git a/src/Umbraco.Web/Actions/ActionCopy.cs b/src/Umbraco.Web/Actions/ActionCopy.cs new file mode 100644 index 0000000000..3e4b2ddc31 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionCopy.cs @@ -0,0 +1,20 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when copying a document, media, member + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs b/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs new file mode 100644 index 0000000000..0a46393a81 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs @@ -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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionDelete.cs b/src/Umbraco.Web/Actions/ActionDelete.cs new file mode 100644 index 0000000000..0cf2e60c5a --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionDelete.cs @@ -0,0 +1,23 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when a document, media, member is deleted + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionMove.cs b/src/Umbraco.Web/Actions/ActionMove.cs new file mode 100644 index 0000000000..7ae8474965 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionMove.cs @@ -0,0 +1,22 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked upon creation of a document, media, member + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionNew.cs b/src/Umbraco.Web/Actions/ActionNew.cs new file mode 100644 index 0000000000..c07580b42a --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionNew.cs @@ -0,0 +1,23 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked upon creation of a document + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionProtect.cs b/src/Umbraco.Web/Actions/ActionProtect.cs new file mode 100644 index 0000000000..0e5f9f8433 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionProtect.cs @@ -0,0 +1,20 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when a document is protected or unprotected + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionPublish.cs b/src/Umbraco.Web/Actions/ActionPublish.cs new file mode 100644 index 0000000000..5c9ce08c35 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionPublish.cs @@ -0,0 +1,21 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when a document is being published + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionRestore.cs b/src/Umbraco.Web/Actions/ActionRestore.cs new file mode 100644 index 0000000000..aa309131f2 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionRestore.cs @@ -0,0 +1,20 @@ + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when the content/media item is to be restored from the recycle bin + /// + 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; + + } +} diff --git a/src/Umbraco.Web/Actions/ActionRights.cs b/src/Umbraco.Web/Actions/ActionRights.cs new file mode 100644 index 0000000000..0d9ace918e --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionRights.cs @@ -0,0 +1,20 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when rights are changed on a document + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionRollback.cs b/src/Umbraco.Web/Actions/ActionRollback.cs new file mode 100644 index 0000000000..96ce1e7767 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionRollback.cs @@ -0,0 +1,22 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when copying a document is being rolled back + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionSort.cs b/src/Umbraco.Web/Actions/ActionSort.cs new file mode 100644 index 0000000000..8b4e01823e --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionSort.cs @@ -0,0 +1,19 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when children to a document, media, member is being sorted + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionToPublish.cs b/src/Umbraco.Web/Actions/ActionToPublish.cs new file mode 100644 index 0000000000..518c82ab87 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionToPublish.cs @@ -0,0 +1,22 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when children to a document is being sent to published (by an editor without publishrights) + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/ActionUnpublish.cs b/src/Umbraco.Web/Actions/ActionUnpublish.cs new file mode 100644 index 0000000000..8ece4c008e --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionUnpublish.cs @@ -0,0 +1,21 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; + + +namespace Umbraco.Web.Actions +{ + + /// + /// This action is invoked when a document is being unpublished + /// + 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; + } + +} diff --git a/src/Umbraco.Web/Actions/ActionUpdate.cs b/src/Umbraco.Web/Actions/ActionUpdate.cs new file mode 100644 index 0000000000..a2fba0fd89 --- /dev/null +++ b/src/Umbraco.Web/Actions/ActionUpdate.cs @@ -0,0 +1,22 @@ +using Umbraco.Core; +using Umbraco.Core.CodeAnnotations; +using Umbraco.Web.UI.Pages; + + +namespace Umbraco.Web.Actions +{ + /// + /// This action is invoked when copying a document or media + /// + 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; + } +} diff --git a/src/Umbraco.Web/Actions/IAction.cs b/src/Umbraco.Web/Actions/IAction.cs new file mode 100644 index 0000000000..986ed9b509 --- /dev/null +++ b/src/Umbraco.Web/Actions/IAction.cs @@ -0,0 +1,46 @@ +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Actions +{ + /// + /// Defines a back office action that can be permission assigned or subscribed to for notifications + /// + /// + /// If an IAction returns false for both ShowInNotifier and CanBePermissionAssigned then the IAction should not exist + /// + public interface IAction : IDiscoverable + { + /// + /// The letter used to assign a permission (must be unique) + /// + char Letter { get; } + + /// + /// Whether to allow subscribing to notifications for this action + /// + bool ShowInNotifier { get; } + + /// + /// Whether to allow assigning permissions based on this action + /// + bool CanBePermissionAssigned { get; } + + /// + /// The icon to display for this action + /// + string Icon { get; } + + /// + /// The alias for this action (must be unique) + /// + string Alias { get; } + + /// + /// The category used for this action + /// + /// + /// Used in the UI when assigning permissions + /// + string Category { get; } + } +} diff --git a/src/Umbraco.Web/Components/NotificationsComponent.cs b/src/Umbraco.Web/Components/NotificationsComponent.cs index 27fc604d29..79f5ee9f6d 100644 --- a/src/Umbraco.Web/Components/NotificationsComponent.cs +++ b/src/Umbraco.Web/Components/NotificationsComponent.cs @@ -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()); //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()); }; //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()); + notificationService.SendNotification(updatedEntities, actions.GetAction()); }; //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()); }; //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()); }; } } diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 3e3f6c75a6..839254f03c 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -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 diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs index f33c8e98a8..fe2ea4b8a7 100644 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ b/src/Umbraco.Web/CompositionExtensions.cs @@ -3,14 +3,15 @@ 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; +using Umbraco.Web.Features; // the namespace here is intentional - although defined in Umbraco.Web assembly, // this class should be visible when using Umbraco.Core.Components, alongside @@ -58,6 +59,9 @@ namespace Umbraco.Core.Components internal static EditorValidatorCollectionBuilder EditorValidators(this Composition composition) => composition.Container.GetInstance(); + public static UmbracoFeatures Features(this Composition composition) + => composition.Container.GetInstance(); + /// /// Gets the filtered controller factories collection builder. /// diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 15554b7f50..7d0cc26d15 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -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 GetLegacyActionJsForActions(LegacyJsActionType type, IEnumerable values) - { - var blockList = new List(); - var urlList = new List(); - 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; - } - - /// - /// Renders out all JavaScript references that have been declared in IActions - /// - private static IEnumerable GetLegacyActionJs(LegacyJsActionType type) - { - return GetLegacyActionJsForActions(type, Action.GetJavaScriptFileReferences()); - } - - internal enum LegacyJsActionType - { - JsBlock, - JsUrl - } - + private ActionResult RedirectToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl)) diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 9681a79ed1..03bfc78204 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -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> 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); } - + /// /// Publishes a document with a given ID /// /// /// /// - /// 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. /// /// @@ -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(), 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 = "*") { diff --git a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs index ed6e15ed09..2698986bcd 100644 --- a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs @@ -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) { diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index dc744ea361..f61cbc5952 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -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().Where(x => folderTypes.Contains(x.ContentTypeId)), + Ordering.By("Name", Direction.Ascending)); return new PagedResult>(total, pageNumber, pageSize) { @@ -271,7 +274,7 @@ namespace Umbraco.Web.Editors // else proceed as usual long totalChildren; - IMedia[] children; + List children; if (pageNumber > 0 && pageSize > 0) { IQuery 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().Where(x => x.Name == nameToFind)); + foreach (var c in children) + return c; //return first one if any are found + } + return null; + } + /// /// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT /// diff --git a/src/Umbraco.Web/Models/Mapping/UserGroupDefaultPermissionsResolver.cs b/src/Umbraco.Web/Models/Mapping/UserGroupDefaultPermissionsResolver.cs index 89144084e2..b13b5cda10 100644 --- a/src/Umbraco.Web/Models/Mapping/UserGroupDefaultPermissionsResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/UserGroupDefaultPermissionsResolver.cs @@ -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(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)); diff --git a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs index 213a1a5e3a..8261dda0d4 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs @@ -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 { diff --git a/src/Umbraco.Web/Models/Trees/ActionMenuItem.cs b/src/Umbraco.Web/Models/Trees/ActionMenuItem.cs index b2fb479771..9354417155 100644 --- a/src/Umbraco.Web/Models/Trees/ActionMenuItem.cs +++ b/src/Umbraco.Web/Models/Trees/ActionMenuItem.cs @@ -1,41 +1,55 @@ using System; +using System.Diagnostics.CodeAnalysis; using Umbraco.Core; +using Umbraco.Core.Services; namespace Umbraco.Web.Models.Trees { - /// - /// A menu item that represents some JS that needs to execute when the menu item is clicked. - /// - /// - /// 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. - /// + /// + /// + /// A menu item that represents some JS that needs to execute when the menu item is clicked. + /// + /// + /// 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. + /// public abstract class ActionMenuItem : MenuItem { - protected ActionMenuItem() - : base() - { - var attribute = GetType().GetCustomAttribute(false); - if (attribute == null) - { - throw new InvalidOperationException("All " + typeof (ActionMenuItem).FullName + " instances must be attributed with " + typeof (ActionMenuItemAttribute).FullName); - } + /// + /// The angular service name containing the + /// + public abstract string AngularServiceName { get; } + /// + /// The angular service method name to call for this menu item + /// + 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}"); } } } diff --git a/src/Umbraco.Web/Models/Trees/ActionMenuItemAttribute.cs b/src/Umbraco.Web/Models/Trees/ActionMenuItemAttribute.cs deleted file mode 100644 index 64558b8727..0000000000 --- a/src/Umbraco.Web/Models/Trees/ActionMenuItemAttribute.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using Umbraco.Core.Exceptions; - -namespace Umbraco.Web.Models.Trees -{ - /// - /// The attribute to assign to any ActionMenuItem objects. - /// - [AttributeUsage(AttributeTargets.Class)] - public sealed class ActionMenuItemAttribute : Attribute - { - /// - /// This constructor defines both the angular service and method name to use - /// - /// - /// - 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; - } - - /// - /// This constructor will assume that the method name equals the type name of the action menu class - /// - /// - public ActionMenuItemAttribute(string serviceName) - { - if (string.IsNullOrWhiteSpace(serviceName)) throw new ArgumentNullOrEmptyException(nameof(serviceName)); - MethodName = ""; - ServiceName = serviceName; - } - - public string MethodName { get; } - public string ServiceName { get; } - } -} diff --git a/src/Umbraco.Web/Models/Trees/CreateChildEntity.cs b/src/Umbraco.Web/Models/Trees/CreateChildEntity.cs index ca89851beb..022056c35d 100644 --- a/src/Umbraco.Web/Models/Trees/CreateChildEntity.cs +++ b/src/Umbraco.Web/Models/Trees/CreateChildEntity.cs @@ -1,10 +1,27 @@ -namespace Umbraco.Web.Models.Trees +using Umbraco.Core.Services; +using Umbraco.Web.Actions; + +namespace Umbraco.Web.Models.Trees { /// /// Represents the refresh node menu item /// - [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; + } } } diff --git a/src/Umbraco.Web/Models/Trees/DisableUser.cs b/src/Umbraco.Web/Models/Trees/DisableUser.cs deleted file mode 100644 index 3602897ac2..0000000000 --- a/src/Umbraco.Web/Models/Trees/DisableUser.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Umbraco.Web.Models.Trees -{ - /// - /// Represents the disable user menu item - /// - [ActionMenuItem("umbracoMenuActions")] - public sealed class DisableUser : ActionMenuItem - { - public DisableUser() - { - Alias = "disable"; - Icon = "remove"; - } - } -} diff --git a/src/Umbraco.Web/Models/Trees/ExportMember.cs b/src/Umbraco.Web/Models/Trees/ExportMember.cs index 66a10da007..558f7c1fa1 100644 --- a/src/Umbraco.Web/Models/Trees/ExportMember.cs +++ b/src/Umbraco.Web/Models/Trees/ExportMember.cs @@ -1,9 +1,17 @@ -namespace Umbraco.Web.Models.Trees +using Umbraco.Core.Services; + +namespace Umbraco.Web.Models.Trees { /// /// Represents the export member menu item /// - [ActionMenuItem("umbracoMenuActions")] public sealed class ExportMember : ActionMenuItem - { } + { + public override string AngularServiceName => "umbracoMenuActions"; + + public ExportMember(ILocalizedTextService textService) : base("export", textService) + { + Icon = "download-alt"; + } + } } diff --git a/src/Umbraco.Web/Models/Trees/MenuItem.cs b/src/Umbraco.Web/Models/Trees/MenuItem.cs index 412cd9106d..4170cdb73f 100644 --- a/src/Umbraco.Web/Models/Trees/MenuItem.cs +++ b/src/Umbraco.Web/Models/Trees/MenuItem.cs @@ -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}"); + } + + /// + /// Create a menu item based on an definition + /// + /// + /// + 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; } + /// + /// Used in the UI to inform the user that the menu item will open a dialog/confirmation + /// [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. /// /// - public void ExecuteLegacyJs(string jsToExecute) + public void ExecuteJsMethod(string jsToExecute) { SetJsAction(jsToExecute); } @@ -206,7 +222,7 @@ namespace Umbraco.Web.Models.Trees } } } - + #endregion } diff --git a/src/Umbraco.Web/Models/Trees/MenuItemList.cs b/src/Umbraco.Web/Models/Trees/MenuItemList.cs index 170042b151..b34f0b4444 100644 --- a/src/Umbraco.Web/Models/Trees/MenuItemList.cs +++ b/src/Umbraco.Web/Models/Trees/MenuItemList.cs @@ -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 } /// - /// Adds a menu item + /// Adds a menu item based on a /// /// /// The text to display for the menu item, will default to the IAction alias if not specified @@ -32,78 +34,20 @@ namespace Umbraco.Web.Models.Trees { var item = new MenuItem(action, name); - DetectLegacyActionMenu(action.GetType(), item); - Add(item); return item; } - /// - /// Adds a menu item - /// - /// - /// - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - /// - public TMenuItem Add(string name, bool hasSeparator = false, IDictionary additionalData = null) - where TAction : IAction - where TMenuItem : MenuItem, new() - { - var item = CreateMenuItem(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; - } - - /// - /// Adds a menu item - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - public MenuItem Add(string name) - where T : IAction - { - return Add(name, false, null); - } - - /// - /// Adds a menu item with a key value pair which is merged to the AdditionalData bag - /// - /// - /// - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - public MenuItem Add(string name, string key, string value, bool hasSeparator = false) - where T : IAction - { - return Add(name, hasSeparator, new Dictionary { { key, value } }); - } - /// /// Adds a menu item with a dictionary which is merged to the AdditionalData bag /// /// /// - /// /// The text to display for the menu item, will default to the IAction alias if not specified - /// - public MenuItem Add(string name, bool hasSeparator = false, IDictionary additionalData = null) + /// The text to display for the menu item, will default to the IAction alias if not specified + public MenuItem Add(string name, bool hasSeparator = false) where T : IAction { - var item = CreateMenuItem(name, hasSeparator, additionalData); + var item = CreateMenuItem(name, hasSeparator); if (item != null) { Add(item); @@ -113,69 +57,51 @@ namespace Umbraco.Web.Models.Trees } /// - /// + /// Adds a menu item with a dictionary which is merged to the AdditionalData bag /// /// /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - /// - internal MenuItem CreateMenuItem(string name, bool hasSeparator = false, IDictionary additionalData = null) + /// The used to localize the action name based on it's alias + /// + public MenuItem Add(ILocalizedTextService textService, bool hasSeparator = false, bool opensDialog = false) where T : IAction { - var item = Current.Actions.GetAction(); + var item = CreateMenuItem(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; } - - /// - /// Checks if the IAction type passed in is attributed with LegacyActionMenuItemAttribute and if so - /// ensures that the correct action metadata is added. - /// - /// - /// - private void DetectLegacyActionMenu(Type actionType, MenuItem menuItem) + + internal MenuItem CreateMenuItem(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(false); - if (attribute != null) + var item = Current.Actions.GetAction(); + 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(ILocalizedTextService textService, bool hasSeparator = false, bool opensDialog = false) + where T : IAction + { + var item = Current.Actions.GetAction(); + if (item == null) return null; + + var menuItem = new MenuItem(item, textService.Localize($"actions/{item.Alias}")) + { + SeperatorBefore = hasSeparator, + OpensDialog = opensDialog + }; + + return menuItem; + } + } } diff --git a/src/Umbraco.Web/Models/Trees/RefreshNode.cs b/src/Umbraco.Web/Models/Trees/RefreshNode.cs index 7f20562962..2641baa34f 100644 --- a/src/Umbraco.Web/Models/Trees/RefreshNode.cs +++ b/src/Umbraco.Web/Models/Trees/RefreshNode.cs @@ -1,10 +1,27 @@ -namespace Umbraco.Web.Models.Trees +using Umbraco.Core.Services; + +namespace Umbraco.Web.Models.Trees { + /// /// /// Represents the refresh node menu item /// - [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; + } } } diff --git a/src/Umbraco.Web/NotificationServiceExtensions.cs b/src/Umbraco.Web/NotificationServiceExtensions.cs index 1fb229a66e..4be7b4f091 100644 --- a/src/Umbraco.Web/NotificationServiceExtensions.cs +++ b/src/Umbraco.Web/NotificationServiceExtensions.cs @@ -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 diff --git a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs index 2be0dce096..14b9c0a465 100644 --- a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs +++ b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs @@ -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))); diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 028f1bf728..1af24db636 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -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() - .SetProducer(() => typeLoader.GetActions()); + .Add(() => typeLoader.GetTypes()); var surfaceControllerTypes = new SurfaceControllerTypeCollection(typeLoader.GetSurfaceControllers()); composition.Container.RegisterInstance(surfaceControllerTypes); diff --git a/src/Umbraco.Web/Search/ExamineComponent.cs b/src/Umbraco.Web/Search/ExamineComponent.cs index ff7d0c8dc4..7a036ef712 100644 --- a/src/Umbraco.Web/Search/ExamineComponent.cs +++ b/src/Umbraco.Web/Search/ExamineComponent.cs @@ -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); + } } } } } } + /// + /// Updates indexes based on content type changes + /// + /// + /// + 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 removedIds, List refreshedIds, List otherIds)>(); + + foreach (var payload in (ContentTypeCacheRefresher.JsonPayload[])args.MessageObject) + { + if (!changedIds.TryGetValue(payload.ItemType, out var idLists)) + { + idLists = (removedIds: new List(), refreshedIds: new List(), otherIds: new List()); + 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()) + { + 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(); + + 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); + } + } + } + + /// + /// Updates indexes based on content changes + /// + /// + /// 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(); - 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); + } } } } diff --git a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs index f3be39b6f8..365308a8f2 100644 --- a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs @@ -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 @@ -95,9 +96,8 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { // root actions - menu.Items.Add(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); - menu.Items.Add(Services.TextService.Localize( - $"actions/{ActionRefresh.Instance.Alias}"), true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; } var cte = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentType); @@ -105,15 +105,15 @@ namespace Umbraco.Web.Trees if (cte != null) { var ct = Services.ContentTypeService.Get(cte.Id); - var createItem = menu.Items.Add(Services.TextService.Localize($"actions/{ActionCreateBlueprintFromContent.Instance.Alias}")); + var createItem = menu.Items.Add(Services.TextService, opensDialog: true); createItem.NavigateToRoute("/settings/contentBlueprints/edit/-1?create=true&doctype=" + ct.Alias); - menu.Items.Add(Services.TextService.Localize($"actions/{ActionRefresh.Instance.Alias}"), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; } - menu.Items.Add(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); return menu; } diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 4a0589cce4..04c356a4fd 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -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( - 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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionSort.Instance.Alias), true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(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(Services.TextService.Localize("actions", ActionRePublish.Instance.Alias)).ConvertLegacyMenuItem(null, "content", "content"); - menu.Items.Add(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( - 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(item, menu); - AddActionNode(item, menu); - - AddActionNode(item, menu); - - //need to ensure some of these are converted to the legacy system - until we upgrade them all to be angularized. - AddActionNode(item, menu, true); - AddActionNode(item, menu); - + AddActionNode(item, menu, opensDialog: true); + AddActionNode(item, menu, opensDialog: true); + AddActionNode(item, menu, opensDialog: true); + AddActionNode(item, menu, true, opensDialog: true); + AddActionNode(item, menu, opensDialog: true); AddActionNode(item, menu, true); + AddActionNode(item, menu, opensDialog: true); + AddActionNode(item, menu, opensDialog: true); + //fixme - conver this editor to angular + AddActionNode(item, menu, true, convert: true, opensDialog: true); - AddActionNode(item, menu, convert: true); - AddActionNode(item, menu); - AddActionNode(item, menu, convert: true); - AddActionNode(item, menu, true, true); - - AddActionNode(item, menu, true); + menu.Items.Add(new MenuItem("notify", Services.TextService) + { + Icon = "megaphone", + SeperatorBefore = true, + OpensDialog = true + }); - AddActionNode(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(Services.TextService.Localize("actions", ActionRestore.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(Services.TextService, opensDialog: true); - menu.Items.Add(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(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false) + //fixme: Remove the need for converting to legacy + private void AddActionNode(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false, bool opensDialog = false) where TAction : IAction { + //fixme: Inject var menuItem = menu.Items.Add(Services.TextService.Localize("actions", Current.Actions.GetAction().Alias), hasSeparator); if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content"); - } - - private void AddActionNode(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false) - where TItem : MenuItem, new() - where TAction : IAction - { - var menuItem = menu.Items.Add(Services.TextService.Localize("actions", Current.Actions.GetAction().Alias), hasSeparator); - if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content"); + menuItem.OpensDialog = opensDialog; } public IEnumerable Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null) diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 4d4f1be483..646f47068b 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -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(Services.TextService.Localize("actions/emptyTrashcan")); - menu.Items.Add(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 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(); + // 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)); } diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index a2179be75f..43e5b03f2f 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -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(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + menu.Items.Add(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(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + menu.Items.Add(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(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); } - menu.Items.Add(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(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + menu.Items.Add(Services.TextService, opensDialog: true); } //no move action if this is a child doc type if (parent == null) { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); } - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionCopy.Instance.Alias))); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionExport.Instance.Alias)), true); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(new MenuItem("export", Services.TextService) + { + Icon = "download-alt", + SeperatorBefore = true, + OpensDialog = true + }); + menu.Items.Add(Services.TextService, true, opensDialog: true); if (enableInheritedDocumentTypes) - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); } return menu; diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs index 3087808f10..6c89f4a1dc 100644 --- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs @@ -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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); - menu.Items.Add(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); + menu.Items.Add(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(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); } - menu.Items.Add(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(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); - menu.Items.Add(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), hasSeparator: true); + menu.Items.Add(Services.TextService, hasSeparator: true, opensDialog: true); } return menu; diff --git a/src/Umbraco.Web/Trees/DictionaryTreeController.cs b/src/Umbraco.Web/Trees/DictionaryTreeController.cs index 3043377d65..d0a7fce3ad 100644 --- a/src/Umbraco.Web/Trees/DictionaryTreeController.cs +++ b/src/Umbraco.Web/Trees/DictionaryTreeController.cs @@ -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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); if (id != Constants.System.Root.ToInvariantString()) - menu.Items.Add(Services.TextService.Localize( - $"actions/{ActionDelete.Instance.Alias}"), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); - menu.Items.Add(Services.TextService.Localize( - $"actions/{ActionRefresh.Instance.Alias}"), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; } diff --git a/src/Umbraco.Web/Trees/FileSystemTreeController.cs b/src/Umbraco.Web/Trees/FileSystemTreeController.cs index 33c5c360b2..9babb656fe 100644 --- a/src/Umbraco.Web/Trees/FileSystemTreeController.cs +++ b/src/Umbraco.Web/Trees/FileSystemTreeController.cs @@ -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 @@ -87,11 +88,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(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + menu.Items.Add(Services.TextService, opensDialog: true); //refresh action - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; } @@ -101,9 +102,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(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + menu.Items.Add(Services.TextService, opensDialog: true); var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any(); @@ -111,11 +112,11 @@ namespace Umbraco.Web.Trees if (hasChildren == false) { //delete action - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); } //refresh action - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; } @@ -125,7 +126,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(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); + menu.Items.Add(Services.TextService, opensDialog: true); return menu; } diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs index 131c7954c8..d0bfa360fa 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs @@ -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 /// internal class LegacyTreeDataConverter { + //fixme: remove this whole class when everything is angularized + /// /// This will look at the legacy IAction's JsFunctionName and convert it to a confirmation dialog view if possible /// @@ -24,14 +27,9 @@ namespace Umbraco.Web.Trees /// internal static Attempt GetLegacyConfirmView(IAction action) { - if (action.JsFunctionName.IsNullOrWhiteSpace()) + switch (action) { - return Attempt.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 /// internal static Attempt GetUrlAndTitleFromLegacyAction(IAction action, string nodeId, string nodeType, string nodeName, string currentSection) { - if (action.JsFunctionName.IsNullOrWhiteSpace()) + switch (action) { - return Attempt.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.Fail(); } diff --git a/src/Umbraco.Web/Trees/MacrosTreeController.cs b/src/Umbraco.Web/Trees/MacrosTreeController.cs index a4f486661e..3f925eef8d 100644 --- a/src/Umbraco.Web/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/MacrosTreeController.cs @@ -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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)) + menu.Items.Add(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("application")); //refresh action - menu.Items.Add(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(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)) + menu.Items.Add(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 diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs index 8eb37e6224..0292a907fc 100644 --- a/src/Umbraco.Web/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web/Trees/MediaTreeController.cs @@ -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( - 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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionSort.Instance.Alias), true); - menu.Items.Add(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(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( - 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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionMove.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionSort.Instance.Alias)); - menu.Items.Add(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(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; diff --git a/src/Umbraco.Web/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web/Trees/MediaTypeTreeController.cs index 7b346c6871..547199676a 100644 --- a/src/Umbraco.Web/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/MediaTypeTreeController.cs @@ -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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); - menu.Items.Add(Services.TextService.Localize( - $"actions/{ActionRefresh.Instance.Alias}")); + menu.Items.Add(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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); + menu.Items.Add(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(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); } - menu.Items.Add(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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); //no move action if this is a child doc type if (parent == null) { - menu.Items.Add(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); } } else { - menu.Items.Add(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); //no move action if this is a child doc type if (parent == null) { - menu.Items.Add(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); } } - menu.Items.Add(Services.TextService.Localize($"actions/{ActionCopy.Instance.Alias}")); - menu.Items.Add(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); + menu.Items.Add(Services.TextService, opensDialog: true); + menu.Items.Add(Services.TextService, opensDialog: true); if (enableInheritedMediaTypes) - menu.Items.Add(Services.TextService.Localize( - $"actions/{ActionRefresh.Instance.Alias}"), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); } return menu; diff --git a/src/Umbraco.Web/Trees/MemberTreeController.cs b/src/Umbraco.Web/Trees/MemberTreeController.cs index f3ca0c9a02..68819351c0 100644 --- a/src/Umbraco.Web/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberTreeController.cs @@ -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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)); + menu.Items.Add(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(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(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(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)); } diff --git a/src/Umbraco.Web/Trees/MemberTypeAndGroupTreeControllerBase.cs b/src/Umbraco.Web/Trees/MemberTypeAndGroupTreeControllerBase.cs index a710b52595..9ea5908891 100644 --- a/src/Umbraco.Web/Trees/MemberTypeAndGroupTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/MemberTypeAndGroupTreeControllerBase.cs @@ -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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)); - menu.Items.Add(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(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(Services.TextService, opensDialog: true); } return menu; diff --git a/src/Umbraco.Web/Trees/PackagesTreeController.cs b/src/Umbraco.Web/Trees/PackagesTreeController.cs index 31f577ad85..8158b47985 100644 --- a/src/Umbraco.Web/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/PackagesTreeController.cs @@ -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(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")) + menu.Items.Add(Services.TextService, opensDialog: true) .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); } else if (id == "created") { - menu.Items.Add(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")) + menu.Items.Add(Services.TextService, opensDialog: true) .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); - menu.Items.Add( - 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(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(Services.TextService, opensDialog: true); } return menu; diff --git a/src/Umbraco.Web/Trees/RelationTypeTreeController.cs b/src/Umbraco.Web/Trees/RelationTypeTreeController.cs index 4930b4dc5e..33ccc152c5 100644 --- a/src/Umbraco.Web/Trees/RelationTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/RelationTypeTreeController.cs @@ -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(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("application")); + var addMenuItem = menu.Items.Add(Services.TextService, opensDialog: true); + addMenuItem.LaunchDialogUrl("developer/RelationTypes/NewRelationType.aspx", "Create New RelationType"); //refresh action - menu.Items.Add(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(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)) + menu.Items.Add(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 diff --git a/src/Umbraco.Web/Trees/TemplatesTreeController.cs b/src/Umbraco.Web/Trees/TemplatesTreeController.cs index 768768f888..2339d92d96 100644 --- a/src/Umbraco.Web/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web/Trees/TemplatesTreeController.cs @@ -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(Services.TextService.Localize("actions", ActionNew.Instance.Alias)); + var item = menu.Items.Add(Services.TextService, opensDialog: true); item.NavigateToRoute($"{queryStrings.GetValue("application")}/templates/edit/{id}?create=true"); if (id == Constants.System.Root.ToInvariantString()) { //refresh action - menu.Items.Add(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(Services.TextService.Localize("actions", ActionDelete.Instance.Alias), true); + menu.Items.Add(Services.TextService, true, opensDialog: true); } //add refresh - menu.Items.Add(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; diff --git a/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs b/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs index e381c7ec0f..479cc20083 100644 --- a/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs +++ b/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs @@ -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(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; } diff --git a/src/Umbraco.Web/Trees/UserTreeController.cs b/src/Umbraco.Web/Trees/UserTreeController.cs index 8ae5b002c6..f029a929de 100644 --- a/src/Umbraco.Web/Trees/UserTreeController.cs +++ b/src/Umbraco.Web/Trees/UserTreeController.cs @@ -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 diff --git a/src/Umbraco.Web/TypeLoaderExtensions.cs b/src/Umbraco.Web/TypeLoaderExtensions.cs index 710c342115..4d09783ca9 100644 --- a/src/Umbraco.Web/TypeLoaderExtensions.cs +++ b/src/Umbraco.Web/TypeLoaderExtensions.cs @@ -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 /// public static class TypeLoaderExtensions { - /// - /// Returns all available IAction in application - /// - /// - internal static IEnumerable GetActions(this TypeLoader mgr) - { - return mgr.GetTypes(); - } - /// /// Returns all available TreeApiController's in application that are attribute with TreeAttribute /// @@ -43,15 +34,5 @@ namespace Umbraco.Web return mgr.GetTypes(); } - /// - /// Returns all available ISearchableTrees in application - /// - /// - /// - internal static IEnumerable GetSearchableTrees(this TypeLoader mgr) - { - return mgr.GetTypes(); - } - } } diff --git a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs index 30adf2cc3d..9f13939bac 100644 --- a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs +++ b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs @@ -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 { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 6cb8844297..f17f6daf72 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -427,7 +427,6 @@ - @@ -530,39 +529,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -947,7 +933,6 @@ - @@ -1263,12 +1248,6 @@ NewRelationType.aspx - - RelationTypesWebService.asmx - Component - - - insertMasterpageContent.aspx ASPXCodeBehind @@ -1372,7 +1351,6 @@ ASPXCodeBehind - ASPXCodeBehind diff --git a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs index 4d9a6db129..5d71992b74 100644 --- a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs @@ -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) diff --git a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs index 748e0e8a7d..31e0b22ce1 100644 --- a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs @@ -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) diff --git a/src/Umbraco.Web/_Legacy/Actions/Action.cs b/src/Umbraco.Web/_Legacy/Actions/Action.cs deleted file mode 100644 index 241218ddb7..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/Action.cs +++ /dev/null @@ -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 -{ - /// - /// 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. - /// - [Obsolete("Actions and ActionHandlers are obsolete and should no longer be used")] - public class Action - { - private static readonly Dictionary ActionJs = new Dictionary(); - - /// - /// Jacascript for the contextmenu - /// Suggestion: this method should be moved to the presentation layer. - /// - /// - /// String representation - public string ReturnJavascript(string language) - { - return findActions(language); - } - - /// - /// Returns a list of JavaScript file paths. - /// - /// - public static List GetJavaScriptFileReferences() - { - return Current.Actions - .Where(x => !string.IsNullOrWhiteSpace(x.JsSource)) - .Select(x => x.JsSource).ToList(); - //return ActionJsReference; - } - - /// - /// Javascript menuitems - tree contextmenu - /// Umbraco console - /// - /// Suggestion: this method should be moved to the presentation layer. - /// - /// - /// - 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(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 FromEntityPermission(EntityPermission entityPermission) - { - List list = new List(); - 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; - } - - /// - /// Returns a list of IActions that are permission assignable - /// - /// - public static List GetPermissionAssignable() - { - return Current.Actions.ToList().FindAll(x => x.CanBePermissionAssigned); - } - - /// - /// Check if the current IAction is using legacy javascript methods - /// - /// - /// false if the Iaction is incompatible with 4.5 - public static bool ValidateActionJs(IAction action) - { - return !action.JsFunctionName.Contains("+"); - } - - /// - /// Method to convert the old modal calls to the new ones - /// - /// - /// - 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; - } - } - - /// - /// This class is used to manipulate IActions that are implemented in a wrong way - /// For instance incompatible trees with 4.0 vs 4.5 - /// - 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; - } - } - -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionAssignDomain.cs b/src/Umbraco.Web/_Legacy/Actions/ActionAssignDomain.cs deleted file mode 100644 index c313f282ad..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionAssignDomain.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when a domain is being assigned to a document - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionBrowse.cs b/src/Umbraco.Web/_Legacy/Actions/ActionBrowse.cs deleted file mode 100644 index 20dc331516..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionBrowse.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// 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. - /// - /// - /// 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. - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionChangeDocType.cs b/src/Umbraco.Web/_Legacy/Actions/ActionChangeDocType.cs deleted file mode 100644 index b68627c38c..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionChangeDocType.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when the document type of a piece of content is changed - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionCollectionBuilder.cs b/src/Umbraco.Web/_Legacy/Actions/ActionCollectionBuilder.cs deleted file mode 100644 index 39058d6836..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionCollectionBuilder.cs +++ /dev/null @@ -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 - { - private static Func> _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().CreateCollection(), collectionLifetime); - } - - public ActionCollection CreateCollection() - { - var actions = new List(); - 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> producer) - { - _producer = producer; - CollectionLifetime.Reset(); - } - - private ResettablePerContainerLifetime CollectionLifetime { get; } = new ResettablePerContainerLifetime(); - - private class ResettablePerContainerLifetime : ILifetime - { - private object _instance; - - public object GetInstance(Func createInstance, Scope scope) - { - // not dealing with disposable instances, actions are not disposable - return _instance ?? (_instance = createInstance()); - } - - public void Reset() - { - _instance = null; - } - } - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionCopy.cs b/src/Umbraco.Web/_Legacy/Actions/ActionCopy.cs deleted file mode 100644 index 5addcec99f..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionCopy.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when copying a document, media, member - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionCreateBlueprintFromContent.cs b/src/Umbraco.Web/_Legacy/Actions/ActionCreateBlueprintFromContent.cs deleted file mode 100644 index 0d028c35b4..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionCreateBlueprintFromContent.cs +++ /dev/null @@ -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"; - } - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionDelete.cs b/src/Umbraco.Web/_Legacy/Actions/ActionDelete.cs deleted file mode 100644 index 53f7822d47..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionDelete.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when a document, media, member is deleted - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionEmptyTranscan.cs b/src/Umbraco.Web/_Legacy/Actions/ActionEmptyTranscan.cs deleted file mode 100644 index f0da5323b9..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionEmptyTranscan.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when the trash can is emptied - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionExport.cs b/src/Umbraco.Web/_Legacy/Actions/ActionExport.cs deleted file mode 100644 index 56b98c02f2..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionExport.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when exporting a document type - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionImport.cs b/src/Umbraco.Web/_Legacy/Actions/ActionImport.cs deleted file mode 100644 index 52f163ee6b..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionImport.cs +++ /dev/null @@ -1,79 +0,0 @@ -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when importing a document type - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionMove.cs b/src/Umbraco.Web/_Legacy/Actions/ActionMove.cs deleted file mode 100644 index 81d1803679..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionMove.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked upon creation of a document, media, member - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionNew.cs b/src/Umbraco.Web/_Legacy/Actions/ActionNew.cs deleted file mode 100644 index ef1b61efc5..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionNew.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked upon creation of a document - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionNotify.cs b/src/Umbraco.Web/_Legacy/Actions/ActionNotify.cs deleted file mode 100644 index fd6bc3d61a..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionNotify.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when a notification is sent - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionNull.cs b/src/Umbraco.Web/_Legacy/Actions/ActionNull.cs deleted file mode 100644 index 3344560c3f..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionNull.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// 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. - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionPackage.cs b/src/Umbraco.Web/_Legacy/Actions/ActionPackage.cs deleted file mode 100644 index fa17b87073..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionPackage.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked upon creation of a document, media, member - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionPackageCreate.cs b/src/Umbraco.Web/_Legacy/Actions/ActionPackageCreate.cs deleted file mode 100644 index fdec43e810..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionPackageCreate.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked upon creation of a document, media, member - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionProtect.cs b/src/Umbraco.Web/_Legacy/Actions/ActionProtect.cs deleted file mode 100644 index 65e9d7128e..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionProtect.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when a document is protected or unprotected - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionPublish.cs b/src/Umbraco.Web/_Legacy/Actions/ActionPublish.cs deleted file mode 100644 index 70c7735572..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionPublish.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when a document is being published - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionRePublish.cs b/src/Umbraco.Web/_Legacy/Actions/ActionRePublish.cs deleted file mode 100644 index 312ae80825..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionRePublish.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when all documents are being republished - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionRefresh.cs b/src/Umbraco.Web/_Legacy/Actions/ActionRefresh.cs deleted file mode 100644 index 0abf4fcac5..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionRefresh.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// 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. - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionRestore.cs b/src/Umbraco.Web/_Legacy/Actions/ActionRestore.cs deleted file mode 100644 index 2a2baac070..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionRestore.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when the content/media item is to be restored from the recycle bin - /// - 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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionRights.cs b/src/Umbraco.Web/_Legacy/Actions/ActionRights.cs deleted file mode 100644 index beb3b06ddf..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionRights.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when rights are changed on a document - /// - [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 - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionRollback.cs b/src/Umbraco.Web/_Legacy/Actions/ActionRollback.cs deleted file mode 100644 index 3179dc9fb5..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionRollback.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when copying a document is being rolled back - /// - [ActionMetadata(Constants.Conventions.PermissionCategories.AdministrationCategory)] - public class ActionRollback : IAction - { - //create singleton -#pragma warning disable 612,618 - private static readonly ActionRollback m_instance = new ActionRollback(); -#pragma warning restore 612,618 - - public static ActionRollback Instance - { - get { return m_instance; } - } - - #region IAction Members - - public char Letter - { - get - { - - return 'K'; - } - } - - public string JsFunctionName - { - get - { - return string.Format("{0}.actionRollback()", ClientTools.Scripts.GetAppActions); - } - } - - public string JsSource - { - get - { - return ""; - } - } - - public string Alias - { - get - { - - return "rollback"; - } - } - - public string Icon - { - get - { - - return "undo"; - } - } - - public bool ShowInNotifier - { - get - { - - return true; - } - } - public bool CanBePermissionAssigned - { - get - { - - return true; - } - } - - public bool OpensDialog => true; - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionSort.cs b/src/Umbraco.Web/_Legacy/Actions/ActionSort.cs deleted file mode 100644 index 48f6b8d1e9..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionSort.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when children to a document, media, member is being sorted - /// - [ActionMetadata(Constants.Conventions.PermissionCategories.StructureCategory)] - public class ActionSort : IAction - { - //create singleton -#pragma warning disable 612,618 - private static readonly ActionSort m_instance = new ActionSort(); -#pragma warning restore 612,618 - - public static ActionSort Instance - { - get { return m_instance; } - } - - #region IAction Members - - public char Letter - { - get - { - - return 'S'; - } - } - - public string JsFunctionName - { - get - { - return null; - } - } - - public string JsSource - { - get - { - - return null; - } - } - - public string Alias - { - get - { - - return "sort"; - } - } - - public string Icon - { - get - { - - return "navigation-vertical"; - } - } - - public bool ShowInNotifier - { - get - { - - return true; - } - } - public bool CanBePermissionAssigned - { - get - { - - return true; - } - } - - public bool OpensDialog => true; - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionToPublish.cs b/src/Umbraco.Web/_Legacy/Actions/ActionToPublish.cs deleted file mode 100644 index a04a24f4a3..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionToPublish.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when children to a document is being sent to published (by an editor without publishrights) - /// - [ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)] - public class ActionToPublish : IAction - { - //create singleton -#pragma warning disable 612,618 - private static readonly ActionToPublish m_instance = new ActionToPublish(); -#pragma warning restore 612,618 - - public static ActionToPublish Instance - { - get { return m_instance; } - } - - #region IAction Members - - public char Letter - { - get - { - return 'H'; - } - } - - public string JsFunctionName - { - get - { - return string.Format("{0}.actionToPublish()", ClientTools.Scripts.GetAppActions); - } - } - - public string JsSource - { - get - { - return null; - } - } - - public string Alias - { - get - { - return "sendtopublish"; - } - } - - public string Icon - { - get - { - return "outbox"; - } - } - - public bool ShowInNotifier - { - get - { - return true; - } - } - public bool CanBePermissionAssigned - { - get - { - //SD: Changed this to true so that any user may be able to perform this action, not just a writer - return true; - } - } - - public bool OpensDialog => false; - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionTranslate.cs b/src/Umbraco.Web/_Legacy/Actions/ActionTranslate.cs deleted file mode 100644 index 157fd827a6..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionTranslate.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when a translation occurs - /// - [ActionMetadata(Constants.Conventions.PermissionCategories.AdministrationCategory)] - public class ActionTranslate : IAction - { - //create singleton -#pragma warning disable 612,618 - private static readonly ActionTranslate m_instance = new ActionTranslate(); -#pragma warning restore 612,618 - - public static ActionTranslate Instance - { - get { return m_instance; } - } - - #region IAction Members - - public char Letter - { - get - { - return '4'; - } - } - - public string JsFunctionName - { - get - { - return ""; - } - } - - public string JsSource - { - get - { - return null; - } - } - - public string Alias - { - get - { - return "translate"; - } - } - - public string Icon - { - get - { - return "comments"; - } - } - - public bool ShowInNotifier - { - get - { - return true; - } - } - public bool CanBePermissionAssigned - { - get - { - return true; - } - } - - public bool OpensDialog => true; - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionUnPublish.cs b/src/Umbraco.Web/_Legacy/Actions/ActionUnPublish.cs deleted file mode 100644 index 11225add1d..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionUnPublish.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - - /// - /// This action is invoked when a document is being unpublished - /// - [ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)] - public class ActionUnpublish : IAction - { - //create singleton -#pragma warning disable 612,618 - private static readonly ActionUnpublish m_instance = new ActionUnpublish(); -#pragma warning restore 612,618 - - public static ActionUnpublish Instance => m_instance; - - public char Letter => 'Z'; - public string JsFunctionName => ""; - public string JsSource => null; - public string Alias => "unpublish"; - public string Icon => "circle-dotted"; - public bool ShowInNotifier => false; - public bool CanBePermissionAssigned => true; - public bool OpensDialog => false; - - } - -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ActionUpdate.cs b/src/Umbraco.Web/_Legacy/Actions/ActionUpdate.cs deleted file mode 100644 index 5621d505a9..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ActionUpdate.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using Umbraco.Web.UI.Pages; -using Umbraco.Core; -using Umbraco.Core.CodeAnnotations; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// This action is invoked when copying a document or media - /// - [ActionMetadata(Constants.Conventions.PermissionCategories.ContentCategory)] - public class ActionUpdate : IAction - { - //create singleton -#pragma warning disable 612,618 - private static readonly ActionUpdate m_instance = new ActionUpdate(); -#pragma warning restore 612,618 - - public static ActionUpdate Instance - { - get { return m_instance; } - } - - #region IAction Members - - public char Letter - { - get - { - return 'A'; - } - } - - public string JsFunctionName - { - get - { - return string.Format("{0}.actionUpdate()", ClientTools.Scripts.GetAppActions); - } - } - - public string JsSource - { - get - { - return null; - } - } - - public string Alias - { - get - { - return "update"; - } - } - - public string Icon - { - get - { - return "save"; - } - } - - public bool ShowInNotifier - { - get - { - return true; - } - } - public bool CanBePermissionAssigned - { - get - { - return true; - } - } - - public bool OpensDialog => false; - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/ContextMenuSeperator.cs b/src/Umbraco.Web/_Legacy/Actions/ContextMenuSeperator.cs deleted file mode 100644 index 45a1d0e1c5..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/ContextMenuSeperator.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// Used simply to define context menu seperator items. - /// This should not be used directly in any code except for creating menus. - /// - public class ContextMenuSeperator : IAction - { - //create singleton - private static readonly ContextMenuSeperator instance = new ContextMenuSeperator(); - private ContextMenuSeperator() { } - public static ContextMenuSeperator Instance - { - get { return instance; } - } - - #region IAction Members - - public char Letter - { - get { return ','; } - } - - public string JsFunctionName - { - get { return string.Empty; } - } - public string JsSource - { - get { return string.Empty; } - } - public string Alias - { - get { return string.Empty; } - } - public string Icon - { - get { return string.Empty; } - } - public bool ShowInNotifier - { - get { return false; } - } - public bool CanBePermissionAssigned - { - get { return false; } - } - - public bool OpensDialog => false; - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/IAction.cs b/src/Umbraco.Web/_Legacy/Actions/IAction.cs deleted file mode 100644 index 48a752e7da..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/IAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Web._Legacy.Actions -{ - public interface IAction : IDiscoverable - { - char Letter { get; } - bool ShowInNotifier { get; } - bool CanBePermissionAssigned { get; } - string Icon { get; } - string Alias { get; } - string JsFunctionName { get; } - /// - /// A path to a supporting JavaScript file for the IAction. A script tag will be rendered out with the reference to the JavaScript file. - /// - string JsSource { get; } - /// - /// Whether or not the action opens a dialog when invoked - /// - bool OpensDialog { get; } - } -} diff --git a/src/Umbraco.Web/_Legacy/Actions/LegacyActionMenuItemAttribute.cs b/src/Umbraco.Web/_Legacy/Actions/LegacyActionMenuItemAttribute.cs deleted file mode 100644 index ca9ace9630..0000000000 --- a/src/Umbraco.Web/_Legacy/Actions/LegacyActionMenuItemAttribute.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using Umbraco.Core; -using Umbraco.Core.Exceptions; - -namespace Umbraco.Web._Legacy.Actions -{ - /// - /// The attribute to assign to any IAction objects. - /// - /// - /// This is purely used for compatibility reasons for old IActions used in v7 that haven't been upgraded to - /// the new format. - /// - [AttributeUsage(AttributeTargets.Class)] - internal sealed class LegacyActionMenuItemAttribute : Attribute - { - /// - /// This constructor defines both the angular service and method name to use - /// - /// - /// - public LegacyActionMenuItemAttribute(string serviceName, string methodName) - { - if (string.IsNullOrEmpty(serviceName)) throw new ArgumentNullOrEmptyException(nameof(serviceName)); - if (string.IsNullOrEmpty(methodName)) throw new ArgumentNullOrEmptyException(nameof(methodName)); - - MethodName = methodName; - ServiceName = serviceName; - } - - /// - /// This constructor will assume that the method name equals the type name of the action menu class - /// - /// - public LegacyActionMenuItemAttribute(string serviceName) - { - if (string.IsNullOrEmpty(serviceName)) throw new ArgumentNullOrEmptyException(nameof(serviceName)); - - MethodName = ""; - ServiceName = serviceName; - } - - public string MethodName { get; } - public string ServiceName { get; } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/RelationTypesWebService.asmx b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/RelationTypesWebService.asmx deleted file mode 100644 index 160745ca2d..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/RelationTypesWebService.asmx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebService Language="C#" CodeBehind="RelationTypesWebService.asmx.cs" Class="umbraco.cms.presentation.developer.RelationTypes.RelationTypesWebService" %> diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/RelationTypesWebService.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/RelationTypesWebService.asmx.cs deleted file mode 100644 index 0f8ca29c94..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/RelationTypesWebService.asmx.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Web.Services; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Web; -using Umbraco.Web.Composing; - -namespace umbraco.cms.presentation.developer.RelationTypes -{ - /// - /// Webservice to delete relation types, this allows deletion via a javacscript call hooked into the tree UI - /// - [WebService(Namespace = "http://tempuri.org/")] - [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] - [System.ComponentModel.ToolboxItem(false)] - [System.Web.Script.Services.ScriptService] // Allows this Web Service to be called from script, using ASP.NET AJAX - public class RelationTypesWebService : WebService - { - /// - /// Delete an Umbraco RelationType and all it's associated Relations - /// - /// database id of the relation type to delete - [WebMethod] - public void DeleteRelationType(int relationTypeId) - { - var user = UmbracoContext.Current.Security.CurrentUser; - - if (user.IsAdmin()) - { - var relationService = Current.Services.RelationService; - var relationType = relationService.GetRelationTypeById(relationTypeId); - relationService.Delete(relationType); - } - } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/TreeMenu/ActionDeleteRelationType.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/TreeMenu/ActionDeleteRelationType.cs deleted file mode 100644 index 5526a3d9a3..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/TreeMenu/ActionDeleteRelationType.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Umbraco.Web._Legacy.Actions; - -namespace umbraco.cms.presentation.developer.RelationTypes.TreeMenu -{ - /// - /// Delete a Relation Type - an Umbraco tree context menu action - /// - public class ActionDeleteRelationType : IAction - { - /// - /// Private field for the singleton instance - /// - private static readonly ActionDeleteRelationType instance = new ActionDeleteRelationType(); - - /// - /// Gets a singleton instance of this action - /// - public static ActionDeleteRelationType Instance - { - get { return instance; } - } - - #region IAction Members - - /// - /// Gets a string alias used to identify this action - /// - public string Alias - { - get { return "delete"; } - } - - /// - /// Gets a unique char to associate with this action - /// - public char Letter - { - get { return '¤'; } - } - - /// - /// Gets a value indicating whether the Umbraco notification area is used ? - /// - public bool ShowInNotifier - { - get { return false; } - } - - /// - /// Gets a value indicating whether this action can be configured for use only by specific members - /// - public bool CanBePermissionAssigned - { - get { return false; } // Since this tree is in the developer section, no further granular permissions are required - } - - /// - /// Gets an icon to be used for the right click action - /// - public string Icon - { - get { return "delete"; } // delete refers to an existing sprite - } - - /// - /// Gets a string for the javascript source - /// - public string JsSource - { - get { return "developer/RelationTypes/TreeMenu/ActionDeleteRelationType.js"; } - } - - /// - /// Gets a javascript string to execute when this action is fired - /// - public string JsFunctionName - { - get { return "javascript:actionDeleteRelationType(UmbClientMgr.mainTree().getActionNode().nodeId,UmbClientMgr.mainTree().getActionNode().nodeName);"; } - } - - public bool OpensDialog => true; - - #endregion - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/TreeMenu/ActionNewRelationType.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/TreeMenu/ActionNewRelationType.cs deleted file mode 100644 index cb776d5246..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/RelationTypes/TreeMenu/ActionNewRelationType.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Umbraco.Web._Legacy.Actions; - -namespace umbraco.cms.presentation.developer.RelationTypes.TreeMenu -{ - /// - /// Create new Relation Type - an Umbraco tree context menu action - /// - public class ActionNewRelationType : IAction - { - /// - /// Private field for the singleton instance - /// - private static readonly ActionNewRelationType instance = new ActionNewRelationType(); - - /// - /// Gets a singleton instance of this action - /// - public static ActionNewRelationType Instance - { - get { return instance; } - } - - #region IAction Members - - /// - /// Gets a string alias used to identify this action - /// - public string Alias - { - get { return "create"; } - } - - /// - /// Gets a unique char to associate with this action - /// - public char Letter - { - get { return '®'; } - } - - /// - /// Gets a value indicating whether the Umbraco notification area is used ? - /// - public bool ShowInNotifier - { - get { return false; } - } - - /// - /// Gets a value indicating whether this action can be configured for use only by specific members - /// - public bool CanBePermissionAssigned - { - get { return false; } // Since this tree is in the developer section, no further granular permissions are required - } - - /// - /// Gets an icon to be used for the right click action - /// - public string Icon - { - get { return "add"; } // add refers to an existing sprite - } - - /// - /// Gets a string for the javascript source - /// - public string JsSource - { - get { return "developer/RelationTypes/TreeMenu/ActionNewRelationType.js"; } - } - - /// - /// Gets a javascript string to execute when this action is fired - /// - public string JsFunctionName - { - get { return "javascript:actionNewRelationType();"; } - } - - public bool OpensDialog => true; - - #endregion - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/SendPublish.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/SendPublish.aspx.cs index 727af897ca..1f4ba277b5 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/SendPublish.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/SendPublish.aspx.cs @@ -1,7 +1,9 @@ using System; using Umbraco.Web; using Umbraco.Core; -using Umbraco.Web._Legacy.Actions; +using Umbraco.Web.Actions; +using Umbraco.Web.Composing; + namespace umbraco.dialogs { @@ -25,7 +27,7 @@ namespace umbraco.dialogs { //send notifications! TODO: This should be put somewhere centralized instead of hard coded directly here Services.NotificationService.SendNotification( - Services.ContentService.GetById(docId), ActionToPublish.Instance); + Services.ContentService.GetById(docId), Current.Actions.GetAction()); } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs index 89a03a1437..8473341ca8 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs @@ -11,9 +11,10 @@ using Umbraco.Core.Services; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web; +using Umbraco.Web.Actions; using Umbraco.Web.Composing; using Umbraco.Web.Macros; -using Umbraco.Web._Legacy.Actions; + namespace umbraco.presentation.templateControls { @@ -276,7 +277,7 @@ namespace umbraco.presentation.templateControls if (u == null) return false; var permission = Current.Services.UserService.GetPermissions(u, PageElements["path"].ToString()); - return permission.AssignedPermissions.Contains(ActionUpdate.Instance.Letter.ToString(CultureInfo.InvariantCulture), StringComparer.Ordinal); + return permission.AssignedPermissions.Contains(ActionUpdate.ActionLetter.ToString(CultureInfo.InvariantCulture), StringComparer.Ordinal); } #endregion diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs index f82587a413..5e0cb289f0 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs @@ -9,8 +9,9 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Web; +using Umbraco.Web.Actions; using Umbraco.Web.Composing; -using Umbraco.Web._Legacy.Actions; + namespace umbraco.presentation.webservices { @@ -186,7 +187,7 @@ namespace umbraco.presentation.webservices //send notifications! TODO: This should be put somewhere centralized instead of hard coded directly here if (parentId > 0) { - Services.NotificationService.SendNotification(contentService.GetById(parentId), ActionSort.Instance, UmbracoContext, Services.TextService, GlobalSettings); + Services.NotificationService.SendNotification(contentService.GetById(parentId), Current.Actions.GetAction(), UmbracoContext, Services.TextService, GlobalSettings); } }