Merge temp-U4-6911 into 7.4.0
This commit is contained in:
@@ -9,6 +9,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class ObjectTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Guid for a data type container
|
||||
/// </summary>
|
||||
public const string DataTypeContainer = "521231E3-8B37-469C-9F9D-51AFC91FEB7B";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a doc type container
|
||||
/// </summary>
|
||||
@@ -102,6 +107,8 @@ namespace Umbraco.Core
|
||||
/// Guid for a Lock object.
|
||||
/// </summary>
|
||||
public const string LockObject = "87A9F1FF-B1E4-4A25-BABB-465A4A47EC41";
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
internal class DataOperationException<T> : Exception
|
||||
{
|
||||
public T Operation { get; private set; }
|
||||
|
||||
public DataOperationException(T operation, string message)
|
||||
:base(message)
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
|
||||
public DataOperationException(T operation)
|
||||
: base("Data operation exception: " + operation)
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,6 @@ namespace Umbraco.Core.Models
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
[Obsolete("Don't use this, parentId is always -1 for data types")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public DataTypeDefinition(int parentId, string propertyEditorAlias)
|
||||
{
|
||||
_parentId = parentId;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a folder for organizing entities such as content types and data types
|
||||
/// </summary>
|
||||
public sealed class EntityContainer : UmbracoEntity, IAggregateRoot
|
||||
{
|
||||
public EntityContainer()
|
||||
{
|
||||
}
|
||||
|
||||
public EntityContainer(int id, int parentId, string name, int userId, string path)
|
||||
{
|
||||
Id = id;
|
||||
ParentId = parentId;
|
||||
Name = name;
|
||||
CreatorId = userId;
|
||||
Path = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Implementation of the <see cref="IUmbracoEntity"/> for internal use.
|
||||
/// </summary>
|
||||
internal class UmbracoEntity : Entity, IUmbracoEntity
|
||||
public class UmbracoEntity : Entity, IUmbracoEntity
|
||||
{
|
||||
private int _creatorId;
|
||||
private int _level;
|
||||
|
||||
@@ -15,49 +15,49 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Content Item Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentItemType)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.ContentItemType)]
|
||||
[FriendlyName("Content Item Type")]
|
||||
ContentItemType,
|
||||
|
||||
/// <summary>
|
||||
/// Root
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.SystemRoot)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.SystemRoot)]
|
||||
[FriendlyName("Root")]
|
||||
ROOT,
|
||||
|
||||
/// <summary>
|
||||
/// Document
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Document, typeof(IContent))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Document, typeof(IContent))]
|
||||
[FriendlyName("Document")]
|
||||
Document,
|
||||
|
||||
/// <summary>
|
||||
/// Media
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Media, typeof(IMedia))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Media, typeof(IMedia))]
|
||||
[FriendlyName("Media")]
|
||||
Media,
|
||||
|
||||
/// <summary>
|
||||
/// Member Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.MemberType, typeof(IMemberType))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MemberType, typeof(IMemberType))]
|
||||
[FriendlyName("Member Type")]
|
||||
MemberType,
|
||||
|
||||
/// <summary>
|
||||
/// Template
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Template, typeof(ITemplate))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Template, typeof(ITemplate))]
|
||||
[FriendlyName("Template")]
|
||||
Template,
|
||||
|
||||
/// <summary>
|
||||
/// Member Group
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.MemberGroup)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MemberGroup)]
|
||||
[FriendlyName("Member Group")]
|
||||
MemberGroup,
|
||||
|
||||
@@ -65,57 +65,73 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Content Item
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentItem)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.ContentItem)]
|
||||
[FriendlyName("Content Item")]
|
||||
ContentItem,
|
||||
|
||||
/// <summary>
|
||||
/// "Media Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.MediaType, typeof(IMediaType))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MediaType, typeof(IMediaType))]
|
||||
[FriendlyName("Media Type")]
|
||||
MediaType,
|
||||
|
||||
/// <summary>
|
||||
/// Document Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.DocumentType, typeof(IContentType))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentType, typeof(IContentType))]
|
||||
[FriendlyName("Document Type")]
|
||||
DocumentType,
|
||||
|
||||
/// <summary>
|
||||
/// Recycle Bin
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentRecycleBin)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.ContentRecycleBin)]
|
||||
[FriendlyName("Recycle Bin")]
|
||||
RecycleBin,
|
||||
|
||||
/// <summary>
|
||||
/// Stylesheet
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Stylesheet)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Stylesheet)]
|
||||
[FriendlyName("Stylesheet")]
|
||||
Stylesheet,
|
||||
|
||||
/// <summary>
|
||||
/// Member
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Member, typeof(IMember))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Member, typeof(IMember))]
|
||||
[FriendlyName("Member")]
|
||||
Member,
|
||||
|
||||
/// <summary>
|
||||
/// Data Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))]
|
||||
[FriendlyName("Data Type")]
|
||||
DataType,
|
||||
|
||||
/// <summary>
|
||||
/// Entity Container
|
||||
/// Document type container
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.DocumentTypeContainer)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentTypeContainer)]
|
||||
[FriendlyName("Document Type Container")]
|
||||
DocumentTypeContainer
|
||||
DocumentTypeContainer,
|
||||
|
||||
/// <summary>
|
||||
/// Media type container
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MediaTypeContainer)]
|
||||
[FriendlyName("Media Type Container")]
|
||||
MediaTypeContainer,
|
||||
|
||||
/// <summary>
|
||||
/// Media type container
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DataTypeContainer)]
|
||||
[FriendlyName("Data Type Container")]
|
||||
DataTypeContainer
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -16,6 +18,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Relators;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
@@ -28,72 +31,90 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
where TEntity : class, IContentTypeComposition
|
||||
{
|
||||
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax,
|
||||
Guid containerType)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
_guidRepo = new GuidReadOnlyContentTypeBaseRepository(this, work, cache, logger, sqlSyntax);
|
||||
ContainerRepository = new EntityContainerRepository(work, cache, logger, sqlSyntax, containerType, NodeObjectTypeId);
|
||||
}
|
||||
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
_guidRepo = new GuidReadOnlyContentTypeBaseRepository(this, work, cache, logger, sqlSyntax);
|
||||
ContainerRepository = null;
|
||||
}
|
||||
|
||||
protected EntityContainerRepository ContainerRepository { get; private set; }
|
||||
private readonly GuidReadOnlyContentTypeBaseRepository _guidRepo;
|
||||
|
||||
/// <summary>
|
||||
/// The container object type - used for organizing content types
|
||||
/// </summary>
|
||||
protected abstract Guid ContainerObjectTypeId { get; }
|
||||
|
||||
public Attempt<int> CreateFolder(int parentId, string name, int userId)
|
||||
public IEnumerable<MoveEventInfo<TEntity>> Move(TEntity toMove, int parentId)
|
||||
{
|
||||
name = name.Trim();
|
||||
|
||||
Mandate.ParameterNotNullOrEmpty(name, "name");
|
||||
|
||||
var exists = Database.FirstOrDefault<NodeDto>(
|
||||
new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.ParentId == parentId && dto.Text == name && dto.NodeObjectType == ContainerObjectTypeId));
|
||||
|
||||
if (exists != null)
|
||||
if (parentId > 0)
|
||||
{
|
||||
return Attempt.Fail(exists.NodeId, new InvalidOperationException("A folder with the same name already exists"));
|
||||
}
|
||||
var container = ContainerRepository.Get(parentId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
|
||||
var level = 0;
|
||||
var path = "-1";
|
||||
if (parentId > -1)
|
||||
{
|
||||
var parent = Database.FirstOrDefault<NodeDto>(
|
||||
new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.NodeId == parentId && dto.NodeObjectType == ContainerObjectTypeId));
|
||||
|
||||
if (parent == null)
|
||||
// Check on paths
|
||||
if ((string.Format(",{0},", container.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1)
|
||||
{
|
||||
return Attempt.Fail(0, new NullReferenceException("No content type container found with parent id " + parentId));
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedNotAllowedByPath);
|
||||
}
|
||||
level = parent.Level;
|
||||
path = parent.Path;
|
||||
}
|
||||
|
||||
var folder = new NodeDto
|
||||
//used to track all the moved entities to be given to the event
|
||||
var moveInfo = new List<MoveEventInfo<TEntity>>
|
||||
{
|
||||
CreateDate = DateTime.Now,
|
||||
Level = Convert.ToInt16(level + 1),
|
||||
NodeObjectType = ContainerObjectTypeId,
|
||||
ParentId = parentId,
|
||||
Path = path,
|
||||
SortOrder = 0,
|
||||
Text = name,
|
||||
Trashed = false,
|
||||
UniqueId = Guid.NewGuid(),
|
||||
UserId = userId
|
||||
new MoveEventInfo<TEntity>(toMove, toMove.Path, parentId)
|
||||
};
|
||||
|
||||
Database.Save(folder);
|
||||
//update the path
|
||||
folder.Path = folder.Path + "," + folder.NodeId;
|
||||
Database.Save(folder);
|
||||
//do the move to a new parent
|
||||
toMove.ParentId = parentId;
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(toMove);
|
||||
|
||||
return Attempt.Succeed(folder.NodeId);
|
||||
//update all descendants
|
||||
var descendants = this.GetByQuery(
|
||||
new Query<TEntity>().Where(type => type.Path.StartsWith(toMove.Path + ",")));
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<TEntity>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
//all we're doing here is setting the parent Id to be dirty so that it resets the path/level/etc...
|
||||
descendant.ParentId = descendant.ParentId;
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
return moveInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a folder - this will move all contained entities into their parent
|
||||
/// </summary>
|
||||
/// <param name="containerId"></param>
|
||||
public void DeleteContainer(int containerId)
|
||||
{
|
||||
if (ContainerRepository == null) throw new NotSupportedException("The repository type " + GetType() + " does not support containers");
|
||||
|
||||
var found = ContainerRepository.Get(containerId);
|
||||
ContainerRepository.Delete(found);
|
||||
}
|
||||
|
||||
public EntityContainer CreateContainer(int parentId, string name, int userId)
|
||||
{
|
||||
if (ContainerRepository == null) throw new NotSupportedException("The repository type " + GetType() + " does not support containers");
|
||||
|
||||
var container = new EntityContainer
|
||||
{
|
||||
ParentId = parentId,
|
||||
Name = name,
|
||||
CreatorId = userId
|
||||
};
|
||||
ContainerRepository.AddOrUpdate(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,15 +126,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sqlClause = new Sql();
|
||||
sqlClause.Select("*")
|
||||
.From<PropertyTypeGroupDto>()
|
||||
.RightJoin<PropertyTypeDto>()
|
||||
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId);
|
||||
.From<PropertyTypeGroupDto>(SqlSyntax)
|
||||
.RightJoin<PropertyTypeDto>(SqlSyntax)
|
||||
.On<PropertyTypeGroupDto, PropertyTypeDto>(SqlSyntax, left => left.Id, right => right.PropertyTypeGroupId)
|
||||
.InnerJoin<DataTypeDto>(SqlSyntax)
|
||||
.On<PropertyTypeDto, DataTypeDto>(SqlSyntax, left => left.DataTypeId, right => right.DataTypeId);
|
||||
|
||||
var translator = new SqlTranslator<PropertyType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId);
|
||||
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -11,6 +13,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Relators;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
@@ -22,13 +25,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly ITemplateRepository _templateRepository;
|
||||
|
||||
public ContentTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, ITemplateRepository templateRepository)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax, new Guid(Constants.ObjectTypes.DocumentTypeContainer))
|
||||
{
|
||||
_templateRepository = templateRepository;
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of RepositoryBase<int,IContentType>
|
||||
|
||||
protected override IContentType PerformGet(int id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetContentTypes(
|
||||
@@ -46,7 +47,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
@@ -57,16 +58,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContentType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text);
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<DocumentTypeDto, ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
/// </summary>
|
||||
@@ -88,19 +87,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
return Database.Fetch<string>("SELECT DISTINCT Alias FROM cmsPropertyType ORDER BY Alias");
|
||||
}
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<int,IContentType>
|
||||
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
|
||||
sql.Select(isCount ? "COUNT(*)" : "*")
|
||||
.From<ContentTypeDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.LeftJoin<DocumentTypeDto>()
|
||||
.On<DocumentTypeDto, ContentTypeDto>(left => left.ContentTypeNodeId, right => right.NodeId)
|
||||
.From<ContentTypeDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentTypeDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.LeftJoin<DocumentTypeDto>(SqlSyntax)
|
||||
.On<DocumentTypeDto, ContentTypeDto>(SqlSyntax ,left => left.ContentTypeNodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
|
||||
return sql;
|
||||
@@ -135,11 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.DocumentType); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit of Work Implementation
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a content type
|
||||
/// </summary>
|
||||
@@ -239,16 +232,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The container object type - used for organizing content types
|
||||
/// </summary>
|
||||
protected override Guid ContainerObjectTypeId
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.DocumentTypeContainer); }
|
||||
}
|
||||
|
||||
protected override IContentType PerformGet(Guid id)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -27,6 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly CacheHelper _cacheHelper;
|
||||
private readonly IContentTypeRepository _contentTypeRepository;
|
||||
private readonly DataTypePreValueRepository _preValRepository;
|
||||
private readonly EntityContainerRepository _containerRepository;
|
||||
|
||||
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax,
|
||||
IContentTypeRepository contentTypeRepository)
|
||||
@@ -35,10 +38,31 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
_cacheHelper = cacheHelper;
|
||||
_contentTypeRepository = contentTypeRepository;
|
||||
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax);
|
||||
|
||||
_containerRepository = new EntityContainerRepository(work, cache, logger, sqlSyntax, new Guid(Constants.ObjectTypes.DataTypeContainer), NodeObjectTypeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a folder - this will move all contained entities into their parent
|
||||
/// </summary>
|
||||
/// <param name="containerId"></param>
|
||||
public void DeleteContainer(int containerId)
|
||||
{
|
||||
var found = _containerRepository.Get(containerId);
|
||||
_containerRepository.Delete(found);
|
||||
}
|
||||
|
||||
public EntityContainer CreateContainer(int parentId, string name, int userId)
|
||||
{
|
||||
var container = new EntityContainer
|
||||
{
|
||||
ParentId = parentId,
|
||||
Name = name,
|
||||
CreatorId = userId
|
||||
};
|
||||
_containerRepository.AddOrUpdate(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
#region Overrides of RepositoryBase<int,DataTypeDefinition>
|
||||
|
||||
protected override IDataTypeDefinition PerformGet(int id)
|
||||
@@ -331,6 +355,49 @@ AND umbracoNode.id <> @id",
|
||||
AddOrUpdatePreValues(dtd, values);
|
||||
}
|
||||
|
||||
public IEnumerable<MoveEventInfo<IDataTypeDefinition>> Move(IDataTypeDefinition toMove, int parentId)
|
||||
{
|
||||
if (parentId > 0)
|
||||
{
|
||||
var container = _containerRepository.Get(parentId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
|
||||
// Check on paths
|
||||
if ((string.Format(",{0},", container.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1)
|
||||
{
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedNotAllowedByPath);
|
||||
}
|
||||
}
|
||||
|
||||
//used to track all the moved entities to be given to the event
|
||||
var moveInfo = new List<MoveEventInfo<IDataTypeDefinition>>
|
||||
{
|
||||
new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId)
|
||||
};
|
||||
|
||||
//do the move to a new parent
|
||||
toMove.ParentId = parentId;
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(toMove);
|
||||
|
||||
//update all descendants
|
||||
var descendants = this.GetByQuery(
|
||||
new Query<IDataTypeDefinition>().Where(type => type.Path.StartsWith(toMove.Path + ",")));
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<IDataTypeDefinition>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
//all we're doing here is setting the parent Id to be dirty so that it resets the path/level/etc...
|
||||
descendant.ParentId = descendant.ParentId + 1;
|
||||
descendant.ParentId = descendant.ParentId - 1;
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
return moveInfo;
|
||||
}
|
||||
|
||||
public void AddOrUpdatePreValues(IDataTypeDefinition dataType, IDictionary<string, PreValue> values)
|
||||
{
|
||||
var currentVals = new DataTypePreValueDto[] { };
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// An internal repository for managing entity containers such as doc type, media type, data type containers
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All we're supporting here is a single get, creating and deleting
|
||||
/// </remarks>
|
||||
internal class EntityContainerRepository : PetaPocoRepositoryBase<int, EntityContainer>
|
||||
{
|
||||
private readonly Guid _containerObjectType;
|
||||
private readonly Guid _entityObjectType;
|
||||
|
||||
public EntityContainerRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax,
|
||||
Guid containerObjectType, Guid entityObjectType)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
_containerObjectType = containerObjectType;
|
||||
_entityObjectType = entityObjectType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do not cache anything
|
||||
/// </summary>
|
||||
protected override IRuntimeCacheProvider RuntimeCache
|
||||
{
|
||||
get { return new NullCacheProvider(); }
|
||||
}
|
||||
|
||||
protected override EntityContainer PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id, NodeObjectType = _containerObjectType });
|
||||
|
||||
var containerDto = Database.Fetch<NodeDto>(sql).FirstOrDefault();
|
||||
if (containerDto == null)
|
||||
return null;
|
||||
|
||||
var entity = new EntityContainer(containerDto.NodeId,
|
||||
containerDto.ParentId, containerDto.Text, containerDto.UserId ?? 0,
|
||||
containerDto.Path);
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
entity.ResetDirtyProperties(false);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected override IEnumerable<EntityContainer> PerformGetAll(params int[] ids)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override IEnumerable<EntityContainer> PerformGetByQuery(IQuery<EntityContainer> query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
if (isCount)
|
||||
{
|
||||
sql.Select("COUNT(*)").From<NodeDto>(SqlSyntax);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.Select("*").From<NodeDto>(SqlSyntax);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
return "umbracoNode.id = @Id and nodeObjectType = @NodeObjectType";
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return _containerObjectType; }
|
||||
}
|
||||
|
||||
protected override void PersistDeletedItem(EntityContainer entity)
|
||||
{
|
||||
var exists = Database.FirstOrDefault<NodeDto>(
|
||||
new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.NodeId == entity.Id && dto.NodeObjectType == _containerObjectType));
|
||||
|
||||
if (exists == null) return;
|
||||
|
||||
//We need to move the content types and folders that exist under this folder to it's parent folder
|
||||
var children = Database.Fetch<NodeDto>(
|
||||
new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where("parentID=@parentID AND (nodeObjectType=@entityObjectType OR nodeObjectType=@containerObjectType)",
|
||||
new {parentID = entity.Id, entityObjectType = _entityObjectType, containerObjectType = _containerObjectType}));
|
||||
|
||||
foreach (var childDto in children)
|
||||
{
|
||||
childDto.ParentId = exists.ParentId;
|
||||
Database.Update(childDto);
|
||||
}
|
||||
|
||||
//now that everything is moved up a level, we need to delete the container
|
||||
Database.Delete(exists);
|
||||
}
|
||||
|
||||
protected override void PersistNewItem(EntityContainer entity)
|
||||
{
|
||||
entity.Name = entity.Name.Trim();
|
||||
|
||||
Mandate.ParameterNotNullOrEmpty(entity.Name, "entity.Name");
|
||||
|
||||
var exists = Database.FirstOrDefault<NodeDto>(
|
||||
new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.ParentId == entity.ParentId && dto.Text == entity.Name && dto.NodeObjectType == _containerObjectType));
|
||||
|
||||
if (exists != null)
|
||||
{
|
||||
throw new InvalidOperationException("A folder with the same name already exists");
|
||||
}
|
||||
|
||||
var level = 0;
|
||||
var path = "-1";
|
||||
if (entity.ParentId > -1)
|
||||
{
|
||||
var parent = Database.FirstOrDefault<NodeDto>(
|
||||
new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.NodeId == entity.ParentId && dto.NodeObjectType == _containerObjectType));
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
throw new NullReferenceException("No content type container found with parent id " + entity.ParentId);
|
||||
}
|
||||
level = parent.Level;
|
||||
path = parent.Path;
|
||||
}
|
||||
|
||||
var nodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = DateTime.Now,
|
||||
Level = Convert.ToInt16(level + 1),
|
||||
NodeObjectType = _containerObjectType,
|
||||
ParentId = entity.ParentId,
|
||||
Path = path,
|
||||
SortOrder = 0,
|
||||
Text = entity.Name,
|
||||
Trashed = false,
|
||||
UniqueId = Guid.NewGuid(),
|
||||
UserId = entity.CreatorId
|
||||
};
|
||||
|
||||
var id = Convert.ToInt32(Database.Insert(nodeDto));
|
||||
|
||||
//update the path
|
||||
nodeDto.Path = nodeDto.Path + "," + nodeDto.NodeId;
|
||||
Database.Save(nodeDto);
|
||||
|
||||
entity.Id = id;
|
||||
entity.Path = nodeDto.Path;
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(EntityContainer entity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
((TracksChangesEntityBase)entity).ResetDirtyProperties(false);
|
||||
entity.ResetDirtyProperties(false);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
@@ -20,6 +21,21 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllPropertyTypeAliases();
|
||||
|
||||
Attempt<int> CreateFolder(int parentId, string name, int userId);
|
||||
/// <summary>
|
||||
/// Creates a folder for content types
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
EntityContainer CreateContainer(int parentId, string name, int userId);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a folder - this will move all contained content types into their parent
|
||||
/// </summary>
|
||||
/// <param name="containerId"></param>
|
||||
void DeleteContainer(int containerId);
|
||||
|
||||
IEnumerable<MoveEventInfo<IContentType>> Move(IContentType toMove, int parentId);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -6,10 +7,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IDataTypeDefinitionRepository : IRepositoryQueryable<int, IDataTypeDefinition>
|
||||
{
|
||||
EntityContainer CreateContainer(int parentId, string name, int userId);
|
||||
void DeleteContainer(int containerId);
|
||||
|
||||
PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId);
|
||||
string GetPreValueAsString(int preValueId);
|
||||
|
||||
void AddOrUpdatePreValues(IDataTypeDefinition dataType, IDictionary<string, PreValue> values);
|
||||
void AddOrUpdatePreValues(int dataTypeId, IDictionary<string, PreValue> values);
|
||||
IEnumerable<MoveEventInfo<IDataTypeDefinition>> Move(IDataTypeDefinition toMove, int parentId);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
@@ -13,5 +14,22 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="query"></param>
|
||||
/// <returns>An enumerable list of <see cref="IContentType"/> objects</returns>
|
||||
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a folder for content types
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
EntityContainer CreateContainer(int parentId, string name, int userId);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a folder - this will move all contained content types into their parent
|
||||
/// </summary>
|
||||
/// <param name="folderId"></param>
|
||||
void DeleteContainer(int folderId);
|
||||
|
||||
IEnumerable<MoveEventInfo<IMediaType>> Move(IMediaType toMove, int parentId);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -10,6 +12,7 @@ using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
@@ -20,12 +23,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
|
||||
public MediaTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax, new Guid(Constants.ObjectTypes.MediaTypeContainer))
|
||||
{
|
||||
}
|
||||
|
||||
#region Overrides of RepositoryBase<int,IMedia>
|
||||
|
||||
|
||||
protected override IMediaType PerformGet(int id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
|
||||
@@ -43,7 +44,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
|
||||
}
|
||||
@@ -54,17 +55,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IMediaType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text);
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
/// </summary>
|
||||
@@ -76,17 +74,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return ints.Any()
|
||||
? GetAll(ints)
|
||||
: Enumerable.Empty<IMediaType>();
|
||||
}
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<int,IMedia>
|
||||
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(isCount ? "COUNT(*)" : "*")
|
||||
.From<ContentTypeDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.From<ContentTypeDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentTypeDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
return sql;
|
||||
}
|
||||
@@ -119,11 +115,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.MediaType); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit of Work Implementation
|
||||
|
||||
|
||||
protected override void PersistNewItem(IMediaType entity)
|
||||
{
|
||||
((MediaType)entity).AddingEntity();
|
||||
@@ -163,16 +155,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The container object type - used for organizing content types
|
||||
/// </summary>
|
||||
protected override Guid ContainerObjectTypeId
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(Guid id)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId);
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
@@ -240,15 +240,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The container object type - used for organizing content types
|
||||
/// </summary>
|
||||
protected override Guid ContainerObjectTypeId
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Override so we can specify explicit db type's on any property types that are built-in.
|
||||
/// </summary>
|
||||
|
||||
@@ -41,6 +41,66 @@ namespace Umbraco.Core.Services
|
||||
_mediaService = mediaService;
|
||||
}
|
||||
|
||||
public Attempt<int> CreateContentTypeContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
var container = repo.CreateContainer(parentId, name, userId);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<int> CreateMediaTypeContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateMediaTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
var container = repo.CreateContainer(parentId, name, userId);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteContentTypeContainer(int folderId, int userId = 0)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
repo.DeleteContainer(folderId);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMediaTypeContainer(int folderId, int userId = 0)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateMediaTypeRepository(uow))
|
||||
{
|
||||
repo.DeleteContainer(folderId);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all property type aliases.
|
||||
/// </summary>
|
||||
@@ -652,6 +712,76 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int parentId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (MovingMediaType.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, parentId)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(
|
||||
MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMediaType>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
moveInfo.AddRange(repository.Move(toMove, parentId));
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
MovedMediaType.RaiseEvent(new MoveEventArgs<IMediaType>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
return Attempt.Succeed(
|
||||
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int parentId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (MovingContentType.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IContentType>(evtMsgs, new MoveEventInfo<IContentType>(toMove, toMove.Path, parentId)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(
|
||||
MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContentType>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
moveInfo.AddRange(repository.Move(toMove, parentId));
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
MovedContentType.RaiseEvent(new MoveEventArgs<IContentType>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
return Attempt.Succeed(
|
||||
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
@@ -890,6 +1020,26 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavedMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Move
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, MoveEventArgs<IMediaType>> MovingMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Move
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, MoveEventArgs<IMediaType>> MovedMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Move
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, MoveEventArgs<IContentType>> MovingContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Move
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, MoveEventArgs<IContentType>> MovedContentType;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,7 @@ namespace Umbraco.Core.Services
|
||||
: base(provider, repositoryFactory, logger, eventMessagesFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public Attempt<int> CreateFolder(int parentId, string name, int userId = 0)
|
||||
{
|
||||
using (var repo = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repo.CreateFolder(parentId, name, userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is called after an content type is saved and is used to update the content xml structures in the database
|
||||
/// if they are required to be updated.
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -26,6 +27,36 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
}
|
||||
|
||||
public Attempt<int> CreateContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
var container = repo.CreateContainer(parentId, name, userId);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
|
||||
{
|
||||
repo.DeleteContainer(containerId);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IDataTypeDefinition"/> by its Name
|
||||
/// </summary>
|
||||
@@ -153,6 +184,41 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> Move(IDataTypeDefinition toMove, int parentId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (Moving.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IDataTypeDefinition>(evtMsgs, new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(
|
||||
MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IDataTypeDefinition>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
moveInfo.AddRange(repository.Move(toMove, parentId));
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(
|
||||
new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Moved.RaiseEvent(new MoveEventArgs<IDataTypeDefinition>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
return Attempt.Succeed(
|
||||
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves an <see cref="IDataTypeDefinition"/>
|
||||
/// </summary>
|
||||
@@ -401,8 +467,18 @@ namespace Umbraco.Core.Services
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IDataTypeService, SaveEventArgs<IDataTypeDefinition>> Saved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Move
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IDataTypeService, MoveEventArgs<IDataTypeDefinition>> Moving;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Move
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IDataTypeService, MoveEventArgs<IDataTypeDefinition>> Moved;
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -17,7 +18,10 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
Attempt<string[]> ValidateComposition(IContentTypeComposition compo);
|
||||
|
||||
Attempt<int> CreateFolder(int parentId, string name, int userId = 0);
|
||||
Attempt<int> CreateContentTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<int> CreateMediaTypeContainer(int parentId, string name, int userId = 0);
|
||||
void DeleteMediaTypeContainer(int folderId, int userId = 0);
|
||||
void DeleteContentTypeContainer(int folderId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all property type aliases.
|
||||
@@ -258,5 +262,8 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="id">Id of the <see cref="IMediaType"/></param>
|
||||
/// <returns>True if the media type has any children otherwise False</returns>
|
||||
bool MediaTypeHasChildren(Guid id);
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int parentId);
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int parentId);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IDataTypeService : IService
|
||||
{
|
||||
Attempt<int> CreateContainer(int parentId, string name, int userId = 0);
|
||||
void DeleteContainer(int containerId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IDataTypeDefinition"/> by its Name
|
||||
/// </summary>
|
||||
@@ -151,5 +154,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="id">Id of the PreValue to retrieve the value from</param>
|
||||
/// <returns>PreValue as a string</returns>
|
||||
string GetPreValueAsString(int id);
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> Move(IDataTypeDefinition toMove, int parentId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A status type of the result of moving an item
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Anything less than 10 = Success!
|
||||
/// </remarks>
|
||||
public enum MoveOperationStatusType
|
||||
{
|
||||
/// <summary>
|
||||
/// The move was successful.
|
||||
/// </summary>
|
||||
Success = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The parent being moved to doesn't exist
|
||||
/// </summary>
|
||||
FailedParentNotFound = 13,
|
||||
|
||||
/// <summary>
|
||||
/// The move action has been cancelled by an event handler
|
||||
/// </summary>
|
||||
FailedCancelledByEvent = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Trying to move an item to an invalid path (i.e. a child of itself)
|
||||
/// </summary>
|
||||
FailedNotAllowedByPath = 15,
|
||||
}
|
||||
}
|
||||
@@ -336,6 +336,7 @@
|
||||
<Compile Include="Events\RollbackEventArgs.cs" />
|
||||
<Compile Include="Events\SaveEventArgs.cs" />
|
||||
<Compile Include="Events\SendToPublishEventArgs.cs" />
|
||||
<Compile Include="Exceptions\DataOperationException.cs" />
|
||||
<Compile Include="Exceptions\InvalidCompositionException.cs" />
|
||||
<Compile Include="Exceptions\UmbracoStartupFailedException.cs" />
|
||||
<Compile Include="FileResources\Files.Designer.cs">
|
||||
@@ -357,6 +358,7 @@
|
||||
<Compile Include="Manifest\GridEditorConverter.cs" />
|
||||
<Compile Include="Models\AuditItem.cs" />
|
||||
<Compile Include="Models\AuditType.cs" />
|
||||
<Compile Include="Models\EntityContainer.cs" />
|
||||
<Compile Include="Models\Identity\IdentityModelMappings.cs" />
|
||||
<Compile Include="Models\Identity\IdentityUser.cs" />
|
||||
<Compile Include="Models\Identity\IdentityUserClaim.cs" />
|
||||
@@ -444,6 +446,7 @@
|
||||
<Compile Include="Persistence\RecordPersistenceType.cs" />
|
||||
<Compile Include="Persistence\Relators\AccessRulesRelator.cs" />
|
||||
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\EntityContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DeepCloneRuntimeCacheProvider.cs" />
|
||||
<Compile Include="Persistence\Repositories\DomainRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ExternalLoginRepository.cs" />
|
||||
@@ -497,6 +500,7 @@
|
||||
<Compile Include="Services\ITaskService.cs" />
|
||||
<Compile Include="Services\LocalizedTextServiceSupplementaryFileSource.cs" />
|
||||
<Compile Include="Services\MigrationEntryService.cs" />
|
||||
<Compile Include="Services\MoveOperationStatusType.cs" />
|
||||
<Compile Include="Services\PublicAccessService.cs" />
|
||||
<Compile Include="Services\PublicAccessServiceExtensions.cs" />
|
||||
<Compile Include="Services\RepositoryService.cs" />
|
||||
|
||||
@@ -95,6 +95,151 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Move()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var container2 = repository.CreateContainer(container.Id, "blah2", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var contentType = (IContentType) MockedContentTypes.CreateBasicContentType("asdfasdf");
|
||||
contentType.ParentId = container2.Id;
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//create a
|
||||
var contentType2 = (IContentType)new ContentType(contentType, "hello")
|
||||
{
|
||||
Name = "Blahasdfsadf"
|
||||
};
|
||||
contentType.ParentId = contentType.Id;
|
||||
repository.AddOrUpdate(contentType2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var result = repository.Move(contentType, container.Id).ToArray();
|
||||
unitOfWork.Commit();
|
||||
|
||||
Assert.AreEqual(2, result.Count());
|
||||
|
||||
//re-get
|
||||
contentType = repository.Get(contentType.Id);
|
||||
contentType2 = repository.Get(contentType2.Id);
|
||||
|
||||
Assert.AreEqual(container.Id, contentType.ParentId);
|
||||
Assert.AreNotEqual(result.Single(x => x.Entity.Id == contentType.Id).OriginalPath, contentType.Path);
|
||||
Assert.AreNotEqual(result.Single(x => x.Entity.Id == contentType2.Id).OriginalPath, contentType2.Path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
Assert.That(container.Id, Is.GreaterThan(0));
|
||||
}
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.DocumentTypeContainer), new Guid(Constants.ObjectTypes.DocumentType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNotNull(found);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
// Act
|
||||
repository.DeleteContainer(container.Id);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.DocumentTypeContainer), new Guid(Constants.ObjectTypes.DocumentType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNull(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container_Containing_Media_Types()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup");
|
||||
contentType.ParentId = container.Id;
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
Assert.AreEqual(container.Id, contentType.ParentId);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container_Containing_Media_Types()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
IContentType contentType;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
contentType = MockedContentTypes.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup");
|
||||
contentType.ParentId = container.Id;
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
// Act
|
||||
repository.DeleteContainer(container.Id);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.DocumentTypeContainer), new Guid(Constants.ObjectTypes.DocumentType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNull(found);
|
||||
}
|
||||
|
||||
contentType = repository.Get(contentType.Id);
|
||||
Assert.IsNotNull(contentType);
|
||||
Assert.AreEqual(-1, contentType.ParentId);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Add_On_ContentTypeRepository()
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
@@ -58,6 +59,150 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.AreEqual(outcome, Regex.IsMatch(cacheKey, DataTypeDefinitionRepository.GetCacheKeyRegex(preValueId)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Move()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var container2 = repository.CreateContainer(container.Id, "blah2", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var dataType = (IDataTypeDefinition) new DataTypeDefinition(container2.Id, Constants.PropertyEditors.RadioButtonListAlias)
|
||||
{
|
||||
Name = "dt1"
|
||||
};
|
||||
repository.AddOrUpdate(dataType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//create a
|
||||
var dataType2 = (IDataTypeDefinition)new DataTypeDefinition(dataType.Id, Constants.PropertyEditors.RadioButtonListAlias)
|
||||
{
|
||||
Name = "dt2"
|
||||
};
|
||||
repository.AddOrUpdate(dataType2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var result = repository.Move(dataType, container.Id).ToArray();
|
||||
unitOfWork.Commit();
|
||||
|
||||
Assert.AreEqual(2, result.Count());
|
||||
|
||||
//re-get
|
||||
dataType = repository.Get(dataType.Id);
|
||||
dataType2 = repository.Get(dataType2.Id);
|
||||
|
||||
Assert.AreEqual(container.Id, dataType.ParentId);
|
||||
Assert.AreNotEqual(result.Single(x => x.Entity.Id == dataType.Id).OriginalPath, dataType.Path);
|
||||
Assert.AreNotEqual(result.Single(x => x.Entity.Id == dataType2.Id).OriginalPath, dataType2.Path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
Assert.That(container.Id, Is.GreaterThan(0));
|
||||
}
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.DataTypeContainer), new Guid(Constants.ObjectTypes.DataType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNotNull(found);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
// Act
|
||||
repository.DeleteContainer(container.Id);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.DataTypeContainer), new Guid(Constants.ObjectTypes.DataType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNull(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container_Containing_Data_Types()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var dataTypeDefinition = new DataTypeDefinition(container.Id, Constants.PropertyEditors.RadioButtonListAlias) { Name = "test" };
|
||||
repository.AddOrUpdate(dataTypeDefinition);
|
||||
unitOfWork.Commit();
|
||||
|
||||
Assert.AreEqual(container.Id, dataTypeDefinition.ParentId);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container_Containing_Data_Types()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
IDataTypeDefinition dataType;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
dataType = new DataTypeDefinition(container.Id, Constants.PropertyEditors.RadioButtonListAlias) { Name = "test" };
|
||||
repository.AddOrUpdate(dataType);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
// Act
|
||||
repository.DeleteContainer(container.Id);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.DataTypeContainer), new Guid(Constants.ObjectTypes.DataType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNull(found);
|
||||
}
|
||||
|
||||
dataType = repository.Get(dataType.Id);
|
||||
Assert.IsNotNull(dataType);
|
||||
Assert.AreEqual(-1, dataType.ParentId);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create()
|
||||
{
|
||||
@@ -85,39 +230,6 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Create_Duplicate_Name()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var id = 0;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var dataTypeDefinition = new DataTypeDefinition(-1, new Guid(Constants.PropertyEditors.RadioButtonList)) { Name = "test" };
|
||||
repository.AddOrUpdate(dataTypeDefinition);
|
||||
unitOfWork.Commit();
|
||||
id = dataTypeDefinition.Id;
|
||||
Assert.That(id, Is.GreaterThan(0));
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var dataTypeDefinition = repository.Get(id);
|
||||
Assert.IsNotNull(dataTypeDefinition);
|
||||
Assert.AreEqual("test", dataTypeDefinition.Name);
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var dataTypeDefinition = new DataTypeDefinition(-1, new Guid(Constants.PropertyEditors.RadioButtonList)) { Name = "test" };
|
||||
repository.AddOrUpdate(dataTypeDefinition);
|
||||
|
||||
unitOfWork.Commit();
|
||||
Assert.AreNotEqual(0, dataTypeDefinition.Id); // has been saved
|
||||
Assert.AreNotEqual(id, dataTypeDefinition.Id); // as a new one
|
||||
Assert.AreEqual("test (1)", dataTypeDefinition.Name); // with a new name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Get_On_DataTypeDefinitionRepository()
|
||||
|
||||
@@ -31,6 +31,151 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
return new MediaTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Move()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var container2 = repository.CreateContainer(container.Id, "blah2", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var contentType = (IMediaType)MockedContentTypes.CreateVideoMediaType();
|
||||
contentType.ParentId = container2.Id;
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//create a
|
||||
var contentType2 = (IMediaType)new MediaType(contentType, "hello")
|
||||
{
|
||||
Name = "Blahasdfsadf"
|
||||
};
|
||||
contentType.ParentId = contentType.Id;
|
||||
repository.AddOrUpdate(contentType2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var result = repository.Move(contentType, container.Id).ToArray();
|
||||
unitOfWork.Commit();
|
||||
|
||||
Assert.AreEqual(2, result.Count());
|
||||
|
||||
//re-get
|
||||
contentType = repository.Get(contentType.Id);
|
||||
contentType2 = repository.Get(contentType2.Id);
|
||||
|
||||
Assert.AreEqual(container.Id, contentType.ParentId);
|
||||
Assert.AreNotEqual(result.Single(x => x.Entity.Id == contentType.Id).OriginalPath, contentType.Path);
|
||||
Assert.AreNotEqual(result.Single(x => x.Entity.Id == contentType2.Id).OriginalPath, contentType2.Path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
Assert.That(container.Id, Is.GreaterThan(0));
|
||||
}
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.MediaTypeContainer), new Guid(Constants.ObjectTypes.MediaType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNotNull(found);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
// Act
|
||||
repository.DeleteContainer(container.Id);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.MediaTypeContainer), new Guid(Constants.ObjectTypes.MediaType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNull(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container_Containing_Media_Types()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var contentType = MockedContentTypes.CreateVideoMediaType();
|
||||
contentType.ParentId = container.Id;
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
Assert.AreEqual(container.Id, contentType.ParentId);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container_Containing_Media_Types()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container;
|
||||
IMediaType contentType;
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
container = repository.CreateContainer(-1, "blah", 0);
|
||||
unitOfWork.Commit();
|
||||
|
||||
contentType = MockedContentTypes.CreateVideoMediaType();
|
||||
contentType.ParentId = container.Id;
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
// Act
|
||||
repository.DeleteContainer(container.Id);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var entityRepo = new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax,
|
||||
new Guid(Constants.ObjectTypes.MediaTypeContainer), new Guid(Constants.ObjectTypes.MediaType)))
|
||||
{
|
||||
var found = entityRepo.Get(container.Id);
|
||||
Assert.IsNull(found);
|
||||
}
|
||||
|
||||
contentType = repository.Get(contentType.Id);
|
||||
Assert.IsNotNull(contentType);
|
||||
Assert.AreEqual(-1, contentType.ParentId);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Add_On_MediaTypeRepository()
|
||||
{
|
||||
|
||||
@@ -109,7 +109,7 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentTypeApiBaseUrl",
|
||||
"DeleteContainerById",
|
||||
"DeleteContainer",
|
||||
[{ id: id }])),
|
||||
'Failed to delete content type contaier');
|
||||
},
|
||||
@@ -166,14 +166,57 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
'Failed to save data for content type id ' + contentType.id);
|
||||
},
|
||||
|
||||
createFolder: function(parentId, name) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.contentTypeResource#move
|
||||
* @methodOf umbraco.resources.contentTypeResource
|
||||
*
|
||||
* @description
|
||||
* Moves a node underneath a new parentId
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* contentTypeResource.move({ parentId: 1244, id: 123 })
|
||||
* .then(function() {
|
||||
* alert("node was moved");
|
||||
* }, function(err){
|
||||
* alert("node didnt move:" + err.data.Message);
|
||||
* });
|
||||
* </pre>
|
||||
* @param {Object} args arguments object
|
||||
* @param {Int} args.idd the ID of the node to move
|
||||
* @param {Int} args.parentId the ID of the parent node to move to
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
move: function (args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.parentId) {
|
||||
throw "args.parentId cannot be null";
|
||||
}
|
||||
if (!args.id) {
|
||||
throw "args.id cannot be null";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateFolder", { parentId: parentId, name: name })),
|
||||
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostMove"),
|
||||
{
|
||||
parentId: args.parentId,
|
||||
id: args.id
|
||||
}),
|
||||
'Failed to move content');
|
||||
},
|
||||
|
||||
createContainer: function(parentId, name) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateContainer", { parentId: parentId, name: name })),
|
||||
'Failed to create a folder under parent id ' + parentId);
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.resources').factory('contentTypeResource', contentTypeResource);
|
||||
|
||||
@@ -181,13 +181,13 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the data type scaffold.
|
||||
*
|
||||
*/
|
||||
getScaffold: function () {
|
||||
getScaffold: function (parentId) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"GetEmpty")),
|
||||
"GetEmpty", { parentId: parentId })),
|
||||
"Failed to retrieve data for empty datatype");
|
||||
},
|
||||
/**
|
||||
@@ -220,6 +220,17 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"Failed to delete item " + id);
|
||||
},
|
||||
|
||||
deleteContainerById: function (id) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"DeleteContainer",
|
||||
[{ id: id }])),
|
||||
'Failed to delete content type contaier');
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -303,6 +314,60 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("dataTypeApiBaseUrl", "PostSave"), saveModel),
|
||||
"Failed to save data for data type id " + dataType.id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.dataTypeResource#move
|
||||
* @methodOf umbraco.resources.dataTypeResource
|
||||
*
|
||||
* @description
|
||||
* Moves a node underneath a new parentId
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* dataTypeResource.move({ parentId: 1244, id: 123 })
|
||||
* .then(function() {
|
||||
* alert("node was moved");
|
||||
* }, function(err){
|
||||
* alert("node didnt move:" + err.data.Message);
|
||||
* });
|
||||
* </pre>
|
||||
* @param {Object} args arguments object
|
||||
* @param {Int} args.idd the ID of the node to move
|
||||
* @param {Int} args.parentId the ID of the parent node to move to
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
move: function (args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.parentId) {
|
||||
throw "args.parentId cannot be null";
|
||||
}
|
||||
if (!args.id) {
|
||||
throw "args.id cannot be null";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("dataTypeApiBaseUrl", "PostMove"),
|
||||
{
|
||||
parentId: args.parentId,
|
||||
id: args.id
|
||||
}),
|
||||
'Failed to move content');
|
||||
},
|
||||
|
||||
createContainer: function (parentId, name) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"PostCreateContainer",
|
||||
{ parentId: parentId, name: name })),
|
||||
'Failed to create a folder under parent id ' + parentId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -79,6 +79,17 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
'Failed to retrieve content type');
|
||||
},
|
||||
|
||||
deleteContainerById: function (id) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"mediaTypeApiBaseUrl",
|
||||
"DeleteContainer",
|
||||
[{ id: id }])),
|
||||
'Failed to delete content type contaier');
|
||||
},
|
||||
|
||||
save: function (contentType) {
|
||||
|
||||
var saveModel = umbDataFormatter.formatContentTypePostData(contentType);
|
||||
@@ -88,13 +99,56 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
'Failed to save data for content type id ' + contentType.id);
|
||||
},
|
||||
|
||||
createFolder: function(parentId, name) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.mediaTypeResource#move
|
||||
* @methodOf umbraco.resources.mediaTypeResource
|
||||
*
|
||||
* @description
|
||||
* Moves a node underneath a new parentId
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaTypeResource.move({ parentId: 1244, id: 123 })
|
||||
* .then(function() {
|
||||
* alert("node was moved");
|
||||
* }, function(err){
|
||||
* alert("node didnt move:" + err.data.Message);
|
||||
* });
|
||||
* </pre>
|
||||
* @param {Object} args arguments object
|
||||
* @param {Int} args.idd the ID of the node to move
|
||||
* @param {Int} args.parentId the ID of the parent node to move to
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
move: function (args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.parentId) {
|
||||
throw "args.parentId cannot be null";
|
||||
}
|
||||
if (!args.id) {
|
||||
throw "args.id cannot be null";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("mediaTypeApiBaseUrl", "PostMove"),
|
||||
{
|
||||
parentId: args.parentId,
|
||||
id: args.id
|
||||
}),
|
||||
'Failed to move content');
|
||||
},
|
||||
|
||||
createContainer: function(parentId, name) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"mediaTypeApiBaseUrl",
|
||||
"PostCreateFolder",
|
||||
"PostCreateContainer",
|
||||
{ parentId: parentId, name: name })),
|
||||
'Failed to create a folder under parent id ' + parentId);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
* @param {String} source The URL to load into the iframe
|
||||
*/
|
||||
loadLegacyIFrame: function (source) {
|
||||
$location.path("/" + appState.getSectionState("currentSection") + "/framed/" + encodeURIComponent(source));
|
||||
$location.path("/" + appState.getSectionState("currentSection").toLowerCase() + "/framed/" + encodeURIComponent(source));
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -132,7 +132,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
appState.setSectionState("currentSection", sectionAlias);
|
||||
this.showTree(sectionAlias);
|
||||
|
||||
$location.path(sectionAlias);
|
||||
$location.path(sectionAlias.toLowerCase());
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -250,10 +250,10 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
appState.setMenuState("currentNode", args.node);
|
||||
|
||||
//not legacy, lets just set the route value and clear the query string if there is one.
|
||||
$location.path(n.routePath).search("");
|
||||
$location.path(n.routePath.toLowerCase()).search("");
|
||||
}
|
||||
else if (args.element.section) {
|
||||
$location.path(args.element.section).search("");
|
||||
$location.path(args.element.section.toLowerCase()).search("");
|
||||
}
|
||||
|
||||
service.hideNavigation();
|
||||
@@ -446,7 +446,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
if (action.metaData && action.metaData["actionRoute"] && angular.isString(action.metaData["actionRoute"])) {
|
||||
//first check if the menu item simply navigates to a route
|
||||
var parts = action.metaData["actionRoute"].split("?");
|
||||
$location.path(parts[0]).search(parts.length > 1 ? parts[1] : "");
|
||||
$location.path(parts[0].toLowerCase()).search(parts.length > 1 ? parts[1] : "");
|
||||
this.hideNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -537,7 +537,7 @@ function umbDataFormatter() {
|
||||
/** formats the display model used to display the data type to the model used to save the data type */
|
||||
formatDataTypePostData: function(displayModel, preValues, action) {
|
||||
var saveModel = {
|
||||
parentId: -1,
|
||||
parentId: displayModel.parentId,
|
||||
id: displayModel.id,
|
||||
name: displayModel.name,
|
||||
selectedEditor: displayModel.selectedEditor,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="umb-pane">
|
||||
|
||||
<p class="abstract" ng-hide="success">
|
||||
Choose where to move <strong>{{currentNode.name}}</strong> to in the tree structure below
|
||||
Choose where to move <strong>{{currentNode.name}}</strong> to in the tree structure below
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
|
||||
<div ng-show="success">
|
||||
<h5 class="text-success"><strong>{{currentNode.name}}</strong> was moved underneath<strong>{{target.name}}</strong></h5>
|
||||
<h5 class="text-success"><strong>{{currentNode.name}}</strong> was moved underneath <strong>{{target.name}}</strong></h5>
|
||||
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.DataType.CreateController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the data type creation dialog
|
||||
*/
|
||||
function DataTypeCreateController($scope, $location, navigationService, dataTypeResource, formHelper, appState) {
|
||||
|
||||
$scope.model = {
|
||||
folderName: "",
|
||||
creatingFolder: false
|
||||
};
|
||||
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
|
||||
$scope.showCreateFolder = function() {
|
||||
$scope.model.creatingFolder = true;
|
||||
}
|
||||
|
||||
$scope.createContainer = function () {
|
||||
if (formHelper.submitForm({ scope: $scope, formCtrl: this.createFolderForm, statusMessage: "Creating folder..." })) {
|
||||
dataTypeResource.createContainer(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
var currPath = node.path ? node.path : "-1";
|
||||
navigationService.syncTree({ tree: "datatypes", path: currPath + "," + folderId, forceReload: true, activate: true });
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
//TODO: Handle errors
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
$scope.createDataType = function() {
|
||||
$location.search('create', null);
|
||||
$location.path("/developer/datatypes/edit/" + node.id).search("create", "true");
|
||||
navigationService.hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('umbraco').controller("Umbraco.Editors.DataType.CreateController", DataTypeCreateController);
|
||||
@@ -0,0 +1,50 @@
|
||||
<div class="umbracoDialog umb-dialog-body with-footer" ng-controller="Umbraco.Editors.DataType.CreateController">
|
||||
|
||||
<div class="umb-pane" ng-if="!model.creatingFolder">
|
||||
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li>
|
||||
<a href="" ng-click="createDataType()">
|
||||
|
||||
<i class="large icon-autofill"></i>
|
||||
|
||||
<span class="menu-label">
|
||||
<localize key="general_new">New</localize> Data type
|
||||
</span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="showCreateFolder()">
|
||||
|
||||
<i class="large icon-folder"></i>
|
||||
|
||||
<span class="menu-label">
|
||||
Folder
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="umb-pane" ng-if="model.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="createContainer()"
|
||||
val-form-manager>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
<input type="text" name="folderName" ng-model="model.folderName" class="umb-textstring textstring input-block-level" required />
|
||||
</umb-control-group>
|
||||
|
||||
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-if="!model.creatingFolder">
|
||||
<button class="btn" ng-click="nav.hideDialog(true)">
|
||||
<localize key="buttons_somethingElse">Do something else</localize>
|
||||
</button>
|
||||
</div>
|
||||
@@ -25,6 +25,23 @@ function DataTypeDeleteController($scope, dataTypeResource, treeService, navigat
|
||||
|
||||
};
|
||||
|
||||
$scope.performContainerDelete = function () {
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
dataTypeResource.deleteContainerById($scope.currentNode.id).then(function () {
|
||||
$scope.currentNode.loading = false;
|
||||
|
||||
//get the root node before we remove it
|
||||
var rootNode = treeService.getTreeRoot($scope.currentNode);
|
||||
|
||||
//TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
$scope.page.loading = true;
|
||||
|
||||
//we are creating so get an empty data type item
|
||||
dataTypeResource.getScaffold()
|
||||
dataTypeResource.getScaffold($routeParams.id)
|
||||
.then(function(data) {
|
||||
|
||||
$scope.preValuesLoaded = true;
|
||||
@@ -91,7 +91,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
// if there are any and then clear them so the collection no longer persists them.
|
||||
serverValidationManager.executeAndClearAllSubscriptions();
|
||||
|
||||
navigationService.syncTree({ tree: "datatypes", path: [String(data.id)] }).then(function (syncArgs) {
|
||||
navigationService.syncTree({ tree: "datatypes", path: data.path }).then(function (syncArgs) {
|
||||
$scope.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
@@ -152,7 +152,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
//share state
|
||||
editorState.set($scope.content);
|
||||
|
||||
navigationService.syncTree({ tree: "datatypes", path: [String(data.id)], forceReload: true }).then(function (syncArgs) {
|
||||
navigationService.syncTree({ tree: "datatypes", path: data.path, forceReload: true }).then(function (syncArgs) {
|
||||
$scope.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
|
||||
@@ -2,11 +2,33 @@
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<p class="umb-abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
<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>
|
||||
<ng-switch on="currentNode.nodeType">
|
||||
<div ng-switch-when="container">
|
||||
<umb-confirm on-confirm="performContainerDelete"
|
||||
on-cancel="cancel">
|
||||
</umb-confirm>
|
||||
</div>
|
||||
|
||||
<div ng-switch-default>
|
||||
<p>
|
||||
<i class="icon-alert red"></i> <strong class="red">All property types & property data</strong>
|
||||
using this data type will be deleted permanently, please confirm you want to delete these as well.
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" ng-model="confirmed" />
|
||||
Yes, delete {{currentNode.name}} and all property types & property data using this data type
|
||||
</label>
|
||||
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel">
|
||||
</umb-confirm>
|
||||
</div>
|
||||
</ng-switch>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.DataType.MoveController",
|
||||
function ($scope, dataTypeResource, treeService, navigationService, notificationsService, appState) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
|
||||
function nodeSelectHandler(ev, args) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
}
|
||||
|
||||
$scope.move = function () {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.error = false;
|
||||
|
||||
dataTypeResource.move({ parentId: $scope.target.id, id: dialogOptions.currentNode.id })
|
||||
.then(function (path) {
|
||||
$scope.error = false;
|
||||
$scope.success = true;
|
||||
$scope.busy = false;
|
||||
|
||||
//first we need to remove the node that launched the dialog
|
||||
treeService.removeNode($scope.currentNode);
|
||||
|
||||
//get the currently edited node (if any)
|
||||
var activeNode = appState.getTreeState("selectedNode");
|
||||
|
||||
//we need to do a double sync here: first sync to the moved content - but don't activate the node,
|
||||
//then sync to the currenlty edited content (note: this might not be the content that was moved!!)
|
||||
|
||||
navigationService.syncTree({ tree: "dataTypes", path: path, forceReload: true, activate: false }).then(function (args) {
|
||||
if (activeNode) {
|
||||
var activeNodePath = treeService.getPath(activeNode).join();
|
||||
//sync to this node now - depending on what was copied this might already be synced but might not be
|
||||
navigationService.syncTree({ tree: "dataTypes", path: activeNodePath, forceReload: false, activate: true });
|
||||
}
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.busy = false;
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.DataType.MoveController">
|
||||
|
||||
<div class="umb-dialog-body">
|
||||
<div class="umb-pane">
|
||||
|
||||
<p class="abstract" ng-hide="success">
|
||||
Select the folder to move <strong>{{currentNode.name}}</strong> to in the tree structure below
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<div ng-show="success">
|
||||
<h5 class="text-success"><strong>{{currentNode.name}}</strong> was moved underneath <strong>{{target.name}}</strong></h5>
|
||||
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="success">
|
||||
|
||||
<div>
|
||||
<umb-tree section="developer"
|
||||
treealias="dataTypes"
|
||||
customtreeparams="foldersonly=1"
|
||||
hideheader="false"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
|
||||
<a class="btn btn-link" ng-click="nav.hideDialog()" ng-if="!busy">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
<button class="btn btn-primary" ng-click="move()" ng-disabled="busy">
|
||||
<localize key="actions_move">Move</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -6,11 +6,11 @@
|
||||
* @description
|
||||
* The controller for the doc type creation dialog
|
||||
*/
|
||||
function DocumentTypesCreateController($scope, $location, navigationService, contentTypeResource, formHelper, appState) {
|
||||
function DocumentTypesCreateController($scope, $location, navigationService, contentTypeResource, formHelper, appState, notificationsService) {
|
||||
|
||||
$scope.model = {
|
||||
folderName: "",
|
||||
creatingFolder: false
|
||||
creatingFolder: false,
|
||||
};
|
||||
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
@@ -19,9 +19,9 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
|
||||
$scope.model.creatingFolder = true;
|
||||
}
|
||||
|
||||
$scope.createFolder = function () {
|
||||
$scope.createContainer = function () {
|
||||
if (formHelper.submitForm({ scope: $scope, formCtrl: this.createFolderForm, statusMessage: "Creating folder..." })) {
|
||||
contentTypeResource.createFolder(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
contentTypeResource.createContainer(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
var currPath = node.path ? node.path : "-1";
|
||||
@@ -29,12 +29,18 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
$location.path("/" + section + "/documenttypes/list/" + folderId);
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
//TODO: Handle errors
|
||||
$scope.error = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="umbracoDialog umb-dialog-body with-footer" ng-controller="Umbraco.Editors.DocumentTypes.CreateController">
|
||||
|
||||
<div class="umb-pane" ng-if="!model.creatingFolder">
|
||||
<h5><localize key="create_createUnder">Create a page under</localize> {{currentNode.name}}</h5>
|
||||
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li>
|
||||
@@ -33,8 +33,13 @@
|
||||
|
||||
<div class="umb-pane" ng-if="model.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="createFolder()"
|
||||
ng-submit="createContainer()"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
<input type="text" name="folderName" ng-model="model.folderName" class="umb-textstring textstring input-block-level" required />
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<p class="umb-abstract">
|
||||
Are you sure you want to delete <strong>{{currentNode.name}}</strong> ?
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize>
|
||||
<strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
<ng-switch on="currentNode.nodeType">
|
||||
<div ng-switch-when="container">
|
||||
<p>This action cannot be undone, click ok to delete.</p>
|
||||
|
||||
<umb-confirm
|
||||
on-confirm="performContainerDelete"
|
||||
on-cancel="cancel">
|
||||
|
||||
@@ -1,5 +1,66 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.DocumentTypes.MoveController",
|
||||
function($scope){
|
||||
function ($scope, contentTypeResource, treeService, navigationService, notificationsService, appState) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
|
||||
function nodeSelectHandler(ev, args) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
}
|
||||
|
||||
$scope.move = function () {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.error = false;
|
||||
|
||||
contentTypeResource.move({ parentId: $scope.target.id, id: dialogOptions.currentNode.id })
|
||||
.then(function (path) {
|
||||
$scope.error = false;
|
||||
$scope.success = true;
|
||||
$scope.busy = false;
|
||||
|
||||
//first we need to remove the node that launched the dialog
|
||||
treeService.removeNode($scope.currentNode);
|
||||
|
||||
//get the currently edited node (if any)
|
||||
var activeNode = appState.getTreeState("selectedNode");
|
||||
|
||||
//we need to do a double sync here: first sync to the moved content - but don't activate the node,
|
||||
//then sync to the currenlty edited content (note: this might not be the content that was moved!!)
|
||||
|
||||
navigationService.syncTree({ tree: "documentTypes", path: path, forceReload: true, activate: false }).then(function (args) {
|
||||
if (activeNode) {
|
||||
var activeNodePath = treeService.getPath(activeNode).join();
|
||||
//sync to this node now - depending on what was copied this might already be synced but might not be
|
||||
navigationService.syncTree({ tree: "documentTypes", path: activeNodePath, forceReload: false, activate: true });
|
||||
}
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.busy = false;
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,50 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.DocumentTypes.MoveController">
|
||||
|
||||
<div class="umb-dialog-body">
|
||||
<div class="umb-pane">
|
||||
|
||||
<p class="umb-abstract">
|
||||
Select the folder to move {{currentNode.name}} to.
|
||||
</p>
|
||||
<p class="abstract" ng-hide="success">
|
||||
Select the folder to move <strong>{{currentNode.name}}</strong> to in the tree structure below
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<div ng-show="success">
|
||||
<h5 class="text-success"><strong>{{currentNode.name}}</strong> was moved underneath <strong>{{target.name}}</strong></h5>
|
||||
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="success">
|
||||
|
||||
<div>
|
||||
<umb-tree section="settings"
|
||||
treealias="documentTypes"
|
||||
customtreeparams="foldersonly=1"
|
||||
hideheader="false"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
|
||||
<a class="btn btn-link" ng-click="nav.hideDialog()" ng-if="!busy">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
<button class="btn btn-primary" ng-click="move()" ng-disabled="busy">
|
||||
<localize key="actions_move">Move</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,9 +19,9 @@ function MediaTypesCreateController($scope, $location, navigationService, mediaT
|
||||
$scope.model.creatingFolder = true;
|
||||
}
|
||||
|
||||
$scope.createFolder = function () {
|
||||
$scope.createContainer = function () {
|
||||
if (formHelper.submitForm({ scope: $scope, formCtrl: this.createFolderForm, statusMessage: "Creating folder..." })) {
|
||||
mediaTypeResource.createFolder(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
mediaTypeResource.createContainer(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
var currPath = node.path ? node.path : "-1";
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
<div class="umbracoDialog umb-dialog-body with-footer" ng-controller="Umbraco.Editors.MediaTypes.CreateController">
|
||||
|
||||
<div class="umb-pane" ng-if="!model.creatingFolder">
|
||||
<h5><localize key="create_createUnder">Create a page under</localize> {{currentNode.name}}</h5>
|
||||
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li>
|
||||
<a href="" ng-click="createMediaType()">
|
||||
|
||||
<i class="large icon-item-arrangement"></i>
|
||||
|
||||
<span class="menu-label">
|
||||
<localize key="general_new">New</localize>
|
||||
<localize key="content_mediatype">Media type</localize>
|
||||
</span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="showCreateFolder()">
|
||||
|
||||
@@ -14,24 +26,12 @@
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="createMediaType()">
|
||||
|
||||
<i class="large icon-item-arrangement"></i>
|
||||
|
||||
<span class="menu-label">
|
||||
<localize key="general_new">New</localize>
|
||||
<localize key="content_mediaType">Media type</localize>
|
||||
</span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="umb-pane" ng-if="model.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="createFolder()"
|
||||
ng-submit="createContainer()"
|
||||
val-form-manager>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for the media type delete dialog
|
||||
*/
|
||||
function MediaTypesDeleteController($scope, dataTypeResource, mediaTypeResource, contentTypeResource, treeService, navigationService) {
|
||||
function MediaTypesDeleteController($scope, dataTypeResource, mediaTypeResource, treeService, navigationService) {
|
||||
|
||||
$scope.performDelete = function() {
|
||||
|
||||
@@ -29,7 +29,7 @@ function MediaTypesDeleteController($scope, dataTypeResource, mediaTypeResource,
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
contentTypeResource.deleteContainerById($scope.currentNode.id).then(function () {
|
||||
mediaTypeResource.deleteContainerById($scope.currentNode.id).then(function () {
|
||||
$scope.currentNode.loading = false;
|
||||
|
||||
//get the root node before we remove it
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<p class="umb-abstract">
|
||||
Are you sure you want to delete <strong>{{currentNode.name}}</strong> ?
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
<ng-switch on="currentNode.nodeType">
|
||||
<div ng-switch-when="container">
|
||||
<p>This action cannot be undone, click ok to delete.</p>
|
||||
|
||||
<umb-confirm
|
||||
on-confirm="performContainerDelete"
|
||||
on-cancel="cancel">
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.MediaTypes.MoveController",
|
||||
function($scope){
|
||||
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState) {
|
||||
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
|
||||
function nodeSelectHandler(ev, args) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
}
|
||||
|
||||
$scope.move = function () {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.error = false;
|
||||
|
||||
mediaTypeResource.move({ parentId: $scope.target.id, id: dialogOptions.currentNode.id })
|
||||
.then(function (path) {
|
||||
$scope.error = false;
|
||||
$scope.success = true;
|
||||
$scope.busy = false;
|
||||
|
||||
//first we need to remove the node that launched the dialog
|
||||
treeService.removeNode($scope.currentNode);
|
||||
|
||||
//get the currently edited node (if any)
|
||||
var activeNode = appState.getTreeState("selectedNode");
|
||||
|
||||
//we need to do a double sync here: first sync to the moved content - but don't activate the node,
|
||||
//then sync to the currenlty edited content (note: this might not be the content that was moved!!)
|
||||
|
||||
navigationService.syncTree({ tree: "mediaTypes", path: path, forceReload: true, activate: false }).then(function (args) {
|
||||
if (activeNode) {
|
||||
var activeNodePath = treeService.getPath(activeNode).join();
|
||||
//sync to this node now - depending on what was copied this might already be synced but might not be
|
||||
navigationService.syncTree({ tree: "mediaTypes", path: activeNodePath, forceReload: false, activate: true });
|
||||
}
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.busy = false;
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,51 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.MediaTypes.MoveController">
|
||||
|
||||
|
||||
<div class="umb-dialog-body">
|
||||
<div class="umb-pane">
|
||||
|
||||
<p class="umb-abstract">
|
||||
Select the folder to move {{currentNode.name}} to.
|
||||
</p>
|
||||
<p class="abstract" ng-hide="success">
|
||||
Select the folder to move <strong>{{currentNode.name}}</strong> to in the tree structure below
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<div ng-show="success">
|
||||
<h5 class="text-success"><strong>{{currentNode.name}}</strong> was moved underneath <strong>{{target.name}}</strong></h5>
|
||||
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="success">
|
||||
|
||||
<div>
|
||||
<umb-tree section="settings"
|
||||
treealias="mediaTypes"
|
||||
customtreeparams="foldersonly=1"
|
||||
hideheader="false"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
|
||||
<a class="btn btn-link" ng-click="nav.hideDialog()" ng-if="!busy">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
<button class="btn btn-primary" ng-click="move()" ng-disabled="busy">
|
||||
<localize key="actions_move">Move</localize>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -19,9 +19,9 @@ function MemberTypesCreateController($scope, $location, navigationService, membe
|
||||
$scope.model.creatingFolder = true;
|
||||
}
|
||||
|
||||
$scope.createFolder = function () {
|
||||
$scope.createContainer = function () {
|
||||
if (formHelper.submitForm({ scope: $scope, formCtrl: this.createFolderForm, statusMessage: "Creating folder..." })) {
|
||||
memberTypeResource.createFolder(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
memberTypeResource.createContainer(node.id, $scope.model.folderName).then(function (folderId) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
var currPath = node.path ? node.path : "-1";
|
||||
|
||||
@@ -602,13 +602,9 @@ namespace Umbraco.Web.Editors
|
||||
//cannot move if the content item is not allowed at the root
|
||||
if (toMove.ContentType.AllowedAsRoot == false)
|
||||
{
|
||||
var msg = Services.TextService.Localize("moveOrCopy/notAllowedAtRoot");
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = msg
|
||||
};
|
||||
notificationModel.AddErrorNotification(msg, "");
|
||||
throw new HttpResponseException( Request.CreateValidationErrorResponse(notificationModel));
|
||||
throw new HttpResponseException(
|
||||
Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("moveOrCopy/notAllowedAtRoot")));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -619,31 +615,21 @@ namespace Umbraco.Web.Editors
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//check if the item is allowed under this one
|
||||
if (parent.ContentType.AllowedContentTypes.Select(x => x.Id).ToArray()
|
||||
.Any(x => x.Value == toMove.ContentType.Id) == false)
|
||||
{
|
||||
var msg = Services.TextService.Localize("moveOrCopy/notAllowedByContentType");
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = msg
|
||||
};
|
||||
notificationModel.AddErrorNotification(msg, "");
|
||||
throw new HttpResponseException(Request.CreateValidationErrorResponse(notificationModel));
|
||||
throw new HttpResponseException(
|
||||
Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("moveOrCopy/notAllowedByContentType")));
|
||||
}
|
||||
|
||||
// Check on paths
|
||||
if ((string.Format(",{0},", parent.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1)
|
||||
{
|
||||
var msg = Services.TextService.Localize("moveOrCopy/notAllowedByPath");
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = msg
|
||||
};
|
||||
notificationModel.AddErrorNotification(msg, "");
|
||||
throw new HttpResponseException(Request.CreateValidationErrorResponse(notificationModel));
|
||||
{
|
||||
throw new HttpResponseException(
|
||||
Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("moveOrCopy/notAllowedByPath")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,37 +118,22 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public HttpResponseMessage DeleteContainerById(int id)
|
||||
public HttpResponseMessage DeleteContainer(int id)
|
||||
{
|
||||
//TODO: This needs to be implemented correctly
|
||||
|
||||
var foundType = Services.EntityService.Get(id);
|
||||
if (foundType == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
if (foundType.HasChildren())
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.Forbidden);
|
||||
}
|
||||
|
||||
//TODO: what service to use to delete?
|
||||
Services.ContentTypeService.DeleteContentTypeContainer(id, Security.CurrentUser.Id);
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
public HttpResponseMessage PostCreateFolder(int parentId, string name)
|
||||
|
||||
public HttpResponseMessage PostCreateContainer(int parentId, string name)
|
||||
{
|
||||
var result = Services.ContentTypeService.CreateFolder(parentId, name, Security.CurrentUser.Id);
|
||||
var result = Services.ContentTypeService.CreateContentTypeContainer(parentId, name, Security.CurrentUser.Id);
|
||||
|
||||
return result
|
||||
? Request.CreateResponse(HttpStatusCode.OK, result.Result) //return the id
|
||||
: Request.CreateValidationErrorResponse(result.Exception.Message);
|
||||
: Request.CreateNotificationValidationErrorResponse(result.Exception.Message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ContentTypeDisplay PostSave(ContentTypeSave contentTypeSave)
|
||||
{
|
||||
var savedCt = PerformPostSave<IContentType, ContentTypeDisplay>(
|
||||
@@ -258,6 +243,19 @@ namespace Umbraco.Web.Editors
|
||||
return basics;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the media type
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponseMessage PostMove(MoveOrCopy move)
|
||||
{
|
||||
return PerformMove(
|
||||
move,
|
||||
getContentType: i => Services.ContentTypeService.GetContentType(i),
|
||||
doMove: (type, i) => Services.ContentTypeService.MoveContentType(type, i));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Http;
|
||||
using AutoMapper;
|
||||
@@ -215,6 +216,50 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
return newCt;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the sort order for media
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <param name="getContentType"></param>
|
||||
/// <param name="doMove"></param>
|
||||
/// <returns></returns>
|
||||
protected HttpResponseMessage PerformMove<TContentType>(
|
||||
MoveOrCopy move,
|
||||
Func<int, TContentType> getContentType,
|
||||
Func<TContentType, int, Attempt<OperationStatus<MoveOperationStatusType>>> doMove)
|
||||
where TContentType : IContentTypeComposition
|
||||
{
|
||||
var toMove = getContentType(move.Id);
|
||||
if (toMove == null)
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var result = doMove(toMove, move.ParentId);
|
||||
if (result.Success)
|
||||
{
|
||||
var response = Request.CreateResponse(HttpStatusCode.OK);
|
||||
response.Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json");
|
||||
return response;
|
||||
}
|
||||
|
||||
switch (result.Result.StatusType)
|
||||
{
|
||||
case MoveOperationStatusType.FailedParentNotFound:
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
case MoveOperationStatusType.FailedCancelledByEvent:
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return Request.CreateValidationErrorResponse(new SimpleNotificationModel());
|
||||
case MoveOperationStatusType.FailedNotAllowedByPath:
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedByPath"), "");
|
||||
return Request.CreateValidationErrorResponse(notificationModel);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private ICultureDictionary CultureDictionary
|
||||
|
||||
@@ -19,6 +19,7 @@ using Umbraco.Web.WebApi.Filters;
|
||||
using umbraco;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -80,9 +81,9 @@ namespace Umbraco.Web.Editors
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
public DataTypeDisplay GetEmpty()
|
||||
public DataTypeDisplay GetEmpty(int parentId)
|
||||
{
|
||||
var dt = new DataTypeDefinition("");
|
||||
var dt = new DataTypeDefinition(parentId, "");
|
||||
return Mapper.Map<IDataTypeDefinition, DataTypeDisplay>(dt);
|
||||
}
|
||||
|
||||
@@ -162,7 +163,28 @@ namespace Umbraco.Web.Editors
|
||||
return Mapper.Map<PropertyEditor, IEnumerable<PreValueFieldDisplay>>(propEd);
|
||||
}
|
||||
|
||||
//TODO: Generally there probably won't be file uploads for pre-values but we should allow them just like we do for the content editor
|
||||
/// <summary>
|
||||
/// Deletes a data type container wth a given ID
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public HttpResponseMessage DeleteContainer(int id)
|
||||
{
|
||||
Services.DataTypeService.DeleteContainer(id, Security.CurrentUser.Id);
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
public HttpResponseMessage PostCreateContainer(int parentId, string name)
|
||||
{
|
||||
var result = Services.DataTypeService.CreateContainer(parentId, name, Security.CurrentUser.Id);
|
||||
|
||||
return result
|
||||
? Request.CreateResponse(HttpStatusCode.OK, result.Result) //return the id
|
||||
: Request.CreateNotificationValidationErrorResponse(result.Exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the data type
|
||||
@@ -207,6 +229,44 @@ namespace Umbraco.Web.Editors
|
||||
return display;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the media type
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponseMessage PostMove(MoveOrCopy move)
|
||||
{
|
||||
var toMove = Services.DataTypeService.GetDataTypeDefinitionById(move.Id);
|
||||
if (toMove == null)
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var result = Services.DataTypeService.Move(toMove, move.ParentId);
|
||||
if (result.Success)
|
||||
{
|
||||
var response = Request.CreateResponse(HttpStatusCode.OK);
|
||||
response.Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json");
|
||||
return response;
|
||||
}
|
||||
|
||||
switch (result.Result.StatusType)
|
||||
{
|
||||
case MoveOperationStatusType.FailedParentNotFound:
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
case MoveOperationStatusType.FailedCancelledByEvent:
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return Request.CreateValidationErrorResponse(new SimpleNotificationModel());
|
||||
case MoveOperationStatusType.FailedNotAllowedByPath:
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedByPath"), "");
|
||||
return Request.CreateValidationErrorResponse(notificationModel);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
#region ReadOnly actions to return basic data - allow access for: content ,media, members, settings, developer
|
||||
/// <summary>
|
||||
/// Gets the content json for all data types
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Net;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using Umbraco.Web.WebApi;
|
||||
using ContentType = System.Net.Mime.ContentType;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -82,9 +83,9 @@ namespace Umbraco.Web.Editors
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
public ContentTypeCompositionDisplay GetEmpty()
|
||||
public ContentTypeCompositionDisplay GetEmpty(int parentId)
|
||||
{
|
||||
var ct = new MediaType(-1);
|
||||
var ct = new MediaType(parentId);
|
||||
ct.Icon = "icon-picture";
|
||||
|
||||
var dto = Mapper.Map<IMediaType, ContentTypeCompositionDisplay>(ct);
|
||||
@@ -102,6 +103,29 @@ namespace Umbraco.Web.Editors
|
||||
.Select(Mapper.Map<IMediaType, ContentTypeBasic>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a document type container wth a given ID
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public HttpResponseMessage DeleteContainer(int id)
|
||||
{
|
||||
Services.ContentTypeService.DeleteMediaTypeContainer(id, Security.CurrentUser.Id);
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
public HttpResponseMessage PostCreateContainer(int parentId, string name)
|
||||
{
|
||||
var result = Services.ContentTypeService.CreateMediaTypeContainer(parentId, name, Security.CurrentUser.Id);
|
||||
|
||||
return result
|
||||
? Request.CreateResponse(HttpStatusCode.OK, result.Result) //return the id
|
||||
: Request.CreateNotificationValidationErrorResponse(result.Exception.Message);
|
||||
}
|
||||
|
||||
public ContentTypeCompositionDisplay PostSave(ContentTypeSave contentTypeSave)
|
||||
{
|
||||
var savedCt = PerformPostSave<IMediaType, ContentTypeCompositionDisplay>(
|
||||
@@ -163,5 +187,19 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
return basics;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the media type
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponseMessage PostMove(MoveOrCopy move)
|
||||
{
|
||||
return PerformMove(
|
||||
move,
|
||||
getContentType: i => Services.ContentTypeService.GetMediaType(i),
|
||||
doMove: (type, i) => Services.ContentTypeService.MoveMediaType(type, i));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AutoMapper;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -71,7 +70,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(x => x.Notifications, expression => expression.Ignore())
|
||||
.ForMember(x => x.Icon, expression => expression.Ignore())
|
||||
.ForMember(x => x.Alias, expression => expression.Ignore())
|
||||
.ForMember(x => x.Group, expression => expression.Ignore())
|
||||
.ForMember(x => x.Group, expression => expression.Ignore())
|
||||
.ForMember(x => x.IsSystemDataType, expression => expression.MapFrom(definition => systemIds.Contains(definition.Id)))
|
||||
.AfterMap((def, basic) =>
|
||||
{
|
||||
@@ -99,7 +98,6 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(definition => definition.Key, expression => expression.Ignore())
|
||||
.ForMember(definition => definition.Path, expression => expression.Ignore())
|
||||
.ForMember(definition => definition.PropertyEditorAlias, expression => expression.MapFrom(save => save.SelectedEditor))
|
||||
.ForMember(definition => definition.ParentId, expression => expression.MapFrom(save => -1))
|
||||
.ForMember(definition => definition.DatabaseType, expression => expression.ResolveUsing<DatabaseTypeResolver>())
|
||||
.ForMember(x => x.ControlId, expression => expression.Ignore())
|
||||
.ForMember(x => x.CreatorId, expression => expression.Ignore())
|
||||
|
||||
@@ -15,10 +15,11 @@ using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
[UmbracoTreeAuthorize(Constants.Trees.DataTypes)]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.DocumentTypes)]
|
||||
[Tree(Constants.Applications.Settings, Constants.Trees.DocumentTypes, null, sortOrder: 6)]
|
||||
[Umbraco.Web.Mvc.PluginController("UmbracoTrees")]
|
||||
[Mvc.PluginController("UmbracoTrees")]
|
||||
[CoreTree]
|
||||
[LegacyBaseTree(typeof(loadNodeTypes))]
|
||||
public class ContentTypeTreeController : TreeController
|
||||
{
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
@@ -36,16 +37,24 @@ namespace Umbraco.Web.Trees
|
||||
var node = CreateTreeNode(dt.Id.ToString(), id, queryStrings, dt.Name, "icon-folder", dt.HasChildren(), "");
|
||||
node.Path = dt.Path;
|
||||
node.NodeType = "container";
|
||||
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
node.AdditionalData["jsClickCallback"] = "javascript:void(0);";
|
||||
return node;
|
||||
}));
|
||||
|
||||
//if the request is for folders only then just return
|
||||
if (queryStrings["foldersonly"].IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes;
|
||||
|
||||
nodes.AddRange(
|
||||
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DocumentType)
|
||||
.OrderBy(entity => entity.Name)
|
||||
.Select(dt =>
|
||||
{
|
||||
var node = CreateTreeNode(dt.Id.ToString(), id, queryStrings, dt.Name, "icon-item-arrangement", false);
|
||||
var node = CreateTreeNode(dt.Id.ToString(), id, queryStrings, dt.Name, "icon-item-arrangement",
|
||||
//NOTE: This is legacy now but we need to support upgrades. From 7.4+ we don't allow 'child' creations since
|
||||
// this is an organiational thing and we do that with folders now.
|
||||
dt.HasChildren());
|
||||
|
||||
node.Path = dt.Path;
|
||||
return node;
|
||||
}));
|
||||
@@ -67,35 +76,26 @@ namespace Umbraco.Web.Trees
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
else
|
||||
|
||||
var container = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentTypeContainer);
|
||||
if (container != null)
|
||||
{
|
||||
var container = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentTypeContainer);
|
||||
if (container != null)
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
if (container.HasChildren() == false)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
|
||||
// root actions
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
|
||||
if (container.HasChildren() == false)
|
||||
{
|
||||
//can delete doc type
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
|
||||
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true);
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)));
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//delete doc type
|
||||
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)));
|
||||
//can delete doc type
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), hasSeparator: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true);
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
||||
@@ -12,6 +12,8 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using umbraco;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Services;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
@@ -24,20 +26,46 @@ namespace Umbraco.Web.Trees
|
||||
{
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
//we only support one tree level for data types
|
||||
if (id != Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
var intId = id.TryConvertTo<int>();
|
||||
if (intId == false) throw new InvalidOperationException("Id must be an integer");
|
||||
|
||||
var nodes = new TreeNodeCollection();
|
||||
|
||||
//Folders first
|
||||
nodes.AddRange(
|
||||
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DataTypeContainer)
|
||||
.OrderBy(entity => entity.Name)
|
||||
.Select(dt =>
|
||||
{
|
||||
var node = CreateTreeNode(dt.Id.ToString(), id, queryStrings, dt.Name, "icon-folder", dt.HasChildren(), "");
|
||||
node.Path = dt.Path;
|
||||
node.NodeType = "container";
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
node.AdditionalData["jsClickCallback"] = "javascript:void(0);";
|
||||
return node;
|
||||
}));
|
||||
|
||||
//if the request is for folders only then just return
|
||||
if (queryStrings["foldersonly"].IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes;
|
||||
|
||||
//Normal nodes
|
||||
var sysIds = GetSystemIds();
|
||||
|
||||
var collection = new TreeNodeCollection();
|
||||
collection.AddRange(
|
||||
Services.DataTypeService.GetAllDataTypeDefinitions()
|
||||
.OrderBy(x => x.Name)
|
||||
.Select(dt => CreateTreeNode(id, queryStrings, sysIds, dt)));
|
||||
return collection;
|
||||
nodes.AddRange(
|
||||
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType)
|
||||
.OrderBy(entity => entity.Name)
|
||||
.Select(dt =>
|
||||
{
|
||||
var node = CreateTreeNode(dt.Id.ToInvariantString(), id, queryStrings, dt.Name, "icon-autofill", false);
|
||||
node.Path = dt.Path;
|
||||
if (sysIds.Contains(dt.Id))
|
||||
{
|
||||
node.Icon = "icon-thumbnail-list";
|
||||
}
|
||||
return node;
|
||||
}));
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private IEnumerable<int> GetSystemIds()
|
||||
@@ -50,43 +78,47 @@ namespace Umbraco.Web.Trees
|
||||
};
|
||||
return systemIds;
|
||||
}
|
||||
|
||||
private TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, IEnumerable<int> systemIds, IDataTypeDefinition dt)
|
||||
{
|
||||
var node = CreateTreeNode(
|
||||
dt.Id.ToInvariantString(),
|
||||
id,
|
||||
queryStrings,
|
||||
dt.Name,
|
||||
"icon-autofill",
|
||||
false);
|
||||
|
||||
if (systemIds.Contains(dt.Id))
|
||||
{
|
||||
node.Icon = "icon-thumbnail-list";
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
|
||||
// root actions
|
||||
menu.Items.Add<CreateChildEntity, ActionNew>(ui.Text("actions", ActionNew.Instance.Alias));
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(ui.Text("actions", ActionRefresh.Instance.Alias), true);
|
||||
return menu;
|
||||
}
|
||||
|
||||
var sysIds = GetSystemIds();
|
||||
|
||||
if (sysIds.Contains(int.Parse(id)) == false)
|
||||
var container = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.DataTypeContainer);
|
||||
if (container != null)
|
||||
{
|
||||
//only have delete for each node
|
||||
menu.Items.Add<ActionDelete>(ui.Text("actions", ActionDelete.Instance.Alias));
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
if (container.HasChildren() == false)
|
||||
{
|
||||
//can delete data type
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), hasSeparator: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sysIds = GetSystemIds();
|
||||
|
||||
if (sysIds.Contains(int.Parse(id)) == false)
|
||||
{
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
|
||||
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true);
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
||||
@@ -15,10 +15,11 @@ using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
[UmbracoTreeAuthorize(Constants.Trees.DataTypes)]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes)]
|
||||
[Tree(Constants.Applications.Settings, Constants.Trees.MediaTypes, null, sortOrder:5)]
|
||||
[Umbraco.Web.Mvc.PluginController("UmbracoTrees")]
|
||||
[Mvc.PluginController("UmbracoTrees")]
|
||||
[CoreTree]
|
||||
[LegacyBaseTree(typeof(loadMediaTypes))]
|
||||
public class MediaTypeTreeController : TreeController
|
||||
{
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
@@ -28,18 +29,22 @@ namespace Umbraco.Web.Trees
|
||||
|
||||
var nodes = new TreeNodeCollection();
|
||||
|
||||
//TODO: MediaTypeContainers
|
||||
nodes.AddRange(
|
||||
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DocumentTypeContainer)
|
||||
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.MediaTypeContainer)
|
||||
.OrderBy(entity => entity.Name)
|
||||
.Select(dt =>
|
||||
{
|
||||
var node = CreateTreeNode(dt.Id.ToString(), id, queryStrings, dt.Name, "icon-folder", dt.HasChildren(),
|
||||
queryStrings.GetValue<string>("application") + TreeAlias.EnsureStartsWith('/') + "/list/" + dt.Id);
|
||||
var node = CreateTreeNode(dt.Id.ToString(), id, queryStrings, dt.Name, "icon-folder", dt.HasChildren(), "");
|
||||
node.Path = dt.Path;
|
||||
node.NodeType = "container";
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
node.AdditionalData["jsClickCallback"] = "javascript:void(0);";
|
||||
return node;
|
||||
}));
|
||||
|
||||
//if the request is for folders only then just return
|
||||
if (queryStrings["foldersonly"].IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes;
|
||||
|
||||
nodes.AddRange(
|
||||
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.MediaType)
|
||||
.OrderBy(entity => entity.Name)
|
||||
@@ -53,8 +58,6 @@ namespace Umbraco.Web.Trees
|
||||
return nodes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
@@ -69,29 +72,26 @@ namespace Umbraco.Web.Trees
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
else
|
||||
|
||||
var container = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.MediaTypeContainer);
|
||||
if (container != null)
|
||||
{
|
||||
var container = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentTypeContainer);
|
||||
if (container != null)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
|
||||
// root actions
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)));
|
||||
|
||||
if (container.HasChildren() == false)
|
||||
{
|
||||
//can delete doc type
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
}
|
||||
else
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
if (container.HasChildren() == false)
|
||||
{
|
||||
//delete doc type
|
||||
//can delete doc type
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
}
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), hasSeparator: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true);
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
||||
@@ -12,10 +12,11 @@ using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
[UmbracoTreeAuthorize(Constants.Trees.DataTypes)]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MemberTypes)]
|
||||
[Tree(Constants.Applications.Members, Constants.Trees.MemberTypes, null, sortOrder:2 )]
|
||||
[Umbraco.Web.Mvc.PluginController("UmbracoTrees")]
|
||||
[Mvc.PluginController("UmbracoTrees")]
|
||||
[CoreTree]
|
||||
[LegacyBaseTree(typeof(loadMemberTypes))]
|
||||
public class MemberTypeTreeController : TreeController
|
||||
{
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.Web.Http;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.WebApi
|
||||
{
|
||||
@@ -107,6 +108,22 @@ namespace Umbraco.Web.WebApi
|
||||
return msg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an error response with notifications in the result to be displayed in the UI
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="errorMessage"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponseMessage CreateNotificationValidationErrorResponse(this HttpRequestMessage request, string errorMessage)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = errorMessage
|
||||
};
|
||||
notificationModel.AddErrorNotification(errorMessage, string.Empty);
|
||||
return request.CreateValidationErrorResponse(notificationModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a 400 response message indicating that a validation error occurred
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user