Merge temp-U4-6911 into 7.4.0

This commit is contained in:
Stephan
2015-11-13 15:05:47 +01:00
62 changed files with 2219 additions and 410 deletions
@@ -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;
}
}
}
+1 -1
View File
@@ -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;
+33 -17
View File
@@ -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.
+77 -1
View File
@@ -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,
}
}
+4
View File
@@ -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>&nbsp;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&nbsp;<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>&nbsp;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>&nbsp;<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>&nbsp;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&nbsp;<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>&nbsp;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&nbsp;<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>&nbsp;
<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>&nbsp;
<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>&nbsp;<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>&nbsp;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&nbsp;<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";
+10 -24
View File
@@ -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
+63 -3
View File
@@ -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
+40 -2
View File
@@ -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;
+68 -36
View File
@@ -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>