diff --git a/src/Umbraco.Core/Constants-ObjectTypes.cs b/src/Umbraco.Core/Constants-ObjectTypes.cs index 81bd66928d..4f225aaccb 100644 --- a/src/Umbraco.Core/Constants-ObjectTypes.cs +++ b/src/Umbraco.Core/Constants-ObjectTypes.cs @@ -9,6 +9,16 @@ namespace Umbraco.Core /// public static class ObjectTypes { + /// + /// Guid for a doc type container + /// + public const string DocumentTypeContainer = "2F7A2769-6B0B-4468-90DD-AF42D64F7F16"; + + /// + /// Guid for a doc type container + /// + public const string MediaTypeContainer = "42AEF799-B288-4744-9B10-BE144B73CDC4"; + /// /// Guid for a Content Item object. /// diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index e9d4451314..239792bf08 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Strings; namespace Umbraco.Core.Models { + /// /// Defines the type of a object /// diff --git a/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs b/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs index edcc25ade8..987be2a276 100644 --- a/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs +++ b/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs @@ -11,6 +11,20 @@ namespace Umbraco.Core.Models internal static class UmbracoEntityExtensions { + public static bool HasChildren(this IUmbracoEntity entity) + { + if (entity.AdditionalData.ContainsKey("HasChildren")) + { + var convert = entity.AdditionalData["HasChildren"].TryConvertTo(); + if (convert) + { + return convert.Result; + } + } + return false; + } + + public static object GetAdditionalDataValueIgnoreCase(this IUmbracoEntity entity, string key, object defaultVal) { if (entity.AdditionalData.ContainsKeyIgnoreCase(key) == false) return defaultVal; diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs index 37ad181682..8f9acbd057 100644 --- a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs +++ b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs @@ -109,6 +109,13 @@ namespace Umbraco.Core.Models /// [UmbracoObjectTypeAttribute(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))] [FriendlyName("Data Type")] - DataType + DataType, + + /// + /// Entity Container + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.DocumentTypeContainer)] + [FriendlyName("Document Type Container")] + DocumentTypeContainer } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs index 8dba129d93..17f9afe258 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs @@ -33,6 +33,66 @@ namespace Umbraco.Core.Persistence.Repositories { } + /// + /// The container object type - used for organizing content types + /// + protected abstract Guid ContainerObjectTypeId { get; } + + public Attempt CreateFolder(int parentId, string name, int userId) + { + name = name.Trim(); + + Mandate.ParameterNotNullOrEmpty(name, "name"); + + var exists = Database.FirstOrDefault( + new Sql().Select("*") + .From(SqlSyntax) + .Where(dto => dto.ParentId == parentId && dto.Text == name && dto.NodeObjectType == ContainerObjectTypeId)); + + if (exists != null) + { + return Attempt.Fail(exists.NodeId, new InvalidOperationException("A folder with the same name already exists")); + } + + var level = 0; + var path = "-1"; + if (parentId > -1) + { + var parent = Database.FirstOrDefault( + new Sql().Select("*") + .From(SqlSyntax) + .Where(dto => dto.NodeId == parentId && dto.NodeObjectType == ContainerObjectTypeId)); + + if (parent == null) + { + return Attempt.Fail(0, new NullReferenceException("No content type container found with parent id " + parentId)); + } + level = parent.Level; + path = parent.Path; + } + + var folder = new NodeDto + { + 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 + }; + + Database.Save(folder); + //update the path + folder.Path = folder.Path + "," + folder.NodeId; + Database.Save(folder); + + return Attempt.Succeed(folder.NodeId); + } + /// /// Returns the content type ids that match the query /// diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs index 40679af854..4db21a5616 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs @@ -242,6 +242,12 @@ namespace Umbraco.Core.Persistence.Repositories #endregion - + /// + /// The container object type - used for organizing content types + /// + protected override Guid ContainerObjectTypeId + { + get { return new Guid(Constants.ObjectTypes.DocumentTypeContainer); } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs index e3ce084cf7..b612a9109d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Querying; @@ -18,5 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// IEnumerable GetAllPropertyTypeAliases(); + + Attempt CreateFolder(int parentId, string name, int userId); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs index cc51fd6e7c..13cdab400e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs @@ -181,5 +181,13 @@ namespace Umbraco.Core.Persistence.Repositories } #endregion + + /// + /// The container object type - used for organizing content types + /// + protected override Guid ContainerObjectTypeId + { + get { throw new NotImplementedException(); } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs index bb6099a206..d9c8e815be 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs @@ -241,6 +241,14 @@ namespace Umbraco.Core.Persistence.Repositories #endregion + /// + /// The container object type - used for organizing content types + /// + protected override Guid ContainerObjectTypeId + { + get { throw new NotImplementedException(); } + } + /// /// Override so we can specify explicit db type's on any property types that are built-in. /// diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs index d5ebaabdb6..d22ba90d5d 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs @@ -15,6 +15,14 @@ namespace Umbraco.Core.Services { } + public Attempt CreateFolder(int parentId, string name, int userId = 0) + { + using (var repo = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork())) + { + return repo.CreateFolder(parentId, name, userId); + } + } + /// /// 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. diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs index 695d092bd4..1d249aa6d1 100644 --- a/src/Umbraco.Core/Services/EntityService.cs +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Umbraco.Core.Cache; using Umbraco.Core.CodeAnnotations; using Umbraco.Core.Logging; @@ -34,7 +35,28 @@ namespace Umbraco.Core.Services {typeof (IMedia).FullName, new Tuple>(UmbracoObjectTypes.Media, mediaService.GetById)}, {typeof (IMediaType).FullName, new Tuple>(UmbracoObjectTypes.MediaType, contentTypeService1.GetMediaType)}, {typeof (IMember).FullName, new Tuple>(UmbracoObjectTypes.Member, memberService.GetById)}, - {typeof (IMemberType).FullName, new Tuple>(UmbracoObjectTypes.MemberType, memberTypeService.Get)} + {typeof (IMemberType).FullName, new Tuple>(UmbracoObjectTypes.MemberType, memberTypeService.Get)}, + //{typeof (IUmbracoEntity).FullName, new Tuple>(UmbracoObjectTypes.EntityContainer, id => + //{ + // using (var uow = UowProvider.GetUnitOfWork()) + // { + // var found = uow.Database.FirstOrDefault("SELECT * FROM umbracoNode WHERE id=@id", new { id = id }); + // return found == null ? null : new UmbracoEntity(found.Trashed) + // { + // Id = found.NodeId, + // Name = found.Text, + // Key = found.UniqueId, + // SortOrder = found.SortOrder, + // Path = found.Path, + // NodeObjectTypeId = found.NodeObjectType.Value, + // CreateDate = found.CreateDate, + // CreatorId = found.UserId.Value, + // Level = found.Level, + // ParentId = found.ParentId + // }; + // } + + //})} }; } @@ -61,6 +83,7 @@ namespace Umbraco.Core.Services case UmbracoObjectTypes.DocumentType: case UmbracoObjectTypes.Member: case UmbracoObjectTypes.DataType: + case UmbracoObjectTypes.DocumentTypeContainer: return uow.Database.ExecuteScalar(new Sql().Select("id").From().Where(dto => dto.UniqueId == key)); case UmbracoObjectTypes.RecycleBin: case UmbracoObjectTypes.Stylesheet: diff --git a/src/Umbraco.Core/Services/IContentTypeService.cs b/src/Umbraco.Core/Services/IContentTypeService.cs index 9e2d179bb0..a538840e36 100644 --- a/src/Umbraco.Core/Services/IContentTypeService.cs +++ b/src/Umbraco.Core/Services/IContentTypeService.cs @@ -10,6 +10,8 @@ namespace Umbraco.Core.Services /// public interface IContentTypeService : IService { + Attempt CreateFolder(int parentId, string name, int userId = 0); + /// /// Gets all property type aliases. /// diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js index 48e7030571..461e2800e7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js @@ -139,6 +139,14 @@ function contentTypeResource($q, $http, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostSave"), contentType), 'Failed to save data for content type id ' + contentType.id); + }, + + createFolder: function(parentId, name) { + + return umbRequestHelper.resourcePromise( + $http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateFolder", { parentId: parentId, name: name })), + 'Failed to create a folder under parent id ' + parentId); + } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttype/create.html b/src/Umbraco.Web.UI.Client/src/views/documenttype/create.html index ca31abb93c..b7c95d49c4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttype/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttype/create.html @@ -1,45 +1,51 @@ -