Merge remote-tracking branch 'origin/temp8' into temp8-258-empty-trees-arrow

This commit is contained in:
elitsa
2018-11-04 22:44:20 +01:00
140 changed files with 1689 additions and 4360 deletions

View File

@@ -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; }
/// <summary>
/// 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
/// </summary>
/// <param name="category"></param>
public ActionMetadataAttribute(string category)
{
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentNullOrEmptyException(nameof(category));
Category = category;
}
/// <summary>
/// Constructor used to assign an explicit name and category
/// </summary>
/// <param name="category"></param>
/// <param name="name"></param>
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;
}
}
}

View File

@@ -37,101 +37,6 @@ namespace Umbraco.Core
return dirty.WasPropertyDirty("Published") && entity.Published;
}
/// <summary>
/// Returns a list of the current contents ancestors, not including the content itself.
/// </summary>
/// <param name="content">Current content</param>
/// <param name="contentService"></param>
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
public static IEnumerable<IContent> Ancestors(this IContent content, IContentService contentService)
{
return contentService.GetAncestors(content);
}
/// <summary>
/// Returns a list of the current contents children.
/// </summary>
/// <param name="content">Current content</param>
/// <param name="contentService"></param>
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
public static IEnumerable<IContent> Children(this IContent content, IContentService contentService)
{
return contentService.GetChildren(content.Id);
}
/// <summary>
/// Returns a list of the current contents descendants, not including the content itself.
/// </summary>
/// <param name="content">Current content</param>
/// <param name="contentService"></param>
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
public static IEnumerable<IContent> Descendants(this IContent content, IContentService contentService)
{
return contentService.GetDescendants(content);
}
/// <summary>
/// Returns the parent of the current content.
/// </summary>
/// <param name="content">Current content</param>
/// <param name="contentService"></param>
/// <returns>An <see cref="IContent"/> object</returns>
public static IContent Parent(this IContent content, IContentService contentService)
{
return contentService.GetById(content.ParentId);
}
#endregion
#region IMedia
/// <summary>
/// Returns a list of the current medias ancestors, not including the media itself.
/// </summary>
/// <param name="media">Current media</param>
/// <param name="mediaService"></param>
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
public static IEnumerable<IMedia> Ancestors(this IMedia media, IMediaService mediaService)
{
return mediaService.GetAncestors(media);
}
/// <summary>
/// Returns a list of the current medias children.
/// </summary>
/// <param name="media">Current media</param>
/// <param name="mediaService"></param>
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
public static IEnumerable<IMedia> Children(this IMedia media, IMediaService mediaService)
{
return mediaService.GetChildren(media.Id);
}
/// <summary>
/// Returns a list of the current medias descendants, not including the media itself.
/// </summary>
/// <param name="media">Current media</param>
/// <param name="mediaService"></param>
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
public static IEnumerable<IMedia> Descendants(this IMedia media, IMediaService mediaService)
{
return mediaService.GetDescendants(media);
}
/// <summary>
/// Returns the parent of the current media.
/// </summary>
/// <param name="media">Current media</param>
/// <param name="mediaService"></param>
/// <returns>An <see cref="IMedia"/> object</returns>
public static IMedia Parent(this IMedia media, IMediaService mediaService)
{
return mediaService.GetById(media.ParentId);
}
#endregion
/// <summary>
@@ -179,29 +84,7 @@ namespace Umbraco.Core
}
return false;
}
/// <summary>
/// Returns the children for the content base item
/// </summary>
/// <param name="content"></param>
/// <param name="services"></param>
/// <returns></returns>
/// <remarks>
/// This is a bit of a hack because we need to type check!
/// </remarks>
internal static IEnumerable<IContentBase> 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;
}
/// <summary>
/// Returns properties that do not belong to a group
/// </summary>

View File

@@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
private string VariantNameSqlExpression
=> SqlContext.VisitDto<ContentVersionCultureVariationDto, NodeDto>((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql;
protected virtual Sql<ISqlContext> GetBaseQuery(QueryType queryType, bool current)
protected Sql<ISqlContext> GetBaseQuery(QueryType queryType, bool current)
{
var sql = SqlContext.Sql();

View File

@@ -30,7 +30,7 @@ namespace Umbraco.Core.Services
IEnumerable<IUrlSegmentProvider> 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<IUrlSegmentProvider> urlSegmentProviders, IContent[] originalDescendants, IEnumerable<IContent> children, XElement xml, bool published)
private static void SerializeChildren(IContentService contentService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable<IUrlSegmentProvider> urlSegmentProviders, IEnumerable<IContent> 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<IUrlSegmentProvider> urlSegmentProviders, IMedia[] originalDescendants, IEnumerable<IMedia> children, XElement xml)
private static void SerializeChildren(IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable<IUrlSegmentProvider> urlSegmentProviders, IEnumerable<IMedia> 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);
}
}
}
}

View File

@@ -78,26 +78,11 @@ namespace Umbraco.Core.Services
/// </summary>
IEnumerable<IContent> GetByIds(IEnumerable<Guid> ids);
/// <summary>
/// Gets documents of a given document type.
/// </summary>
IEnumerable<IContent> GetByType(int documentTypeId);
/// <summary>
/// Gets documents at a given level.
/// </summary>
IEnumerable<IContent> GetByLevel(int level);
/// <summary>
/// Gets child documents of a given parent.
/// </summary>
IEnumerable<IContent> GetChildren(int parentId);
/// <summary>
/// Gets child documents of a document, (partially) matching a name.
/// </summary>
IEnumerable<IContent> GetChildren(int parentId, string name);
/// <summary>
/// Gets the parent of a document.
/// </summary>
@@ -118,16 +103,6 @@ namespace Umbraco.Core.Services
/// </summary>
IEnumerable<IContent> GetAncestors(IContent content);
/// <summary>
/// Gets descendant documents of a document.
/// </summary>
IEnumerable<IContent> GetDescendants(int id);
/// <summary>
/// Gets descendant documents of a document.
/// </summary>
IEnumerable<IContent> GetDescendants(IContent content);
/// <summary>
/// Gets all versions of a document.
/// </summary>
@@ -169,19 +144,8 @@ namespace Umbraco.Core.Services
/// <summary>
/// Gets documents in the recycle bin.
/// </summary>
IEnumerable<IContent> GetContentInRecycleBin();
/// <summary>
/// Gets child documents of a parent.
/// </summary>
/// <param name="id">The parent identifier.</param>
/// <param name="pageIndex">The page number.</param>
/// <param name="pageSize">The page size.</param>
/// <param name="totalRecords">Total number of documents.</param>
/// <param name="filter">Search text filter.</param>
/// <param name="ordering">Ordering infos.</param>
IEnumerable<IContent> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string filter = null, Ordering ordering = null);
IEnumerable<IContent> GetPagedContentInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
IQuery<IContent> filter = null, Ordering ordering = null);
/// <summary>
/// Gets child documents of a parent.
@@ -193,20 +157,7 @@ namespace Umbraco.Core.Services
/// <param name="filter">Query filter.</param>
/// <param name="ordering">Ordering infos.</param>
IEnumerable<IContent> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
IQuery<IContent> filter, Ordering ordering = null);
/// <summary>
/// Gets descendant documents of a given parent.
/// </summary>
/// <param name="id">The parent identifier.</param>
/// <param name="pageIndex">The page number.</param>
/// <param name="pageSize">The page size.</param>
/// <param name="totalRecords">Total number of documents.</param>
/// <param name="orderBy">A field to order by.</param>
/// <param name="orderDirection">The ordering direction.</param>
/// <param name="filter">Search text filter.</param>
IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
IQuery<IContent> filter = null, Ordering ordering = null);
/// <summary>
/// Gets descendant documents of a given parent.
@@ -220,7 +171,31 @@ namespace Umbraco.Core.Services
/// <param name="orderBySystemField">A flag indicating whether the ordering field is a system field.</param>
/// <param name="filter">Query filter.</param>
IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IContent> filter);
IQuery<IContent> filter = null, Ordering ordering = null);
/// <summary>
/// Gets paged documents of a content content
/// </summary>
/// <param name="contentTypeId">The page number.</param>
/// <param name="pageIndex">The page number.</param>
/// <param name="pageSize">The page size.</param>
/// <param name="totalRecords">Total number of documents.</param>
/// <param name="filter">Search text filter.</param>
/// <param name="ordering">Ordering infos.</param>
IEnumerable<IContent> GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords,
IQuery<IContent> filter, Ordering ordering = null);
/// <summary>
/// Gets paged documents for specified content types
/// </summary>
/// <param name="contentTypeIds">The page number.</param>
/// <param name="pageIndex">The page number.</param>
/// <param name="pageSize">The page size.</param>
/// <param name="totalRecords">Total number of documents.</param>
/// <param name="filter">Search text filter.</param>
/// <param name="ordering">Ordering infos.</param>
IEnumerable<IContent> GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords,
IQuery<IContent> filter, Ordering ordering = null);
/// <summary>
/// Counts documents of a given document type.

View File

@@ -78,27 +78,6 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMedia"/></returns>
IMedia GetById(int id);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetChildren(int id);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
@@ -112,37 +91,7 @@ namespace Umbraco.Core.Services
/// <param name="filter"></param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IMedia> filter);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter">Search text filter</param>
/// <param name="contentTypeFilter">A list of content type Ids to filter the list by</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
IQuery<IMedia> filter = null, Ordering ordering = null);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
@@ -157,21 +106,31 @@ namespace Umbraco.Core.Services
/// <param name="filter"></param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IMedia> filter);
IQuery<IMedia> filter = null, Ordering ordering = null);
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// Gets paged documents of a content content
/// </summary>
/// <param name="id">Id of the Parent to retrieve descendants from</param>
/// <returns>An Enumerable flat list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetDescendants(int id);
/// <param name="contentTypeId">The page number.</param>
/// <param name="pageIndex">The page number.</param>
/// <param name="pageSize">The page size.</param>
/// <param name="totalRecords">Total number of documents.</param>
/// <param name="filter">Search text filter.</param>
/// <param name="ordering">Ordering infos.</param>
IEnumerable<IMedia> GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords,
IQuery<IMedia> filter = null, Ordering ordering = null);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by the Id of the <see cref="IContentType"/>
/// Gets paged documents for specified content types
/// </summary>
/// <param name="id">Id of the <see cref="IMediaType"/></param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetMediaOfMediaType(int id);
/// <param name="contentTypeIds">The page number.</param>
/// <param name="pageIndex">The page number.</param>
/// <param name="pageSize">The page size.</param>
/// <param name="totalRecords">Total number of documents.</param>
/// <param name="filter">Search text filter.</param>
/// <param name="ordering">Ordering infos.</param>
IEnumerable<IMedia> GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords,
IQuery<IMedia> filter = null, Ordering ordering = null);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects, which reside at the first level / root
@@ -183,7 +142,8 @@ namespace Umbraco.Core.Services
/// Gets a collection of an <see cref="IMedia"/> objects, which resides in the Recycle Bin
/// </summary>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetMediaInRecycleBin();
IEnumerable<IMedia> GetPagedMediaInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
IQuery<IMedia> filter = null, Ordering ordering = null);
/// <summary>
/// Moves an <see cref="IMedia"/> object to a new location
@@ -321,13 +281,6 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetAncestors(IMedia media);
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// </summary>
/// <param name="media">The Parent <see cref="IMedia"/> object to retrieve descendants from</param>
/// <returns>An Enumerable flat list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetDescendants(IMedia media);
/// <summary>
/// Gets the parent of the current media as an <see cref="IMedia"/> item.
/// </summary>

View File

@@ -405,28 +405,40 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by the Id of the <see cref="IContentType"/>
/// </summary>
/// <param name="id">Id of the <see cref="IContentType"/></param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetByType(int id)
/// <inheritdoc />
public IEnumerable<IContent> GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords
, IQuery<IContent> 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<IContent>().Where(x => x.ContentTypeId == id);
return _documentRepository.Get(query);
return _documentRepository.GetPage(
Query<IContent>().Where(x => x.ContentTypeId == contentTypeId),
pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
internal IEnumerable<IContent> GetPublishedContentOfContentType(int id)
/// <inheritdoc />
public IEnumerable<IContent> GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, IQuery<IContent> 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<IContent>().Where(x => x.ContentTypeId == id);
return _documentRepository.Get(query);
return _documentRepository.GetPage(
Query<IContent>().Where(x => contentTypeIds.Contains(x.ContentTypeId)),
pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
@@ -536,21 +548,6 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetChildren(int id)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
var query = Query<IContent>().Where(x => x.ParentId == id);
return _documentRepository.Get(query).OrderBy(x => x.SortOrder);
}
}
/// <summary>
/// Gets a collection of published <see cref="IContent"/> objects by Parent Id
/// </summary>
@@ -568,18 +565,7 @@ namespace Umbraco.Core.Services.Implement
/// <inheritdoc />
public IEnumerable<IContent> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
string filter = null, Ordering ordering = null)
{
var filterQuery = filter.IsNullOrWhiteSpace()
? null
: Query<IContent>().Where(x => x.Name.Contains(filter));
return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, filterQuery, ordering);
}
/// <inheritdoc />
public IEnumerable<IContent> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
IQuery<IContent> filter, Ordering ordering = null)
IQuery<IContent> 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
}
/// <inheritdoc />
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren,
IQuery<IContent> filter = null, Ordering ordering = null)
{
var filterQuery = filter.IsNullOrWhiteSpace()
? null
: Query<IContent>().Where(x => x.Name.Contains(filter));
return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
}
/// <inheritdoc />
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IContent> 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<IContent>();
//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<IContent>();
}
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);
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by its name or partial name
/// </summary>
/// <param name="parentId">Id of the Parent to retrieve Children from</param>
/// <param name="name">Full or partial name of the children</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetChildren(int parentId, string name)
private IEnumerable<IContent> GetPagedDescendantsLocked(string contentPath, long pageIndex, int pageSize, out long totalChildren,
IQuery<IContent> filter, Ordering ordering)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
var query = Query<IContent>().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));
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> 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<IContent>();
}
var pathMatch = content.Path + ",";
var query = Query<IContent>().Where(x => x.Id != content.Id && x.Path.StartsWith(pathMatch));
return _documentRepository.Get(query);
}
}
var query = Query<IContent>();
if (!contentPath.IsNullOrWhiteSpace())
query.Where(x => x.Path.SqlStartsWith($"{contentPath},", TextColumnType.NVarchar));
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="content"><see cref="IContent"/> item to retrieve Descendants from</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetDescendants(IContent content)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
var pathMatch = content.Path + ",";
var query = Query<IContent>().Where(x => x.Id != content.Id && x.Path.StartsWith(pathMatch));
return _documentRepository.Get(query);
}
return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
}
/// <summary>
@@ -772,13 +706,17 @@ namespace Umbraco.Core.Services.Implement
/// Gets a collection of an <see cref="IContent"/> objects, which resides in the Recycle Bin
/// </summary>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetContentInRecycleBin()
public IEnumerable<IContent> GetPagedContentInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
IQuery<IContent> 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<IContent>().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<int>();
//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<IContent>(document, TreeChangeTypes.RefreshBranch).ToEventArgs());
scope.Events.Dispatch(Published, this, new PublishEventArgs<IContent>(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<IContent>();
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<IContent>(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<ContentService>(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<IContent>(descendant, descendantCopy, parentId)))
continue;
if (scope.Events.DispatchCancelable(Copying, this, new CopyEventArgs<IContent>(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;
}
}
}

View File

@@ -364,18 +364,39 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by the Id of the <see cref="IMediaType"/>
/// </summary>
/// <param name="id">Id of the <see cref="IMediaType"/></param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetMediaOfMediaType(int id)
/// <inheritdoc />
public IEnumerable<IMedia> GetPagedOfType(int contentTypeId, long pageIndex, int pageSize, out long totalRecords, IQuery<IMedia> 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<IMedia>().Where(x => x.ContentTypeId == id);
return _mediaRepository.Get(query);
scope.ReadLock(Constants.Locks.ContentTree);
return _mediaRepository.GetPage(
Query<IMedia>().Where(x => x.ContentTypeId == contentTypeId),
pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
/// <inheritdoc />
public IEnumerable<IMedia> GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, IQuery<IMedia> 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<IMedia>().Where(x => contentTypeIds.Contains(x.ContentTypeId)),
pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
@@ -460,149 +481,36 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetChildren(int id)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MediaTree);
var query = Query<IMedia>().Where(x => x.ParentId == id);
return _mediaRepository.Get(query).OrderBy(x => x.SortOrder);
}
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page index (zero based)</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, string filter = "")
{
var filterQuery = filter.IsNullOrWhiteSpace()
? null
: Query<IMedia>().Where(x => x.Name.Contains(filter));
return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page index (zero based)</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter"></param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IMedia> filter)
/// <inheritdoc />
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
IQuery<IMedia> 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<IMedia>().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);
}
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter">Search text filter</param>
/// <param name="contentTypeFilter">A list of content type Ids to filter the list by</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter)
/// <inheritdoc />
public IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren,
IQuery<IMedia> 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<IMedia>();
// 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<IMedia>().Where(x => x.Name.Contains(filter));
return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filterQuery, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
}
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> 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<IMedia>().Where(x => x.Name.Contains(filter));
return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter"></param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IMedia> 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<IMedia>();
//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<IMedia>();
}
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);
}
}
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve descendants from</param>
/// <returns>An Enumerable flat list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetDescendants(int id)
private IEnumerable<IMedia> GetPagedDescendantsLocked(string mediaPath, long pageIndex, int pageSize, out long totalChildren,
IQuery<IMedia> 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<IMedia>();
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<IMedia>().Where(x => x.Id != media.Id && x.Path.StartsWith(pathMatch));
return _mediaRepository.Get(query);
}
}
var query = Query<IMedia>();
if (!mediaPath.IsNullOrWhiteSpace())
query.Where(x => x.Path.SqlStartsWith(mediaPath + ",", TextColumnType.NVarchar));
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// </summary>
/// <param name="media">The Parent <see cref="IMedia"/> object to retrieve descendants from</param>
/// <returns>An Enumerable flat list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetDescendants(IMedia media)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MediaTree);
var pathMatch = media.Path + ",";
var query = Query<IMedia>().Where(x => x.Id != media.Id && x.Path.StartsWith(pathMatch));
return _mediaRepository.Get(query);
}
return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
}
/// <summary>
@@ -694,17 +579,18 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets a collection of an <see cref="IMedia"/> objects, which resides in the Recycle Bin
/// </summary>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetMediaInRecycleBin()
/// <inheritdoc />
public IEnumerable<IMedia> GetPagedMediaInRecycleBin(long pageIndex, int pageSize, out long totalRecords,
IQuery<IMedia> 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<IMedia>().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<IMedia>();
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<IMedia>(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<MediaService>(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);
}
}
}

View File

@@ -393,12 +393,14 @@ namespace Umbraco.Core.Services.Implement
// fixme get rid of string filter?
public IEnumerable<IMember> GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, string memberTypeAlias = null, string filter = "")
public IEnumerable<IMember> 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<IMember> GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, bool orderBySystemField, string memberTypeAlias, string filter)
public IEnumerable<IMember> 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))
{

View File

@@ -143,7 +143,6 @@
<Compile Include="Cache\SingleItemsOnlyRepositoryCachePolicy.cs" />
<Compile Include="Cache\StaticCacheProvider.cs" />
<Compile Include="Cache\TypedCacheRefresherBase.cs" />
<Compile Include="CodeAnnotations\ActionMetadataAttribute.cs" />
<Compile Include="CodeAnnotations\FriendlyNameAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoObjectTypeAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoUdiTypeAttribute.cs" />

View File

@@ -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

View File

@@ -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<object> { icon };
e.IndexItem.ValueSet.Values[IconFieldName] = icon;
}
}

View File

@@ -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<object> { 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<object> { email?.ToString().Replace(".", " ").Replace("@", " ") };
if (email.Count > 0)
{
//will be indexed as full text (the default anaylyzer)
e.IndexItem.ValueSet.Values["_searchEmail"] = new List<object> { email[0]?.ToString().Replace(".", " ").Replace("@", " ") };
}
}
}

View File

@@ -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
}
}

View File

@@ -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()
{

View File

@@ -459,7 +459,7 @@ namespace Umbraco.Tests.Integration
#region Utils
private IEnumerable<IContent> 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());

View File

@@ -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,

View File

@@ -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<ContentServicePerformanceTest>("Returned " + total.Count + " items");

View File

@@ -35,7 +35,10 @@ namespace Umbraco.Tests.Services
/// as well as configuration.
/// </summary>
[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<IContent>();
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<IContent>();
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<IContent> 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);

View File

@@ -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<IMedia>().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<IMedia>().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)),
Ordering.By("SortOrder", Direction.Ascending));
Assert.AreEqual(9, result.Count());
Assert.AreEqual(20, total);
}

View File

@@ -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<PerformanceTests>("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<PerformanceTests>("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()

View File

@@ -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);

View File

@@ -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<ActionCollectionBuilder>()
.SetProducer(Enumerable.Empty<Type>);
Container.RegisterCollectionBuilder<ActionCollectionBuilder>();
Container.RegisterCollectionBuilder<PropertyValueConverterCollectionBuilder>();
Container.RegisterSingleton<IPublishedContentTypeFactory, PublishedContentTypeFactory>();

View File

@@ -406,7 +406,6 @@
<Compile Include="Persistence\Repositories\StylesheetRepositoryTest.cs" />
<Compile Include="PublishedContent\PublishedContentMoreTests.cs" />
<Compile Include="Publishing\PublishingStrategyTests.cs" />
<Compile Include="Composing\ActionCollectionTests.cs" />
<Compile Include="TestHelpers\Entities\MockedMember.cs" />
<Compile Include="TestHelpers\Entities\MockedUser.cs" />
<Compile Include="TestHelpers\Stubs\TestProfiler.cs" />

View File

@@ -71,11 +71,7 @@ namespace Umbraco.Tests.UmbracoExamine
contentService = Mock.Of<IContentService>(
x => x.GetPagedDescendants(
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out longTotalRecs, It.IsAny<string>(), It.IsAny<Direction>(), It.IsAny<string>())
==
allRecs
&& x.GetPagedDescendants(
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out longTotalRecs, It.IsAny<string>(), It.IsAny<Direction>(), It.IsAny<bool>(), It.IsAny<IQuery<IContent>>())
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out longTotalRecs, It.IsAny<IQuery<IContent>>(), It.IsAny<Ordering>())
==
allRecs);
}
@@ -116,12 +112,7 @@ namespace Umbraco.Tests.UmbracoExamine
mediaServiceMock
.Setup(x => x.GetPagedDescendants(
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out totalRecs, It.IsAny<string>(), It.IsAny<Direction>(), It.IsAny<string>())
).Returns(() => allRecs);
mediaServiceMock
.Setup(x => x.GetPagedDescendants(
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out totalRecs, It.IsAny<string>(), It.IsAny<Direction>(), It.IsAny<bool>(), It.IsAny<IQuery<IMedia>>())
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out totalRecs, It.IsAny<IQuery<IMedia>>(), It.IsAny<Ordering>())
).Returns(() => allRecs);
//mediaServiceMock.Setup(service => service.GetPagedXmlEntries(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<int>(), out longTotalRecs))

View File

@@ -49,7 +49,7 @@ namespace Umbraco.Tests.UmbracoExamine
.ToArray();
var contentService = Mock.Of<IContentService>(
x => x.GetPagedDescendants(
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out totalRecs, It.IsAny<string>(), It.IsAny<Direction>(), It.IsAny<bool>(), It.IsAny<IQuery<IContent>>())
It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out totalRecs, It.IsAny<IQuery<IContent>>(), It.IsAny<Ordering>())
==
allRecs);

View File

@@ -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);
}
}
}

View File

@@ -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()
}),
})));

View File

@@ -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) {

View File

@@ -23,7 +23,7 @@
* </pre>
**/
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)) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -0,0 +1,14 @@
<div class="umb-dialog" ng-controller="Umbraco.Dialogs.LegacyDeleteController">
<div class="umb-dialog-body" >
<div class="umb-pane">
<p>
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
</p>
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
</umb-confirm>
</div>
</div>
</div>

View File

@@ -324,8 +324,6 @@
<Content Include="Umbraco\Developer\RelationTypes\Images\Refresh.gif" />
<Content Include="Umbraco\Developer\RelationTypes\NewRelationType.aspx" />
<Content Include="Umbraco\Developer\RelationTypes\RelationTypesWebService.asmx" />
<Content Include="Umbraco\Developer\RelationTypes\TreeMenu\ActionDeleteRelationType.js" />
<Content Include="Umbraco\Developer\RelationTypes\TreeMenu\ActionNewRelationType.js" />
<Content Include="Umbraco\Dialogs\ChangeDocType.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>

View File

@@ -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) { }
});
}
}

View File

@@ -1,3 +0,0 @@
function actionNewRelationType() {
UmbClientMgr.openModalWindow('developer/RelationTypes/NewRelationType.aspx', 'Create New RelationType', true, 400, 300, 0, 0);
}

View File

@@ -113,7 +113,8 @@ namespace Umbraco.Web.UI.Umbraco.Dialogs
private IEnumerable<IContentType> RemoveInvalidByChildrenDocumentTypesFromAlternatives(IEnumerable<IContentType> 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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,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<EditorValidatorCollectionBuilder>();
public static UmbracoFeatures Features(this Composition composition)
=> composition.Container.GetInstance<UmbracoFeatures>();
/// <summary>
/// Gets the filtered controller factories collection builder.
/// </summary>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,8 +7,9 @@ using System.Web;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
using Umbraco.Web.Models.Trees;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any();
@@ -111,11 +112,11 @@ namespace Umbraco.Web.Trees
if (hasChildren == false)
{
//delete action
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
}
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
return menu;
}
@@ -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<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
return menu;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -427,7 +427,6 @@
<Compile Include="PublishedCache\NuCache\PublishedSnapshot.cs" />
<Compile Include="PublishedCache\PublishedElement.cs" />
<Compile Include="PublishedCache\PublishedElementPropertyBase.cs" />
<Compile Include="Models\Trees\DisableUser.cs" />
<Compile Include="PropertyEditors\ValueConverters\ContentPickerValueConverter.cs" />
<Compile Include="PublishedCache\PublishedSnapshotServiceBase.cs" />
<Compile Include="PublishedCache\IDomainCache.cs" />
@@ -530,39 +529,26 @@
<Compile Include="Runtime\WebRuntimeComponent.cs" />
<Compile Include="Editors\PublishedStatusController.cs" />
<Compile Include="Editors\NuCacheStatusController.cs" />
<Compile Include="_Legacy\Actions\Action.cs" />
<Compile Include="_Legacy\Actions\ActionAssignDomain.cs" />
<Compile Include="_Legacy\Actions\ActionBrowse.cs" />
<Compile Include="_Legacy\Actions\ActionChangeDocType.cs" />
<Compile Include="_Legacy\Actions\ActionCollection.cs" />
<Compile Include="_Legacy\Actions\ActionCollectionBuilder.cs" />
<Compile Include="_Legacy\Actions\ActionCopy.cs" />
<Compile Include="_Legacy\Actions\ActionCreateBlueprintFromContent.cs" />
<Compile Include="_Legacy\Actions\ActionDelete.cs" />
<Compile Include="_Legacy\Actions\ActionEmptyTranscan.cs" />
<Compile Include="_Legacy\Actions\ActionExport.cs" />
<Compile Include="_Legacy\Actions\ActionImport.cs" />
<Compile Include="_Legacy\Actions\ActionMove.cs" />
<Compile Include="_Legacy\Actions\ActionNew.cs" />
<Compile Include="_Legacy\Actions\ActionNotify.cs" />
<Compile Include="_Legacy\Actions\ActionNull.cs" />
<Compile Include="_Legacy\Actions\ActionPackage.cs" />
<Compile Include="_Legacy\Actions\ActionPackageCreate.cs" />
<Compile Include="_Legacy\Actions\ActionProtect.cs" />
<Compile Include="_Legacy\Actions\ActionPublish.cs" />
<Compile Include="_Legacy\Actions\ActionRefresh.cs" />
<Compile Include="_Legacy\Actions\ActionRePublish.cs" />
<Compile Include="_Legacy\Actions\ActionRestore.cs" />
<Compile Include="_Legacy\Actions\ActionRights.cs" />
<Compile Include="_Legacy\Actions\ActionRollback.cs" />
<Compile Include="_Legacy\Actions\ActionSort.cs" />
<Compile Include="_Legacy\Actions\ActionToPublish.cs" />
<Compile Include="_Legacy\Actions\ActionTranslate.cs" />
<Compile Include="_Legacy\Actions\ActionUnpublish.cs" />
<Compile Include="_Legacy\Actions\ActionUpdate.cs" />
<Compile Include="_Legacy\Actions\ContextMenuSeperator.cs" />
<Compile Include="_Legacy\Actions\IAction.cs" />
<Compile Include="_Legacy\Actions\LegacyActionMenuItemAttribute.cs" />
<Compile Include="Actions\ActionAssignDomain.cs" />
<Compile Include="Actions\ActionBrowse.cs" />
<Compile Include="Actions\ActionChangeDocType.cs" />
<Compile Include="Actions\ActionCollection.cs" />
<Compile Include="Actions\ActionCollectionBuilder.cs" />
<Compile Include="Actions\ActionCopy.cs" />
<Compile Include="Actions\ActionCreateBlueprintFromContent.cs" />
<Compile Include="Actions\ActionDelete.cs" />
<Compile Include="Actions\ActionMove.cs" />
<Compile Include="Actions\ActionNew.cs" />
<Compile Include="Actions\ActionProtect.cs" />
<Compile Include="Actions\ActionPublish.cs" />
<Compile Include="Actions\ActionRestore.cs" />
<Compile Include="Actions\ActionRights.cs" />
<Compile Include="Actions\ActionRollback.cs" />
<Compile Include="Actions\ActionSort.cs" />
<Compile Include="Actions\ActionToPublish.cs" />
<Compile Include="Actions\ActionUnpublish.cs" />
<Compile Include="Actions\ActionUpdate.cs" />
<Compile Include="Actions\IAction.cs" />
<Compile Include="Models\ContentEditing\EntityBasic.cs" />
<Compile Include="Models\Trees\ApplicationAttribute.cs" />
<Compile Include="Models\Trees\ApplicationDefinitions.cs" />
@@ -947,7 +933,6 @@
<Compile Include="PropertyEditors\TrueFalsePropertyEditor.cs" />
<Compile Include="Trees\MediaTreeController.cs" />
<Compile Include="Models\Trees\ActionMenuItem.cs" />
<Compile Include="Models\Trees\ActionMenuItemAttribute.cs" />
<Compile Include="Trees\ActionUrlMethod.cs" />
<Compile Include="Trees\ContentTreeControllerBase.cs" />
<Compile Include="Trees\ISearchableTree.cs" />
@@ -1263,12 +1248,6 @@
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\NewRelationType.aspx.designer.cs">
<DependentUpon>NewRelationType.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\RelationTypesWebService.asmx.cs">
<DependentUpon>RelationTypesWebService.asmx</DependentUpon>
<SubType>Component</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\TreeMenu\ActionDeleteRelationType.cs" />
<Compile Include="umbraco.presentation\umbraco\developer\RelationTypes\TreeMenu\ActionNewRelationType.cs" />
<Compile Include="umbraco.presentation\umbraco\dialogs\insertMasterpageContent.aspx.cs">
<DependentUpon>insertMasterpageContent.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -1372,7 +1351,6 @@
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\NewRelationType.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\RelationTypesWebService.asmx" />
<Content Include="umbraco.presentation\umbraco\dashboard\FeedProxy.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\insertMasterpageContent.aspx">
<SubType>ASPXCodeBehind</SubType>

View File

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

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