diff --git a/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs b/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs new file mode 100644 index 0000000000..0bb9de6c86 --- /dev/null +++ b/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Umbraco.Core.CodeAnnotations +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + internal class UmbracoUdiTypeAttribute : Attribute + { + public string UdiType { get; private set; } + + public UmbracoUdiTypeAttribute(string udiType) + { + UdiType = udiType; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs index aed7f61a06..05189acc3e 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs @@ -159,6 +159,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings get { return GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring"); } } + [ConfigurationProperty("showDeprecatedPropertyEditors")] + internal InnerTextConfigurationElement ShowDeprecatedPropertyEditors + { + get { return GetOptionalTextElement("showDeprecatedPropertyEditors", false); } + } + [ConfigurationProperty("EnableInheritedDocumentTypes")] internal InnerTextConfigurationElement EnableInheritedDocumentTypes { @@ -306,6 +312,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings get { return DefaultDocumentTypeProperty; } } + bool IContentSection.ShowDeprecatedPropertyEditors + { + get { return ShowDeprecatedPropertyEditors; } + } + bool IContentSection.EnableInheritedDocumentTypes { get { return EnableInheritedDocumentTypes; } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs index 3d5e4435b6..a388126948 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs @@ -60,6 +60,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings string DefaultDocumentTypeProperty { get; } + /// + /// The default for this is false but if you would like deprecated property editors displayed + /// in the data type editor you can enable this + /// + bool ShowDeprecatedPropertyEditors { get; } + bool EnableInheritedDocumentTypes { get; } bool EnableInheritedMediaTypes { get; } diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index 80f118b58e..189d11d3a1 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -42,10 +42,14 @@ namespace Umbraco.Core [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string ContentPicker = "158AA029-24ED-4948-939E-C3DA209E5FBA"; + + [Obsolete("This is an obsoleted content picker, use ContentPicker2Alias instead")] + public const string ContentPickerAlias = "Umbraco.ContentPickerAlias"; + /// /// Alias for the Content Picker datatype. /// - public const string ContentPickerAlias = "Umbraco.ContentPickerAlias"; + public const string ContentPicker2Alias = "Umbraco.ContentPicker2"; /// /// Guid for the Date datatype. @@ -192,11 +196,15 @@ namespace Umbraco.Core [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string MediaPicker = "EAD69342-F06D-4253-83AC-28000225583B"; + [Obsolete("This is an obsoleted picker, use MediaPicker2Alias instead")] + public const string MediaPickerAlias = "Umbraco.MediaPicker"; + /// /// Alias for the Media Picker datatype. /// - public const string MediaPickerAlias = "Umbraco.MediaPicker"; + public const string MediaPicker2Alias = "Umbraco.MediaPicker2"; + [Obsolete("This is an obsoleted picker, use MediaPicker2Alias instead")] public const string MultipleMediaPickerAlias = "Umbraco.MultipleMediaPicker"; /// @@ -205,26 +213,32 @@ namespace Umbraco.Core [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string MemberPicker = "39F533E4-0551-4505-A64B-E0425C5CE775"; + [Obsolete("This is an obsoleted picker, use MemberPicker2Alias instead")] + public const string MemberPickerAlias = "Umbraco.MemberPicker"; + /// /// Alias for the Member Picker datatype. /// - public const string MemberPickerAlias = "Umbraco.MemberPicker"; + public const string MemberPicker2Alias = "Umbraco.MemberPicker2"; /// /// Alias for the Member Group Picker datatype. /// public const string MemberGroupPickerAlias = "Umbraco.MemberGroupPicker"; - + /// /// Guid for the Multi-Node Tree Picker datatype /// [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string MultiNodeTreePicker = "7E062C13-7C41-4AD9-B389-41D88AEEF87C"; + [Obsolete("This is an obsoleted picker, use MultiNodeTreePicker2Alias instead")] + public const string MultiNodeTreePickerAlias = "Umbraco.MultiNodeTreePicker"; + /// /// Alias for the Multi-Node Tree Picker datatype /// - public const string MultiNodeTreePickerAlias = "Umbraco.MultiNodeTreePicker"; + public const string MultiNodeTreePicker2Alias = "Umbraco.MultiNodeTreePicker2"; /// /// Guid for the Multiple Textstring datatype. diff --git a/src/Umbraco.Core/Models/Rdbms/DataTypePreValueDto.cs b/src/Umbraco.Core/Models/Rdbms/DataTypePreValueDto.cs index 652e63df0b..6e8fc29d95 100644 --- a/src/Umbraco.Core/Models/Rdbms/DataTypePreValueDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/DataTypePreValueDto.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Rdbms internal class DataTypePreValueDto { [Column("id")] - [PrimaryKeyColumn(IdentitySeed = 6)] + [PrimaryKeyColumn(IdentitySeed = 10)] public int Id { get; set; } [Column("datatypeNodeId")] diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs index 68e6e1a815..0df7a21e57 100644 --- a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs +++ b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Models /// /// Root /// - [UmbracoObjectType(Constants.ObjectTypes.SystemRoot)] + [UmbracoObjectType(Constants.ObjectTypes.SystemRoot)] [FriendlyName("Root")] ROOT, @@ -35,6 +35,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.Document, typeof(IContent))] [FriendlyName("Document")] + [UmbracoUdiType(Constants.UdiEntityType.Document)] Document, /// @@ -42,6 +43,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.Media, typeof(IMedia))] [FriendlyName("Media")] + [UmbracoUdiType(Constants.UdiEntityType.Media)] Media, /// @@ -49,6 +51,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.MemberType, typeof(IMemberType))] [FriendlyName("Member Type")] + [UmbracoUdiType(Constants.UdiEntityType.MemberType)] MemberType, /// @@ -56,6 +59,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.Template, typeof(ITemplate))] [FriendlyName("Template")] + [UmbracoUdiType(Constants.UdiEntityType.Template)] Template, /// @@ -63,6 +67,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.MemberGroup)] [FriendlyName("Member Group")] + [UmbracoUdiType(Constants.UdiEntityType.MemberGroup)] MemberGroup, //TODO: What is a 'Content Item' supposed to be??? @@ -80,6 +85,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.MediaType, typeof(IMediaType))] [FriendlyName("Media Type")] + [UmbracoUdiType(Constants.UdiEntityType.MediaType)] MediaType, /// @@ -87,13 +93,14 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.DocumentType, typeof(IContentType))] [FriendlyName("Document Type")] + [UmbracoUdiType(Constants.UdiEntityType.DocumentType)] DocumentType, /// /// Recycle Bin /// [UmbracoObjectType(Constants.ObjectTypes.ContentRecycleBin)] - [FriendlyName("Recycle Bin")] + [FriendlyName("Recycle Bin")] RecycleBin, /// @@ -101,6 +108,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.Stylesheet)] [FriendlyName("Stylesheet")] + [UmbracoUdiType(Constants.UdiEntityType.Stylesheet)] Stylesheet, /// @@ -108,6 +116,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.Member, typeof(IMember))] [FriendlyName("Member")] + [UmbracoUdiType(Constants.UdiEntityType.Member)] Member, /// @@ -115,6 +124,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))] [FriendlyName("Data Type")] + [UmbracoUdiType(Constants.UdiEntityType.DataType)] DataType, /// @@ -122,6 +132,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.DocumentTypeContainer)] [FriendlyName("Document Type Container")] + [UmbracoUdiType(Constants.UdiEntityType.DocumentTypeContainer)] DocumentTypeContainer, /// @@ -129,6 +140,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.MediaTypeContainer)] [FriendlyName("Media Type Container")] + [UmbracoUdiType(Constants.UdiEntityType.MediaTypeContainer)] MediaTypeContainer, /// @@ -136,6 +148,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.DataTypeContainer)] [FriendlyName("Data Type Container")] + [UmbracoUdiType(Constants.UdiEntityType.DataTypeContainer)] DataTypeContainer, /// @@ -143,6 +156,7 @@ namespace Umbraco.Core.Models /// [UmbracoObjectType(Constants.ObjectTypes.RelationType)] [FriendlyName("Relation Type")] + [UmbracoUdiType(Constants.UdiEntityType.RelationType)] RelationType, /// diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs index 34ee29b96f..5f92e6425e 100644 --- a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs +++ b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs @@ -12,6 +12,7 @@ namespace Umbraco.Core.Models { //MUST be concurrent to avoid thread collisions! private static readonly ConcurrentDictionary UmbracoObjectTypeCache = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary UmbracoObjectTypeUdiCache = new ConcurrentDictionary(); /// /// Get an UmbracoObjectTypes value from it's name @@ -43,6 +44,21 @@ namespace Umbraco.Core.Models return umbracoObjectType; } + public static string GetUdiType(Guid guid) + { + var umbracoObjectType = Constants.UdiEntityType.Unknown; + + foreach (var name in Enum.GetNames(typeof(UmbracoObjectTypes))) + { + var objType = GetUmbracoObjectType(name); + if (objType.GetGuid() == guid) + { + umbracoObjectType = GetUdiType(objType); + } + } + return umbracoObjectType; + } + /// /// Extension method for the UmbracoObjectTypes enum to return the enum GUID /// @@ -68,6 +84,26 @@ namespace Umbraco.Core.Models }); } + public static string GetUdiType(this UmbracoObjectTypes umbracoObjectType) + { + return UmbracoObjectTypeUdiCache.GetOrAdd(umbracoObjectType, types => + { + var type = typeof(UmbracoObjectTypes); + var memInfo = type.GetMember(umbracoObjectType.ToString()); + var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoUdiTypeAttribute), + false); + + if (attributes.Length == 0) + return Constants.UdiEntityType.Unknown; + + var attribute = ((UmbracoUdiTypeAttribute)attributes[0]); + if (attribute == null) + return Constants.UdiEntityType.Unknown; + + return attribute.UdiType; + }); + } + /// /// Extension method for the UmbracoObjectTypes enum to return the enum name /// diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 3c7fc5ed42..7dc57ba7f6 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -130,21 +130,21 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1034, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1034", SortOrder = 2, UniqueId = new Guid("a6857c73-d6e9-480c-b6e6-f15f6ad11125"), Text = "Content Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1035, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1035", SortOrder = 2, UniqueId = new Guid("93929b9a-93a2-4e2a-b239-d99334440a59"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1036, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1036", SortOrder = 2, UniqueId = new Guid("2b24165f-9782-4aa3-b459-1de4a4d21f60"), Text = "Member Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1040, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1040", SortOrder = 2, UniqueId = new Guid("21e798da-e06e-4eda-a511-ed257f78d4fa"), Text = "Related Links", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1041, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1041", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = new Guid(Constants.ObjectTypes.MemberType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1045, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1045", SortOrder = 2, UniqueId = new Guid("7E3962CC-CE20-4FFC-B661-5897A894BA7E"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + //New UDI pickers with newer Ids + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1046, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1046", SortOrder = 2, UniqueId = new Guid("FD1E0DA5-5606-4862-B679-5D0CF3A52A59"), Text = "Content Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); //TODO: We're not creating these for 7.0 //_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); //_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1038, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1038", SortOrder = 2, UniqueId = new Guid("1251c96c-185c-4e9b-93f4-b48205573cbd"), Text = "Simple Editor", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - //_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1042, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1042", SortOrder = 2, UniqueId = new Guid("0a452bd5-83f9-4bc3-8403-1286e13fb77e"), Text = "Macro Container", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); } @@ -246,17 +246,19 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 12, DataTypeId = -40, PropertyEditorAlias = Constants.PropertyEditors.RadioButtonListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 13, DataTypeId = -41, PropertyEditorAlias = Constants.PropertyEditors.DateAlias, DbType = "Date" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 16, DataTypeId = 1034, PropertyEditorAlias = Constants.PropertyEditors.ContentPickerAlias, DbType = "Integer" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 18, DataTypeId = 1036, PropertyEditorAlias = Constants.PropertyEditors.MemberPickerAlias, DbType = "Integer" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 21, DataTypeId = 1040, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, DbType = "Ntext" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 24, DataTypeId = 1043, PropertyEditorAlias = Constants.PropertyEditors.ImageCropperAlias, DbType = "Ntext" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 25, DataTypeId = 1045, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -26, DataTypeId = Constants.System.DefaultContentListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -27, DataTypeId = Constants.System.DefaultMediaListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -28, DataTypeId = Constants.System.DefaultMembersListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -28, DataTypeId = Constants.System.DefaultMembersListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" }); + + //New UDI pickers with newer Ids + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 26, DataTypeId = 1046, PropertyEditorAlias = Constants.PropertyEditors.ContentPicker2Alias, DbType = "Nvarchar" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 27, DataTypeId = 1047, PropertyEditorAlias = Constants.PropertyEditors.MemberPicker2Alias, DbType = "Nvarchar" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 28, DataTypeId = 1048, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 29, DataTypeId = 1049, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" }); //TODO: We're not creating these for 7.0 //_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 19, DataTypeId = 1038, PropertyEditorAlias = Constants.PropertyEditors.MarkdownEditorAlias, DbType = "Ntext" }); @@ -268,10 +270,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial { _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 3, Alias = "", SortOrder = 0, DataTypeNodeId = -87, Value = ",code,undo,redo,cut,copy,mcepasteword,stylepicker,bold,italic,bullist,numlist,outdent,indent,mcelink,unlink,mceinsertanchor,mceimage,umbracomacro,mceinserttable,umbracoembed,mcecharmap,|1|1,2,3,|0|500,400|1049,|true|" }); _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 4, Alias = "group", SortOrder = 0, DataTypeNodeId = 1041, Value = "default" }); - - //default's for MultipleMediaPickerAlias picker - _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 5, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1045, Value = "1" }); - + //defaults for the member list _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -1, Alias = "pageSize", SortOrder = 1, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "10" }); _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -2, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "username" }); @@ -288,6 +287,9 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -7, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "desc" }); _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -8, Alias = "layouts", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[" + cardLayout + "," + listLayout + "]" }); _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -9, Alias = "includeProperties", SortOrder = 5, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]" }); + + //default's for MultipleMediaPickerAlias picker + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 6, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1049, Value = "1" }); } private void CreateUmbracoRelationTypeData() diff --git a/src/Umbraco.Core/PropertyEditors/PreValueField.cs b/src/Umbraco.Core/PropertyEditors/PreValueField.cs index 3cf4e960ea..2b66f7a6a8 100644 --- a/src/Umbraco.Core/PropertyEditors/PreValueField.cs +++ b/src/Umbraco.Core/PropertyEditors/PreValueField.cs @@ -15,6 +15,7 @@ namespace Umbraco.Core.PropertyEditors public PreValueField() { Validators = new List(); + Config = new Dictionary(); //check for an attribute and fill the values var att = GetType().GetCustomAttribute(false); @@ -79,5 +80,11 @@ namespace Umbraco.Core.PropertyEditors /// [JsonProperty("validation", ItemConverterType = typeof(ManifestValidatorConverter))] public List Validators { get; private set; } + + /// + /// This allows for custom configuration to be injected into the pre-value editor + /// + [JsonProperty("config")] + public IDictionary Config { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs index 6cecc9dff5..c2498ecc7a 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs @@ -38,6 +38,7 @@ namespace Umbraco.Core.PropertyEditors IsParameterEditor = _attribute.IsParameterEditor; Icon = _attribute.Icon; Group = _attribute.Group; + IsDeprecated = _attribute.IsDeprecated; } } @@ -90,6 +91,9 @@ namespace Umbraco.Core.PropertyEditors get { return CreateValueEditor(); } } + [JsonIgnore] + public bool IsDeprecated { get; internal set; } + [JsonIgnore] IValueEditor IParameterEditor.ValueEditor { diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs index d120753185..41e4ccc74e 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs @@ -60,6 +60,12 @@ namespace Umbraco.Core.PropertyEditors public string ValueType { get; set; } public bool IsParameterEditor { get; set; } + /// + /// If set to true, this property editor will not show up in the DataType's drop down list + /// if there is not already one of them chosen for a DataType + /// + public bool IsDeprecated { get; set; } + /// /// If this is is true than the editor will be displayed full width without a label /// diff --git a/src/Umbraco.Core/TypeExtensions.cs b/src/Umbraco.Core/TypeExtensions.cs index 3208c1fbe8..76dc79c219 100644 --- a/src/Umbraco.Core/TypeExtensions.cs +++ b/src/Umbraco.Core/TypeExtensions.cs @@ -425,7 +425,28 @@ namespace Umbraco.Core assemblyName.FullName.StartsWith("App_Code.") ? "App_Code" : assemblyName.Name); } + /// + /// If the given is an array or some other collection + /// comprised of 0 or more instances of a "subtype", get that type + /// + /// the source type + /// + internal static Type GetEnumeratedType(this Type type) + { + if (typeof(IEnumerable).IsAssignableFrom(type) == false) + return null; + // provided by Array + var elType = type.GetElementType(); + if (null != elType) return elType; + + // otherwise provided by collection + var elTypes = type.GetGenericArguments(); + if (elTypes.Length > 0) return elTypes[0]; + + // otherwise is not an 'enumerated' type + return null; + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Udi.cs b/src/Umbraco.Core/Udi.cs index a7298c6f89..9d67c6ccab 100644 --- a/src/Umbraco.Core/Udi.cs +++ b/src/Umbraco.Core/Udi.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; +using System.Reflection; using Umbraco.Core.Deploy; namespace Umbraco.Core @@ -10,9 +12,10 @@ namespace Umbraco.Core /// Represents an entity identifier. /// /// An Udi can be fully qualified or "closed" eg umb://document/{guid} or "open" eg umb://document. + [TypeConverter(typeof(UdiTypeConverter))] public abstract class Udi : IComparable { - private static readonly Dictionary UdiTypes = new Dictionary(); + private static readonly Lazy> UdiTypes; private static readonly ConcurrentDictionary RootUdis = new ConcurrentDictionary(); internal readonly Uri UriValue; // internal for UdiRange @@ -39,32 +42,50 @@ namespace Umbraco.Core static Udi() { - // for tests etc. - UdiTypes[Constants.DeployEntityType.AnyGuid] = UdiType.GuidUdi; - UdiTypes[Constants.DeployEntityType.AnyString] = UdiType.StringUdi; - - // we don't have connectors for these... - UdiTypes[Constants.DeployEntityType.Member] = UdiType.GuidUdi; - UdiTypes[Constants.DeployEntityType.MemberGroup] = UdiType.GuidUdi; - - // fixme - or inject from...? - // there is no way we can get the "registered" service connectors, as registration - // happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we - // just pick every service connectors - just making sure that not two of them - // would register the same entity type, with different udi types (would not make - // much sense anyways). - var connectors = PluginManager.Current.ResolveTypes(); - foreach (var connector in connectors) + UdiTypes = new Lazy>(() => { - var attrs = connector.GetCustomAttributes(false); - foreach (var attr in attrs) + var result = new Dictionary(); + + // known types: + foreach (var fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static)) { - UdiType udiType; - if (UdiTypes.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType) - throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType)); - UdiTypes[attr.EntityType] = attr.UdiType; + // IsLiteral determines if its value is written at + // compile time and not changeable + // IsInitOnly determine if the field can be set + // in the body of the constructor + // for C# a field which is readonly keyword would have both true + // but a const field would have only IsLiteral equal to true + if (fi.IsLiteral && fi.IsInitOnly == false) + { + var udiType = fi.GetCustomAttribute(); + + if (udiType == null) + throw new InvalidOperationException("All Constants listed in UdiEntityType must be attributed with " + typeof(Constants.UdiTypeAttribute)); + result[fi.GetValue(null).ToString()] = udiType.UdiType; + } } - } + + // Scan for unknown UDI types + // there is no way we can get the "registered" service connectors, as registration + // happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we + // just pick every service connectors - just making sure that not two of them + // would register the same entity type, with different udi types (would not make + // much sense anyways). + var connectors = PluginManager.Current.ResolveTypes(); + foreach (var connector in connectors) + { + var attrs = connector.GetCustomAttributes(false); + foreach (var attr in attrs) + { + UdiType udiType; + if (result.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType) + throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType)); + result[attr.EntityType] = attr.UdiType; + } + } + + return result; + }); } /// @@ -105,8 +126,8 @@ namespace Umbraco.Core udi = null; Uri uri; - if (!Uri.IsWellFormedUriString(s, UriKind.Absolute) - || !Uri.TryCreate(s, UriKind.Absolute, out uri)) + if (Uri.IsWellFormedUriString(s, UriKind.Absolute) == false + || Uri.TryCreate(s, UriKind.Absolute, out uri) == false) { if (tryParse) return false; throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s)); @@ -114,7 +135,7 @@ namespace Umbraco.Core var entityType = uri.Host; UdiType udiType; - if (!UdiTypes.TryGetValue(entityType, out udiType)) + if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false) { if (tryParse) return false; throw new FormatException(string.Format("Unknown entity type \"{0}\".", entityType)); @@ -128,7 +149,7 @@ namespace Umbraco.Core return true; } Guid guid; - if (!Guid.TryParse(path, out guid)) + if (Guid.TryParse(path, out guid) == false) { if (tryParse) return false; throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s)); @@ -150,7 +171,7 @@ namespace Umbraco.Core return RootUdis.GetOrAdd(entityType, x => { UdiType udiType; - if (!UdiTypes.TryGetValue(x, out udiType)) + if (UdiTypes.Value.TryGetValue(x, out udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType)); return udiType == UdiType.StringUdi ? (Udi)new StringUdi(entityType, string.Empty) @@ -177,7 +198,7 @@ namespace Umbraco.Core public static Udi Create(string entityType, string id) { UdiType udiType; - if (!UdiTypes.TryGetValue(entityType, out udiType)) + if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType"); if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("Value cannot be null or whitespace.", "id"); @@ -196,7 +217,7 @@ namespace Umbraco.Core public static Udi Create(string entityType, Guid id) { UdiType udiType; - if (!UdiTypes.TryGetValue(entityType, out udiType)) + if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType"); if (udiType != UdiType.GuidUdi) throw new InvalidOperationException(string.Format("Entity type \"{0}\" does not have guid udis.", entityType)); @@ -208,7 +229,7 @@ namespace Umbraco.Core internal static Udi Create(Uri uri) { UdiType udiType; - if (!UdiTypes.TryGetValue(uri.Host, out udiType)) + if (UdiTypes.Value.TryGetValue(uri.Host, out udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", uri.Host), "uri"); if (udiType == UdiType.GuidUdi) return new GuidUdi(uri); @@ -219,7 +240,7 @@ namespace Umbraco.Core public void EnsureType(params string[] validTypes) { - if (!validTypes.Contains(EntityType)) + if (validTypes.Contains(EntityType) == false) throw new Exception(string.Format("Unexpected entity type \"{0}\".", EntityType)); } @@ -260,7 +281,7 @@ namespace Umbraco.Core public static bool operator !=(Udi udi1, Udi udi2) { - return !(udi1 == udi2); + return (udi1 == udi2) == false; } } diff --git a/src/Umbraco.Core/Constants-DeployEntityType.cs b/src/Umbraco.Core/UdiEntityType.cs similarity index 81% rename from src/Umbraco.Core/Constants-DeployEntityType.cs rename to src/Umbraco.Core/UdiEntityType.cs index a62ca3d8ef..f6b9b1e3b0 100644 --- a/src/Umbraco.Core/Constants-DeployEntityType.cs +++ b/src/Umbraco.Core/UdiEntityType.cs @@ -7,52 +7,82 @@ namespace Umbraco.Core public static partial class Constants { - /// /// Defines well-known entity types. /// /// Well-known entity types are those that Deploy already knows about, /// but entity types are strings and so can be extended beyond what is defined here. - public static class DeployEntityType + public static class UdiEntityType { + [UdiType(UdiType.Unknown)] + public const string Unknown = "unknown"; + // guid entity types + [UdiType(UdiType.GuidUdi)] public const string AnyGuid = "any-guid"; // that one is for tests + [UdiType(UdiType.GuidUdi)] public const string Document = "document"; + [UdiType(UdiType.GuidUdi)] public const string Media = "media"; + [UdiType(UdiType.GuidUdi)] public const string Member = "member"; + [UdiType(UdiType.GuidUdi)] public const string DictionaryItem = "dictionary-item"; + [UdiType(UdiType.GuidUdi)] public const string Macro = "macro"; + [UdiType(UdiType.GuidUdi)] public const string Template = "template"; + [UdiType(UdiType.GuidUdi)] public const string DocumentType = "document-type"; + [UdiType(UdiType.GuidUdi)] public const string DocumentTypeContainer = "document-type-container"; + [UdiType(UdiType.GuidUdi)] public const string MediaType = "media-type"; + [UdiType(UdiType.GuidUdi)] public const string MediaTypeContainer = "media-type-container"; + [UdiType(UdiType.GuidUdi)] public const string DataType = "data-type"; + [UdiType(UdiType.GuidUdi)] public const string DataTypeContainer = "data-type-container"; + [UdiType(UdiType.GuidUdi)] public const string MemberType = "member-type"; + [UdiType(UdiType.GuidUdi)] public const string MemberGroup = "member-group"; + [UdiType(UdiType.GuidUdi)] public const string RelationType = "relation-type"; - + // forms + + [UdiType(UdiType.GuidUdi)] public const string FormsForm = "forms-form"; + [UdiType(UdiType.GuidUdi)] public const string FormsPreValue = "forms-prevalue"; + [UdiType(UdiType.GuidUdi)] public const string FormsDataSource = "forms-datasource"; // string entity types + [UdiType(UdiType.StringUdi)] public const string AnyString = "any-string"; // that one is for tests + [UdiType(UdiType.StringUdi)] public const string MediaFile = "media-file"; + [UdiType(UdiType.StringUdi)] public const string TemplateFile = "template-file"; + [UdiType(UdiType.StringUdi)] public const string Script = "script"; + [UdiType(UdiType.StringUdi)] public const string Stylesheet = "stylesheet"; + [UdiType(UdiType.StringUdi)] public const string PartialView = "partial-view"; + [UdiType(UdiType.StringUdi)] public const string PartialViewMacro = "partial-view-macro"; + [UdiType(UdiType.StringUdi)] public const string Xslt = "xslt"; public static string FromUmbracoObjectType(UmbracoObjectTypes umbracoObjectType) @@ -141,6 +171,15 @@ namespace Umbraco.Core } } + [AttributeUsage(AttributeTargets.Field)] + internal class UdiTypeAttribute : Attribute + { + public UdiType UdiType { get; private set; } + public UdiTypeAttribute(UdiType udiType) + { + UdiType = udiType; + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/UdiGetterExtensions.cs b/src/Umbraco.Core/UdiGetterExtensions.cs index a9750fe464..795d48c259 100644 --- a/src/Umbraco.Core/UdiGetterExtensions.cs +++ b/src/Umbraco.Core/UdiGetterExtensions.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this ITemplate entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.Template, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.Template, entity.Key).EnsureClosed(); } /// @@ -28,7 +28,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IContentType entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.DocumentType, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.DocumentType, entity.Key).EnsureClosed(); } /// @@ -39,7 +39,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IMediaType entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.MediaType, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.MediaType, entity.Key).EnsureClosed(); } /// @@ -50,7 +50,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IMemberType entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.MemberType, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.MemberType, entity.Key).EnsureClosed(); } /// @@ -61,7 +61,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IMemberGroup entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.MemberGroup, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.MemberGroup, entity.Key).EnsureClosed(); } /// @@ -74,9 +74,9 @@ namespace Umbraco.Core if (entity == null) throw new ArgumentNullException("entity"); string type; - if (entity is IContentType) type = Constants.DeployEntityType.DocumentType; - else if (entity is IMediaType) type = Constants.DeployEntityType.MediaType; - else if (entity is IMemberType) type = Constants.DeployEntityType.MemberType; + if (entity is IContentType) type = Constants.UdiEntityType.DocumentType; + else if (entity is IMediaType) type = Constants.UdiEntityType.MediaType; + else if (entity is IMemberType) type = Constants.UdiEntityType.MemberType; else throw new NotSupportedException(string.Format("Composition type {0} is not supported.", entity.GetType().FullName)); return new GuidUdi(type, entity.Key).EnsureClosed(); } @@ -89,7 +89,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IDataTypeDefinition entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.DataType, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.DataType, entity.Key).EnsureClosed(); } /// @@ -103,11 +103,11 @@ namespace Umbraco.Core string entityType; if (entity.ContainedObjectType == Constants.ObjectTypes.DataTypeGuid) - entityType = Constants.DeployEntityType.DataTypeContainer; + entityType = Constants.UdiEntityType.DataTypeContainer; else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentTypeGuid) - entityType = Constants.DeployEntityType.DocumentTypeContainer; + entityType = Constants.UdiEntityType.DocumentTypeContainer; else if (entity.ContainedObjectType == Constants.ObjectTypes.MediaTypeGuid) - entityType = Constants.DeployEntityType.MediaTypeContainer; + entityType = Constants.UdiEntityType.MediaTypeContainer; else throw new NotSupportedException(string.Format("Contained object type {0} is not supported.", entity.ContainedObjectType)); return new GuidUdi(entityType, entity.Key).EnsureClosed(); @@ -121,7 +121,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IMedia entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.Media, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.Media, entity.Key).EnsureClosed(); } /// @@ -132,7 +132,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IContent entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.Document, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.Document, entity.Key).EnsureClosed(); } /// @@ -143,7 +143,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IMember entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.Member, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.Member, entity.Key).EnsureClosed(); } /// @@ -154,7 +154,7 @@ namespace Umbraco.Core public static StringUdi GetUdi(this Stylesheet entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new StringUdi(Constants.DeployEntityType.Stylesheet, entity.Path.TrimStart('/')).EnsureClosed(); + return new StringUdi(Constants.UdiEntityType.Stylesheet, entity.Path.TrimStart('/')).EnsureClosed(); } /// @@ -165,7 +165,7 @@ namespace Umbraco.Core public static StringUdi GetUdi(this Script entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new StringUdi(Constants.DeployEntityType.Script, entity.Path.TrimStart('/')).EnsureClosed(); + return new StringUdi(Constants.UdiEntityType.Script, entity.Path.TrimStart('/')).EnsureClosed(); } /// @@ -176,7 +176,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IDictionaryItem entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.DictionaryItem, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.DictionaryItem, entity.Key).EnsureClosed(); } /// @@ -187,7 +187,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IMacro entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.Macro, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.Macro, entity.Key).EnsureClosed(); } /// @@ -198,7 +198,7 @@ namespace Umbraco.Core public static StringUdi GetUdi(this IPartialView entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new StringUdi(Constants.DeployEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed(); + return new StringUdi(Constants.UdiEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed(); } /// @@ -209,7 +209,7 @@ namespace Umbraco.Core public static StringUdi GetUdi(this IXsltFile entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new StringUdi(Constants.DeployEntityType.Xslt, entity.Path.TrimStart('/')).EnsureClosed(); + return new StringUdi(Constants.UdiEntityType.Xslt, entity.Path.TrimStart('/')).EnsureClosed(); } /// @@ -222,9 +222,9 @@ namespace Umbraco.Core if (entity == null) throw new ArgumentNullException("entity"); string type; - if (entity is IContent) type = Constants.DeployEntityType.Document; - else if (entity is IMedia) type = Constants.DeployEntityType.Media; - else if (entity is IMember) type = Constants.DeployEntityType.Member; + if (entity is IContent) type = Constants.UdiEntityType.Document; + else if (entity is IMedia) type = Constants.UdiEntityType.Media; + else if (entity is IMember) type = Constants.UdiEntityType.Member; else throw new NotSupportedException(string.Format("ContentBase type {0} is not supported.", entity.GetType().FullName)); return new GuidUdi(type, entity.Key).EnsureClosed(); } @@ -237,7 +237,7 @@ namespace Umbraco.Core public static GuidUdi GetUdi(this IRelationType entity) { if (entity == null) throw new ArgumentNullException("entity"); - return new GuidUdi(Constants.DeployEntityType.RelationType, entity.Key).EnsureClosed(); + return new GuidUdi(Constants.UdiEntityType.RelationType, entity.Key).EnsureClosed(); } /// diff --git a/src/Umbraco.Core/UdiTypeConverter.cs b/src/Umbraco.Core/UdiTypeConverter.cs new file mode 100644 index 0000000000..110b899454 --- /dev/null +++ b/src/Umbraco.Core/UdiTypeConverter.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel; +using System.Globalization; + +namespace Umbraco.Core +{ + /// + /// A custom type converter for UDI + /// + /// + /// Primarily this is used so that WebApi can auto-bind a string parameter to a UDI instance + /// + internal class UdiTypeConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) + { + Udi udi; + if (Udi.TryParse((string)value, out udi)) + { + return udi; + } + } + return base.ConvertFrom(context, culture, value); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 800c0b8556..c5eadfb131 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -163,6 +163,7 @@ + @@ -289,7 +290,6 @@ - @@ -1439,9 +1439,11 @@ + + diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index b2f8ff9d73..4f1569ac7b 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -441,7 +441,7 @@ namespace Umbraco.Tests.Persistence.Repositories { // Act - var exists = repository.Exists(1034); //Content picker + var exists = repository.Exists(1046); //Content picker var doesntExist = repository.Exists(-80); // Assert diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index d517f81db3..893900677e 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -358,9 +358,9 @@ namespace Umbraco.Tests.TestHelpers.Entities contentCollection.Add(new PropertyType(Constants.PropertyEditors.DateAlias, DataTypeDatabaseType.Date) { Alias = "date", Name = "Date", Mandatory = false, SortOrder = 13, DataTypeDefinitionId = -41 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.DropDownListAlias, DataTypeDatabaseType.Integer) { Alias = "ddl", Name = "Dropdown List", Mandatory = false, SortOrder = 14, DataTypeDefinitionId = -42 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.CheckBoxListAlias, DataTypeDatabaseType.Nvarchar) { Alias = "chklist", Name = "Checkbox List", Mandatory = false, SortOrder = 15, DataTypeDefinitionId = -43 }); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.ContentPickerAlias, DataTypeDatabaseType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeDefinitionId = 1034 }); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.MediaPickerAlias, DataTypeDatabaseType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeDefinitionId = 1035 }); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.MemberPickerAlias, DataTypeDatabaseType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeDefinitionId = 1036 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.ContentPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeDefinitionId = 1046 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.MediaPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeDefinitionId = 1048 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.MemberPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeDefinitionId = 1047 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.RelatedLinksAlias, DataTypeDatabaseType.Ntext) { Alias = "relatedLinks", Name = "Related Links", Mandatory = false, SortOrder = 21, DataTypeDefinitionId = 1040 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.TagsAlias, DataTypeDatabaseType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeDefinitionId = 1041 }); diff --git a/src/Umbraco.Tests/UdiTests.cs b/src/Umbraco.Tests/UdiTests.cs index 36242bab13..9b803d5fa3 100644 --- a/src/Umbraco.Tests/UdiTests.cs +++ b/src/Umbraco.Tests/UdiTests.cs @@ -13,41 +13,41 @@ namespace Umbraco.Tests [Test] public void StringEntityCtorTest() { - var udi = new StringUdi(Constants.DeployEntityType.AnyString, "test-id"); - Assert.AreEqual(Constants.DeployEntityType.AnyString, udi.EntityType); + var udi = new StringUdi(Constants.UdiEntityType.AnyString, "test-id"); + Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType); Assert.AreEqual("test-id", udi.Id); - Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyString + "/test-id", udi.ToString()); + Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString()); } [Test] public void StringEntityParseTest() { - var udi = Udi.Parse("umb://" + Constants.DeployEntityType.AnyString + "/test-id"); - Assert.AreEqual(Constants.DeployEntityType.AnyString, udi.EntityType); + var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id"); + Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType); Assert.IsInstanceOf(udi); var stringEntityId = udi as StringUdi; Assert.IsNotNull(stringEntityId); Assert.AreEqual("test-id", stringEntityId.Id); - Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyString + "/test-id", udi.ToString()); + Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString()); } [Test] public void GuidEntityCtorTest() { var guid = Guid.NewGuid(); - var udi = new GuidUdi(Constants.DeployEntityType.AnyGuid, guid); - Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType); + var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid); + Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType); Assert.AreEqual(guid, udi.Guid); - Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyGuid + "/" + guid.ToString("N"), udi.ToString()); + Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N"), udi.ToString()); } [Test] public void GuidEntityParseTest() { var guid = Guid.NewGuid(); - var s = "umb://" + Constants.DeployEntityType.AnyGuid + "/" + guid.ToString("N"); + var s = "umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N"); var udi = Udi.Parse(s); - Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType); + Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType); Assert.IsInstanceOf(udi); var gudi = udi as GuidUdi; Assert.IsNotNull(gudi); @@ -82,9 +82,9 @@ namespace Umbraco.Tests var guid1 = Guid.NewGuid(); var entities = new[] { - new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1), - new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1), - new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1), + new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1), + new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1), + new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1), }; Assert.AreEqual(1, entities.Distinct().Count()); } @@ -93,12 +93,12 @@ namespace Umbraco.Tests public void CreateTest() { var guid = Guid.NewGuid(); - var udi = Udi.Create(Constants.DeployEntityType.AnyGuid, guid); - Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType); + var udi = Udi.Create(Constants.UdiEntityType.AnyGuid, guid); + Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType); Assert.AreEqual(guid, ((GuidUdi)udi).Guid); - Assert.Throws(() => Udi.Create(Constants.DeployEntityType.AnyString, guid)); - Assert.Throws(() => Udi.Create(Constants.DeployEntityType.AnyGuid, "foo")); + Assert.Throws(() => Udi.Create(Constants.UdiEntityType.AnyString, guid)); + Assert.Throws(() => Udi.Create(Constants.UdiEntityType.AnyGuid, "foo")); Assert.Throws(() => Udi.Create("barf", "foo")); } @@ -106,13 +106,13 @@ namespace Umbraco.Tests public void RangeTest() { // can parse open string udi - var stringUdiString = "umb://" + Constants.DeployEntityType.AnyString; + var stringUdiString = "umb://" + Constants.UdiEntityType.AnyString; Udi stringUdi; Assert.IsTrue(Udi.TryParse(stringUdiString, out stringUdi)); Assert.AreEqual(string.Empty, ((StringUdi)stringUdi).Id); // can parse open guid udi - var guidUdiString = "umb://" + Constants.DeployEntityType.AnyGuid; + var guidUdiString = "umb://" + Constants.UdiEntityType.AnyGuid; Udi guidUdi; Assert.IsTrue(Udi.TryParse(guidUdiString, out guidUdi)); Assert.AreEqual(Guid.Empty, ((GuidUdi)guidUdi).Guid); @@ -134,12 +134,12 @@ namespace Umbraco.Tests var guid = Guid.NewGuid(); - var udi = new GuidUdi(Constants.DeployEntityType.AnyGuid, guid); + var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid); var json = JsonConvert.SerializeObject(udi, settings); Assert.AreEqual(string.Format("\"umb://any-guid/{0:N}\"", guid), json); var dudi = JsonConvert.DeserializeObject(json, settings); - Assert.AreEqual(Constants.DeployEntityType.AnyGuid, dudi.EntityType); + Assert.AreEqual(Constants.UdiEntityType.AnyGuid, dudi.EntityType); Assert.AreEqual(guid, ((GuidUdi)dudi).Guid); var range = new UdiRange(udi, Constants.DeploySelector.ChildrenOfThis); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js index 5e0f5deada..3defb691aa 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js @@ -166,24 +166,17 @@ function entityResource($q, $http, umbRequestHelper) { */ getByIds: function (ids, type) { - var query = ""; - _.each(ids, function(item) { - query += "ids=" + item + "&"; - }); - - // if ids array is empty we need a empty variable in the querystring otherwise the service returns a error - if (ids.length === 0) { - query += "ids=&"; - } - - query += "type=" + type; + var query = "type=" + type; return umbRequestHelper.resourcePromise( - $http.get( + $http.post( umbRequestHelper.getApiUrl( "entityApiBaseUrl", "GetByIds", - query)), + query), + { + ids: ids + }), 'Failed to retrieve entity data for ids ' + ids); }, diff --git a/src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js index 02d5a62432..74d35201c2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js @@ -27,7 +27,8 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig description: preVals[i].description, label: preVals[i].label, view: preVals[i].view, - value: preVals[i].value + value: preVals[i].value, + config: preVals[i].config, }); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediapicker.controller.js index 38dd99c204..e5c09f420e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediapicker.controller.js @@ -13,9 +13,15 @@ function mediaPickerController($scope, dialogService, entityResource, $log, icon multiPicker: false, entityType: "Media", section: "media", - treeAlias: "media" + treeAlias: "media", + idType: "int" }; + //combine the dialogOptions with any values returned from the server + if ($scope.model.config) { + angular.extend(dialogOptions, $scope.model.config); + } + $scope.openContentPicker = function() { $scope.contentPickerOverlay = dialogOptions; $scope.contentPickerOverlay.view = "treePicker"; @@ -53,18 +59,21 @@ function mediaPickerController($scope, dialogService, entityResource, $log, icon }; $scope.add = function (item) { + + var itemId = dialogOptions.idType === "udi" ? item.udi : item.id; + var currIds = _.map($scope.renderModel, function (i) { - return i.id; + return dialogOptions.idType === "udi" ? i.udi : i.id; }); - if (currIds.indexOf(item.id) < 0) { + if (currIds.indexOf(itemId) < 0) { item.icon = iconHelper.convertFromLegacyIcon(item.icon); - $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); + $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon, udi: item.udi }); } }; var unsubscribe = $scope.$on("formSubmitting", function (ev, args) { var currIds = _.map($scope.renderModel, function (i) { - return i.id; + return dialogOptions.idType === "udi" ? i.udi : i.id; }); $scope.model.value = trim(currIds.join(), ","); }); @@ -76,12 +85,15 @@ function mediaPickerController($scope, dialogService, entityResource, $log, icon //load media data var modelIds = $scope.model.value ? $scope.model.value.split(',') : []; - entityResource.getByIds(modelIds, dialogOptions.entityType).then(function (data) { - _.each(data, function (item, i) { - item.icon = iconHelper.convertFromLegacyIcon(item.icon); - $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon }); + if (modelIds.length > 0) { + entityResource.getByIds(modelIds, dialogOptions.entityType).then(function (data) { + _.each(data, function (item, i) { + item.icon = iconHelper.convertFromLegacyIcon(item.icon); + $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon, udi: item.udi }); + }); }); - }); + } + } diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treepicker.controller.js index d2ff7bd778..cf81d1cda6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treepicker.controller.js @@ -12,26 +12,30 @@ angular.module('umbraco') multiPicker: false, entityType: "Document", type: "content", - treeAlias: "content" - }; + treeAlias: "content", + idType: "int" + }; + + //combine the config with any values returned from the server + if ($scope.model.config) { + angular.extend(config, $scope.model.config); + } if($scope.model.value){ $scope.ids = $scope.model.value.split(','); entityResource.getByIds($scope.ids, config.entityType).then(function (data) { _.each(data, function (item, i) { item.icon = iconHelper.convertFromLegacyIcon(item.icon); - $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); - }); + $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon, udi: item.udi }); + }); }); } $scope.openContentPicker = function() { - $scope.treePickerOverlay = {}; - $scope.treePickerOverlay.section = config.type; - $scope.treePickerOverlay.treeAlias = config.treeAlias; - $scope.treePickerOverlay.multiPicker = config.multiPicker; + $scope.treePickerOverlay = config; + $scope.treePickerOverlay.section = config.type; $scope.treePickerOverlay.view = "treePicker"; - $scope.treePickerOverlay.show = true; + $scope.treePickerOverlay.show = true; $scope.treePickerOverlay.submit = function(model) { @@ -64,12 +68,15 @@ angular.module('umbraco') $scope.ids = []; }; - $scope.add =function(item){ - if($scope.ids.indexOf(item.id) < 0){ + $scope.add = function (item) { + + var itemId = config.idType === "udi" ? item.udi : item.id; + + if ($scope.ids.indexOf(itemId) < 0){ item.icon = iconHelper.convertFromLegacyIcon(item.icon); - $scope.ids.push(item.id); - $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); + $scope.ids.push(itemId); + $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon, udi: item.udi}); $scope.model.value = trim($scope.ids.join(), ","); } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js index ff5e31b8eb..5a53e00e1c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js @@ -12,7 +12,12 @@ angular.module('umbraco') $scope.model.value = { type: "content" }; - } + } + if (!$scope.model.config) { + $scope.model.config = { + idType: "int" + }; + } if($scope.model.value.id && $scope.model.value.type !== "member"){ var ent = "Document"; @@ -29,7 +34,8 @@ angular.module('umbraco') $scope.openContentPicker =function(){ $scope.treePickerOverlay = { - view: "treepicker", + view: "treepicker", + idType: $scope.model.config.idType, section: $scope.model.value.type, treeAlias: $scope.model.value.type, multiPicker: false, @@ -67,6 +73,6 @@ angular.module('umbraco') $scope.clear(); item.icon = iconHelper.convertFromLegacyIcon(item.icon); $scope.node = item; - $scope.model.value.id = item.id; + $scope.model.value.id = $scope.model.config.idType === "udi" ? item.udi : item.id; } }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index 947603794a..471e97e875 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -17,11 +17,11 @@ function contentPickerController($scope, entityResource, editorState, iconHelper $scope.$watch(function () { //return the joined Ids as a string to watch return _.map($scope.renderModel, function (i) { - return i.id; + return $scope.model.config.idType === "udi" ? i.udi : i.id; }).join(); }, function (newVal) { var currIds = _.map($scope.renderModel, function (i) { - return i.id; + return $scope.model.config.idType === "udi" ? i.udi : i.id; }); $scope.model.value = trim(currIds.join(), ","); @@ -58,7 +58,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper startNode: { query: "", type: "content", - id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1 // get start node for simple Content Picker + id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1 // get start node for simple Content Picker } }; @@ -105,10 +105,11 @@ function contentPickerController($scope, entityResource, editorState, iconHelper $scope.clear(); $scope.add(data); } - angularHelper.getCurrentForm($scope).$setDirty(); + angularHelper.getCurrentForm($scope).$setDirty(); }, treeAlias: $scope.model.config.startNode.type, - section: $scope.model.config.startNode.type + section: $scope.model.config.startNode.type, + idType: "int" }; //since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the @@ -147,9 +148,10 @@ function contentPickerController($scope, entityResource, editorState, iconHelper if ($scope.model.config.startNode.query) { var rootId = $routeParams.id; entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) { - dialogOptions.startNodeId = ent.id; + dialogOptions.startNodeId = $scope.model.config.idType === "udi" ? ent.udi : ent.id; }); - } else { + } + else { dialogOptions.startNodeId = $scope.model.config.startNode.id; } @@ -200,10 +202,12 @@ function contentPickerController($scope, entityResource, editorState, iconHelper $scope.add = function (item) { var currIds = _.map($scope.renderModel, function (i) { - return i.id; + return $scope.model.config.idType === "udi" ? i.udi : i.id; }); - if (currIds.indexOf(item.id) < 0) { + var itemId = $scope.model.config.idType === "udi" ? item.udi : item.id; + + if (currIds.indexOf(itemId) < 0) { setEntityUrl(item); } }; @@ -227,7 +231,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper var unsubscribe = $scope.$on("formSubmitting", function (ev, args) { var currIds = _.map($scope.renderModel, function (i) { - return i.id; + return $scope.model.config.idType === "udi" ? i.udi : i.id; }); $scope.model.value = trim(currIds.join(), ","); }); @@ -237,26 +241,36 @@ function contentPickerController($scope, entityResource, editorState, iconHelper unsubscribe(); }); - //load current data + var modelIds = $scope.model.value ? $scope.model.value.split(',') : []; - entityResource.getByIds(modelIds, entityType).then(function (data) { + //load current data if anything selected + if (modelIds.length > 0) { + entityResource.getByIds(modelIds, entityType).then(function(data) { - _.each(modelIds, function (id, i) { - var entity = _.find(data, function (d) { - return d.id == id; - }); - - if (entity) { - setEntityUrl(entity); - } - - }); + _.each(modelIds, + function(id, i) { + var entity = _.find(data, + function(d) { + return $scope.model.config.idType === "udi" ? (d.udi == id) : (d.id == id); + }); + if (entity) { + setEntityUrl(entity); + } + + }); + + //everything is loaded, start the watch on the model + startWatch(); + + }); + } + else { //everything is loaded, start the watch on the model startWatch(); - - }); + } + function setEntityUrl(entity) { @@ -304,6 +318,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper $scope.renderModel.push({ "name": item.name, "id": item.id, + "udi": item.udi, "icon": item.icon, "path": item.path, "url": item.url, diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js index bbf61a32d3..dafe6cc3c7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js @@ -40,7 +40,13 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl } $scope.images.push(media); - $scope.ids.push(media.id); + + if ($scope.model.config.idType === "udi") { + $scope.ids.push(media.udi); + } + else { + $scope.ids.push(media.id); + } } }); @@ -80,7 +86,13 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl } $scope.images.push(media); - $scope.ids.push(media.id); + + if ($scope.model.config.idType === "udi") { + $scope.ids.push(media.udi); + } + else { + $scope.ids.push(media.id); + } }); $scope.sync(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js index 0029332f64..efa05ae882 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/memberpicker/memberpicker.controller.js @@ -68,12 +68,19 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico $scope.add = function (item) { var currIds = _.map($scope.renderModel, function (i) { - return i.id; + if ($scope.model.config.idType === "udi") { + return i.udi; + } + else { + return i.id; + } }); - if (currIds.indexOf(item.id) < 0) { + var itemId = $scope.model.config.idType === "udi" ? item.udi : item.id; + + if (currIds.indexOf(itemId) < 0) { item.icon = iconHelper.convertFromLegacyIcon(item.icon); - $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); + $scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon}); } }; @@ -83,7 +90,12 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico var unsubscribe = $scope.$on("formSubmitting", function (ev, args) { var currIds = _.map($scope.renderModel, function (i) { - return i.id; + if ($scope.model.config.idType === "udi") { + return i.udi; + } + else { + return i.id; + } }); $scope.model.value = trim(currIds.join(), ","); }); @@ -99,7 +111,7 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico _.each(data, function (item, i) { // set default icon if it's missing item.icon = (item.icon) ? iconHelper.convertFromLegacyIcon(item.icon) : "icon-user"; - $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon }); + $scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon }); }); }); } diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index 9eb3f135e9..cc71b26b70 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -104,7 +104,8 @@ Textstring - + + true diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 104c451273..81dc5d8722 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.Net; using System.Text; @@ -29,6 +30,7 @@ using Examine.SearchCriteria; using Umbraco.Web.Dynamics; using umbraco; using System.Text.RegularExpressions; +using System.Web.Http.Controllers; using Umbraco.Core.Xml; namespace Umbraco.Web.Editors @@ -43,6 +45,20 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class EntityController : UmbracoAuthorizedJsonController { + + /// + /// Configures this controller with a custom action selector + /// + private class EntityControllerConfigurationAttribute : Attribute, IControllerConfiguration + { + public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) + { + controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector( + new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)), + new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetByIds", "ids", typeof(int[]), typeof(Guid[]), typeof(Udi[])))); + } + } + /// /// Returns an Umbraco alias given a string /// @@ -144,9 +160,7 @@ namespace Umbraco.Web.Editors return foundContent.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse); } - - - + /// /// Gets the url of an entity /// @@ -185,13 +199,9 @@ namespace Umbraco.Web.Editors Content = new StringContent(returnUrl) }; } - - /// - /// Gets an entity by it's unique id if the entity supports that - /// - /// - /// - /// + + [Obsolete("Use GetyById instead")] + [EditorBrowsable(EditorBrowsableState.Never)] public EntityBasic GetByKey(Guid id, UmbracoEntityTypes type) { return GetResultForKey(id, type); @@ -235,13 +245,61 @@ namespace Umbraco.Web.Editors }, publishedContentExists: i => Umbraco.TypedContent(i) != null); } - + + #region GetById + + /// + /// Gets an entity by it's id + /// + /// + /// + /// public EntityBasic GetById(int id, UmbracoEntityTypes type) { return GetResultForId(id, type); } - public IEnumerable GetByIds([FromUri]int[] ids, UmbracoEntityTypes type) + /// + /// Gets an entity by it's key + /// + /// + /// + /// + public EntityBasic GetById(Guid id, UmbracoEntityTypes type) + { + return GetResultForKey(id, type); + } + + /// + /// Gets an entity by it's UDI + /// + /// + /// + /// + public EntityBasic GetById(Udi id, UmbracoEntityTypes type) + { + var guidUdi = id as GuidUdi; + if (guidUdi != null) + { + return GetResultForKey(guidUdi.Guid, type); + } + throw new HttpResponseException(HttpStatusCode.NotFound); + } + #endregion + + #region GetByIds + /// + /// Get entities by integer ids + /// + /// + /// + /// + /// + /// We allow for POST because there could be quite a lot of Ids + /// + [HttpGet] + [HttpPost] + public IEnumerable GetByIds([FromJsonPath]int[] ids, UmbracoEntityTypes type) { if (ids == null) { @@ -250,6 +308,66 @@ namespace Umbraco.Web.Editors return GetResultForIds(ids, type); } + /// + /// Get entities by GUID ids + /// + /// + /// + /// + /// + /// We allow for POST because there could be quite a lot of Ids + /// + [HttpGet] + [HttpPost] + public IEnumerable GetByIds([FromJsonPath]Guid[] ids, UmbracoEntityTypes type) + { + if (ids == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + return GetResultForKeys(ids, type); + } + + /// + /// Get entities by UDIs + /// + /// + /// A list of UDIs to lookup items by, all UDIs must be of the same UDI type! + /// + /// + /// + /// + /// We allow for POST because there could be quite a lot of Ids. + /// + [HttpGet] + [HttpPost] + public IEnumerable GetByIds([FromJsonPath]Udi[] ids, [FromUri]UmbracoEntityTypes type) + { + if (ids == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + if (ids.Length == 0) + { + return Enumerable.Empty(); + } + + //all udi types will need to be the same in this list so we'll determine by the first + //currently we only support GuidIdi for this method + + var guidUdi = ids[0] as GuidUdi; + if (guidUdi != null) + { + return GetResultForKeys(ids.Select(x => ((GuidUdi)x).Guid).ToArray(), type); + } + + throw new HttpResponseException(HttpStatusCode.NotFound); + } + #endregion + + [Obsolete("Use GetyByIds instead")] + [EditorBrowsable(EditorBrowsableState.Never)] public IEnumerable GetByKeys([FromUri]Guid[] ids, UmbracoEntityTypes type) { if (ids == null) @@ -643,21 +761,21 @@ namespace Umbraco.Web.Editors } } - private IEnumerable GetResultForKeys(IEnumerable keys, UmbracoEntityTypes entityType) + private IEnumerable GetResultForKeys(Guid[] keys, UmbracoEntityTypes entityType) { - var keysArray = keys.ToArray(); - if (keysArray.Any() == false) return Enumerable.Empty(); + if (keys.Length == 0) + return Enumerable.Empty(); var objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var entities = Services.EntityService.GetAll(objectType.Value, keysArray) + var entities = Services.EntityService.GetAll(objectType.Value, keys) .WhereNotNull() .Select(Mapper.Map); // entities are in "some" order, put them back in order var xref = entities.ToDictionary(x => x.Key); - var result = keysArray.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null); + var result = keys.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null); return result; } @@ -675,21 +793,21 @@ namespace Umbraco.Web.Editors } } - private IEnumerable GetResultForIds(IEnumerable ids, UmbracoEntityTypes entityType) + private IEnumerable GetResultForIds(int[] ids, UmbracoEntityTypes entityType) { - var idsArray = ids.ToArray(); - if (idsArray.Any() == false) return Enumerable.Empty(); + if (ids.Length == 0) + return Enumerable.Empty(); var objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var entities = Services.EntityService.GetAll(objectType.Value, idsArray) + var entities = Services.EntityService.GetAll(objectType.Value, ids) .WhereNotNull() .Select(Mapper.Map); // entities are in "some" order, put them back in order var xref = entities.ToDictionary(x => x.Id); - var result = idsArray.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null); + var result = ids.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null); return result; } diff --git a/src/Umbraco.Web/Editors/EntityControllerActionSelector.cs b/src/Umbraco.Web/Editors/EntityControllerActionSelector.cs deleted file mode 100644 index 9cfab1bdcd..0000000000 --- a/src/Umbraco.Web/Editors/EntityControllerActionSelector.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Web; -using System.Web.Http.Controllers; -using Umbraco.Core; - -namespace Umbraco.Web.Editors -{ - /// - /// This allows for calling GetById/GetByIds with a GUID... so it will automatically route to GetByKey/GetByKeys - /// - internal class EntityControllerActionSelector : ApiControllerActionSelector - { - - public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) - { - if (controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Path).InvariantEndsWith("GetById")) - { - var id = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).Get("id"); - - if (id != null) - { - Guid parsed; - if (Guid.TryParse(id, out parsed)) - { - var controllerType = controllerContext.Controller.GetType(); - var method = controllerType.GetMethod("GetByKey"); - if (method != null) - { - return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method); - } - } - } - } - - if (controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Path).InvariantEndsWith("GetByIds")) - { - var ids = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).GetValues("ids"); - - if (ids != null) - { - var allmatched = true; - foreach (var id in ids) - { - Guid parsed; - if (Guid.TryParse(id, out parsed) == false) - { - allmatched = false; - } - } - if (allmatched) - { - var controllerType = controllerContext.Controller.GetType(); - var method = controllerType.GetMethod("GetByKeys"); - if (method != null) - { - return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method); - } - } - } - } - - - - return base.SelectAction(controllerContext); - } - - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/EntityControllerConfigurationAttribute.cs b/src/Umbraco.Web/Editors/EntityControllerConfigurationAttribute.cs index 7ef4ef206a..571b29ed01 100644 --- a/src/Umbraco.Web/Editors/EntityControllerConfigurationAttribute.cs +++ b/src/Umbraco.Web/Editors/EntityControllerConfigurationAttribute.cs @@ -4,18 +4,5 @@ using Umbraco.Web.WebApi; namespace Umbraco.Web.Editors { - /// - /// This get's applied to the EntityController in order to have a custom IHttpActionSelector assigned to it - /// - /// - /// NOTE: It is SOOOO important to remember that you cannot just assign this in the 'initialize' method of a webapi - /// controller as it will assign it GLOBALLY which is what you def do not want to do. - /// - internal class EntityControllerConfigurationAttribute : Attribute, IControllerConfiguration - { - public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) - { - controllerSettings.Services.Replace(typeof(IHttpActionSelector), new EntityControllerActionSelector()); - } - } + } \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/FromJsonPathAttribute.cs b/src/Umbraco.Web/Editors/FromJsonPathAttribute.cs new file mode 100644 index 0000000000..bb275f8fa2 --- /dev/null +++ b/src/Umbraco.Web/Editors/FromJsonPathAttribute.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.ModelBinding; +using System.Web.Http.ValueProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; + +namespace Umbraco.Web.Editors +{ + /// + /// Used to bind a value from an inner json property + /// + /// + /// An example would be if you had json like: + /// { ids: [1,2,3,4] } + /// + /// And you had an action like: GetByIds(int[] ids, UmbracoEntityTypes type) + /// + /// The ids array will not bind because the object being sent up is an object and not an array so the + /// normal json formatter will not figure this out. + /// + /// This would also let you bind sub levels of the JSON being sent up too if you wanted with any jsonpath + /// + internal class FromJsonPathAttribute : ModelBinderAttribute + { + private readonly string _jsonPath; + private readonly FromUriAttribute _fromUriAttribute = new FromUriAttribute(); + + public FromJsonPathAttribute() + { + } + + public FromJsonPathAttribute(string jsonPath) : base(typeof(JsonPathBinder)) + { + _jsonPath = jsonPath; + } + + public override IEnumerable GetValueProviderFactories(HttpConfiguration configuration) + { + return _fromUriAttribute.GetValueProviderFactories(configuration); + } + + public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter) + { + var config = parameter.Configuration; + //get the default binder, we'll use that if it's a GET or if the body is empty + var underlyingBinder = base.GetModelBinder(config, parameter.ParameterType); + var binder = new JsonPathBinder(underlyingBinder, _jsonPath); + var valueProviderFactories = GetValueProviderFactories(config); + + return new ModelBinderParameterBinding(parameter, binder, valueProviderFactories); + } + + private class JsonPathBinder : IModelBinder + { + private readonly IModelBinder _underlyingBinder; + private readonly string _jsonPath; + + public JsonPathBinder(IModelBinder underlyingBinder, string jsonPath) + { + _underlyingBinder = underlyingBinder; + _jsonPath = jsonPath; + } + + public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) + { + if (actionContext.Request.Method == HttpMethod.Get) + { + return _underlyingBinder.BindModel(actionContext, bindingContext); + } + + var requestContent = new HttpMessageContent(actionContext.Request); + var strJson = requestContent.HttpRequestMessage.Content.ReadAsStringAsync().Result; + + if (strJson.IsNullOrWhiteSpace()) + { + return _underlyingBinder.BindModel(actionContext, bindingContext); + } + + var json = JsonConvert.DeserializeObject(strJson); + + //if no explicit json path then use the model name + var match = json.SelectToken(_jsonPath ?? bindingContext.ModelName); + + if (match == null) + { + return false; + } + + bindingContext.Model = match.ToObject(bindingContext.ModelType); + + return true; + } + } + + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 77ab9ff6e5..0e191954d6 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -59,7 +59,7 @@ namespace Umbraco.Web.Editors public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) { controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector( - new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetChildren", "id", typeof(int), typeof(Guid), typeof(string)))); + new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetChildren", "id", typeof(int), typeof(Guid), typeof(Udi), typeof(string)))); } } @@ -187,6 +187,7 @@ namespace Umbraco.Web.Editors .Select(Mapper.Map>); } + #region GetChildren /// /// Returns the child media objects - using the entity INT id /// @@ -244,7 +245,7 @@ namespace Umbraco.Web.Editors Direction orderDirection = Direction.Ascending, bool orderBySystemField = true, string filter = "") - { + { var entity = Services.EntityService.GetByKey(id); if (entity != null) { @@ -253,6 +254,39 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } + /// + /// Returns the child media objects - using the entity UDI id + /// + /// + /// + /// + /// + /// + /// + /// + /// + [FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")] + public PagedResult> GetChildren(Udi id, + int pageNumber = 0, + int pageSize = 0, + string orderBy = "SortOrder", + Direction orderDirection = Direction.Ascending, + bool orderBySystemField = true, + string filter = "") + { + var guidUdi = id as GuidUdi; + if (guidUdi != null) + { + var entity = Services.EntityService.GetByKey(guidUdi.Guid); + if (entity != null) + { + return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter); + } + } + + throw new HttpResponseException(HttpStatusCode.NotFound); + } + [Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")] [EditorBrowsable(EditorBrowsableState.Never)] [UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)] @@ -275,7 +309,8 @@ namespace Umbraco.Web.Editors } throw new HttpResponseException(HttpStatusCode.NotFound); - } + } + #endregion /// /// Moves an item to the recycle bin, if it is already there then it will permanently delete it diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index db2a806572..879ffd3d0a 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -40,7 +40,7 @@ namespace Umbraco.Web.Editors public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) { controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector( - new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetAllowedChildren", "contentId", typeof(int), typeof(Guid), typeof(string)))); + new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetAllowedChildren", "contentId", typeof(int), typeof(Guid), typeof(Udi), typeof(string)))); } } @@ -187,6 +187,7 @@ namespace Umbraco.Web.Editors } + #region GetAllowedChildren /// /// Returns the allowed child content type objects for the content item id passed in - based on an INT id /// @@ -247,10 +248,30 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - - [Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")] + + /// + /// Returns the allowed child content type objects for the content item id passed in - based on a UDI id + /// + /// + [UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)] + public IEnumerable GetAllowedChildren(Udi contentId) + { + var guidUdi = contentId as GuidUdi; + if (guidUdi != null) + { + var entity = ApplicationContext.Services.EntityService.GetByKey(guidUdi.Guid); + if (entity != null) + { + return GetAllowedChildren(entity.Id); + } + } + + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + [Obsolete("Do not use this method, use either the overload with INT, GUID or UDI instead, this will be removed in future versions")] [EditorBrowsable(EditorBrowsableState.Never)] - [UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)] + [UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)] public IEnumerable GetAllowedChildren(string contentId) { foreach (var type in new[] { typeof(int), typeof(Guid) }) @@ -260,11 +281,12 @@ namespace Umbraco.Web.Editors { //oooh magic! will auto select the right overload return GetAllowedChildren((dynamic)parsed.Result); - } + } } throw new HttpResponseException(HttpStatusCode.NotFound); - } + } + #endregion /// /// Move the media type diff --git a/src/Umbraco.Web/Editors/ParameterSwapControllerActionSelector.cs b/src/Umbraco.Web/Editors/ParameterSwapControllerActionSelector.cs index 7f17fb9f8b..53e25c146a 100644 --- a/src/Umbraco.Web/Editors/ParameterSwapControllerActionSelector.cs +++ b/src/Umbraco.Web/Editors/ParameterSwapControllerActionSelector.cs @@ -1,7 +1,15 @@ using System; +using System.Collections; using System.Linq; +using System.Net.Http; +using System.Net.Http.Formatting; using System.Web; +using System.Web.Http; using System.Web.Http.Controllers; +using System.Web.Http.Validation; +using System.Web.Http.ValueProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Umbraco.Core; namespace Umbraco.Web.Editors @@ -12,6 +20,8 @@ namespace Umbraco.Web.Editors /// /// As an example, lets say we have 2 methods: GetChildren(int id) and GetChildren(Guid id), by default Web Api won't allow this since /// it won't know what to select, but if this Tuple is passed in new Tuple{string, string}("GetChildren", "id") + /// + /// This supports POST values too however only for JSON values /// internal class ParameterSwapControllerActionSelector : ApiControllerActionSelector { @@ -25,33 +35,102 @@ namespace Umbraco.Web.Editors { _actions = actions; } + public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) { var found = _actions.FirstOrDefault(x => controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Path).InvariantEndsWith(x.ActionName)); if (found != null) { - var id = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).Get(found.ParamName); - - if (id != null) + HttpActionDescriptor method; + if (TryBindFromUri(controllerContext, found, out method)) { - var idTypes = found.SupportedTypes; + return method; + } - foreach (var idType in idTypes) + //if it's a post we can try to read from the body and bind from the json value + if (controllerContext.Request.Method == HttpMethod.Post) + { + var requestContent = new HttpMessageContent(controllerContext.Request); + var strJson = requestContent.HttpRequestMessage.Content.ReadAsStringAsync().Result; + var json = JsonConvert.DeserializeObject(strJson); + + if (json == null) { - var converted = id.TryConvertTo(idType); - if (converted) + return base.SelectAction(controllerContext); + } + + var requestParam = json[found.ParamName]; + + if (requestParam != null) + { + var paramTypes = found.SupportedTypes; + + foreach (var paramType in paramTypes) { - var method = MatchByType(idType, controllerContext, found); - if (method != null) - return method; + try + { + var converted = requestParam.ToObject(paramType); + if (converted != null) + { + method = MatchByType(paramType, controllerContext, found); + if (method != null) + return method; + } + } + catch (JsonReaderException) + { + //can't convert + } + catch (JsonSerializationException) + { + //can't convert + } } - } + } } } return base.SelectAction(controllerContext); } + private bool TryBindFromUri(HttpControllerContext controllerContext, ParameterSwapInfo found, out HttpActionDescriptor method) + { + var requestParam = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).Get(found.ParamName); + + requestParam = (requestParam == null) ? null : requestParam.Trim(); + var paramTypes = found.SupportedTypes; + + if (requestParam == string.Empty && paramTypes.Length > 0) + { + //if it's empty then in theory we can select any of the actions since they'll all need to deal with empty or null parameters + //so we'll try to use the first one available + method = MatchByType(paramTypes[0], controllerContext, found); + if (method != null) + return true; + } + + if (requestParam != null) + { + foreach (var paramType in paramTypes) + { + //check if this is IEnumerable and if so this will get it's type + //we need to know this since the requestParam will always just be a string + var enumType = paramType.GetEnumeratedType(); + + var converted = requestParam.TryConvertTo(enumType ?? paramType); + if (converted) + { + method = MatchByType(paramType, controllerContext, found); + if (method != null) + return true; + } + } + } + + method = null; + return false; + } + private static ReflectedHttpActionDescriptor MatchByType(Type idType, HttpControllerContext controllerContext, ParameterSwapInfo found) { var controllerType = controllerContext.Controller.GetType(); diff --git a/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs b/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs index 40d884d653..9f6e5b28da 100644 --- a/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs @@ -6,7 +6,10 @@ using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; +using Umbraco.Core; using Umbraco.Core.Models.Validation; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Models.ContentEditing { @@ -25,7 +28,12 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "id", IsRequired = true)] [Required] public object Id { get; set; } - + + [DataMember(Name = "udi")] + [ReadOnly(true)] + [JsonConverter(typeof(UdiJsonConverter))] + public Udi Udi { get; set; } + [DataMember(Name = "icon")] public string Icon { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs index 1e8a7ba088..6879701bde 100644 --- a/src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs @@ -1,4 +1,5 @@ -using System.Runtime.Serialization; +using System.Collections.Generic; +using System.Runtime.Serialization; namespace Umbraco.Web.Models.ContentEditing { @@ -33,5 +34,11 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "view", IsRequired = true)] public string View { get; set; } + /// + /// This allows for custom configuration to be injected into the pre-value editor + /// + [DataMember(Name = "config")] + public IDictionary Config { get; set; } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/AvailablePropertyEditorsResolver.cs b/src/Umbraco.Web/Models/Mapping/AvailablePropertyEditorsResolver.cs index 624c641d3b..2b9047c284 100644 --- a/src/Umbraco.Web/Models/Mapping/AvailablePropertyEditorsResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/AvailablePropertyEditorsResolver.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using AutoMapper; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Models.ContentEditing; @@ -10,9 +11,22 @@ namespace Umbraco.Web.Models.Mapping { internal class AvailablePropertyEditorsResolver : ValueResolver> { + private readonly IContentSection _contentSection; + + public AvailablePropertyEditorsResolver(IContentSection contentSection) + { + _contentSection = contentSection; + } + protected override IEnumerable ResolveCore(IDataTypeDefinition source) { return PropertyEditorResolver.Current.PropertyEditors + .Where(x => + { + if (_contentSection.ShowDeprecatedPropertyEditors) + return true; + return source.PropertyEditorAlias == x.Alias || x.IsDeprecated == false; + }) .OrderBy(x => x.Name) .Select(Mapper.Map); } diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 18b03ba076..6f23ecee0f 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -28,6 +28,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IContent TO ContentItemDisplay config.CreateMap() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Document, content.Key))) .ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(display => display.Updater, expression => expression.ResolveUsing(new CreatorResolver())) .ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) @@ -58,6 +59,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IContent TO ContentItemBasic config.CreateMap>() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Document, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.Updater, expression => expression.ResolveUsing(new CreatorResolver())) .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) @@ -68,6 +70,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IContent TO ContentItemDto config.CreateMap>() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Document, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.HasPublishedVersion, expression => expression.MapFrom(content => content.HasPublishedVersion)) .ForMember(dto => dto.Updater, expression => expression.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs index bf0ec1f457..de5b5a14fd 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs @@ -161,9 +161,12 @@ namespace Umbraco.Web.Models.Mapping }); - config.CreateMap(); - config.CreateMap(); - config.CreateMap(); + config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.MemberType, content.Key))); + config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.MediaType, content.Key))); + config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.DocumentType, content.Key))); config.CreateMap() diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs index 52f2dbad4b..cd42c87a56 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs @@ -126,6 +126,7 @@ namespace Umbraco.Web.Models.Mapping where TPropertyTypeDisplay : PropertyTypeDisplay, new() { return mapping + .ForMember(x => x.Udi, expression => expression.ResolveUsing(new ContentTypeUdiResolver())) .ForMember(display => display.Notifications, expression => expression.Ignore()) .ForMember(display => display.Errors, expression => expression.Ignore()) .ForMember(display => display.AllowAsRoot, expression => expression.MapFrom(type => type.AllowedAsRoot)) diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeUdiResolver.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeUdiResolver.cs new file mode 100644 index 0000000000..2d33b17155 --- /dev/null +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeUdiResolver.cs @@ -0,0 +1,23 @@ +using AutoMapper; +using Umbraco.Core; +using Umbraco.Core.Models; + +namespace Umbraco.Web.Models.Mapping +{ + /// + /// Resolves a UDI for a content type based on it's type + /// + internal class ContentTypeUdiResolver : ValueResolver + { + protected override Udi ResolveCore(IContentTypeComposition source) + { + if (source == null) return null; + + return Udi.Create( + source.GetType() == typeof(IMemberType) + ? Constants.UdiEntityType.MemberType + : source.GetType() == typeof(IMediaType) + ? Constants.UdiEntityType.MediaType : Constants.UdiEntityType.DocumentType, source.Key); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs index ac2faa82dc..e78aeaf6a3 100644 --- a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using AutoMapper; using System.Linq; using Umbraco.Core; +using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; using Umbraco.Core.PropertyEditors; @@ -34,6 +35,7 @@ namespace Umbraco.Web.Models.Mapping }; config.CreateMap() + .ForMember(x => x.Udi, expression => expression.Ignore()) .ForMember(x => x.HasPrevalues, expression => expression.Ignore()) .ForMember(x => x.IsSystemDataType, expression => expression.Ignore()) .ForMember(x => x.Id, expression => expression.Ignore()) @@ -44,6 +46,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.AdditionalData, expression => expression.Ignore()); config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.DataType, content.Key))) .ForMember(x => x.HasPrevalues, expression => expression.Ignore()) .ForMember(x => x.Icon, expression => expression.Ignore()) .ForMember(x => x.Alias, expression => expression.Ignore()) @@ -61,7 +64,8 @@ namespace Umbraco.Web.Models.Mapping }); config.CreateMap() - .ForMember(display => display.AvailableEditors, expression => expression.ResolveUsing(new AvailablePropertyEditorsResolver())) + .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.DataType, content.Key))) + .ForMember(display => display.AvailableEditors, expression => expression.ResolveUsing(new AvailablePropertyEditorsResolver(UmbracoConfig.For.UmbracoSettings().Content))) .ForMember(display => display.PreValues, expression => expression.ResolveUsing( new PreValueDisplayResolver(lazyDataTypeService))) .ForMember(display => display.SelectedEditor, expression => expression.MapFrom( diff --git a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs index 5610a70008..cd6b9b9f83 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using AutoMapper; using Examine; +using Examine.LuceneEngine.Providers; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -17,11 +18,13 @@ namespace Umbraco.Web.Models.Mapping public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext) { config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key))) .ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon)) .ForMember(dto => dto.Trashed, expression => expression.Ignore()) .ForMember(x => x.Alias, expression => expression.Ignore()); config.CreateMap() + .ForMember(x => x.Udi, expression => expression.Ignore()) .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-box")) .ForMember(basic => basic.Path, expression => expression.UseValue("")) .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) @@ -29,6 +32,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.AdditionalData, expression => expression.Ignore()); config.CreateMap() + .ForMember(x => x.Udi, expression => expression.Ignore()) .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-tab")) .ForMember(basic => basic.Path, expression => expression.UseValue("")) .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) @@ -38,6 +42,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.AdditionalData, expression => expression.Ignore()); config.CreateMap() + .ForMember(x => x.Udi, expression => expression.Ignore()) .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-user")) .ForMember(basic => basic.Path, expression => expression.UseValue("")) .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) @@ -46,6 +51,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.AdditionalData, expression => expression.Ignore()); config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(Constants.UdiEntityType.Template, x.Key))) .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-layout")) .ForMember(basic => basic.Path, expression => expression.MapFrom(template => template.Path)) .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) @@ -70,6 +76,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.SortOrder, expression => expression.Ignore()); config.CreateMap() + .ForMember(x => x.Udi, expression => expression.ResolveUsing(new ContentTypeUdiResolver())) .ForMember(basic => basic.Path, expression => expression.MapFrom(x => x.Path)) .ForMember(basic => basic.ParentId, expression => expression.MapFrom(x => x.ParentId)) .ForMember(dto => dto.Trashed, expression => expression.Ignore()) @@ -77,6 +84,7 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() //default to document icon + .ForMember(x => x.Udi, expression => expression.Ignore()) .ForMember(x => x.Icon, expression => expression.Ignore()) .ForMember(x => x.Id, expression => expression.MapFrom(result => result.Id)) .ForMember(x => x.Name, expression => expression.Ignore()) @@ -87,21 +95,40 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dto => dto.Trashed, expression => expression.Ignore()) .ForMember(x => x.AdditionalData, expression => expression.Ignore()) .AfterMap((result, basic) => - { + { + //get the icon if there is one basic.Icon = result.Fields.ContainsKey(UmbracoContentIndexer.IconFieldName) ? result.Fields[UmbracoContentIndexer.IconFieldName] : "icon-document"; basic.Name = result.Fields.ContainsKey("nodeName") ? result.Fields["nodeName"] : "[no name]"; - if (result.Fields.ContainsKey("__NodeKey")) + if (result.Fields.ContainsKey(UmbracoContentIndexer.NodeKeyFieldName)) { Guid key; - if (Guid.TryParse(result.Fields["__NodeKey"], out key)) + if (Guid.TryParse(result.Fields[UmbracoContentIndexer.NodeKeyFieldName], out key)) { basic.Key = key; + + //need to set the UDI + if (result.Fields.ContainsKey(LuceneIndexer.IndexTypeFieldName)) + { + switch (result.Fields[LuceneIndexer.IndexTypeFieldName]) + { + case IndexTypes.Member: + basic.Udi = new GuidUdi(Constants.UdiEntityType.Member, basic.Key); + break; + case IndexTypes.Content: + basic.Udi = new GuidUdi(Constants.UdiEntityType.Document, basic.Key); + break; + case IndexTypes.Media: + basic.Udi = new GuidUdi(Constants.UdiEntityType.Media, basic.Key); + break; + } + } } } + if (result.Fields.ContainsKey("parentID")) { int parentId; @@ -114,7 +141,7 @@ namespace Umbraco.Web.Models.Mapping basic.ParentId = -1; } } - basic.Path = result.Fields.ContainsKey("__Path") ? result.Fields["__Path"] : ""; + basic.Path = result.Fields.ContainsKey(UmbracoContentIndexer.IndexPathFieldName) ? result.Fields[UmbracoContentIndexer.IndexPathFieldName] : ""; if (result.Fields.ContainsKey(UmbracoContentIndexer.NodeTypeAliasFieldName)) { diff --git a/src/Umbraco.Web/Models/Mapping/MacroModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MacroModelMapper.cs index 54ebca6e68..3dc86e61c9 100644 --- a/src/Umbraco.Web/Models/Mapping/MacroModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MacroModelMapper.cs @@ -20,6 +20,7 @@ namespace Umbraco.Web.Models.Mapping { //FROM IMacro TO EntityBasic config.CreateMap() + .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Macro, content.Key))) .ForMember(entityBasic => entityBasic.Icon, expression => expression.UseValue("icon-settings-alt")) .ForMember(dto => dto.ParentId, expression => expression.UseValue(-1)) .ForMember(dto => dto.Path, expression => expression.ResolveUsing(macro => "-1," + macro.Id)) diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index b8aaef3e33..453e1567ab 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -25,6 +25,7 @@ namespace Umbraco.Web.Models.Mapping { //FROM IMedia TO MediaItemDisplay config.CreateMap() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Media, content.Key))) .ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) .ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) @@ -45,6 +46,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IMedia TO ContentItemBasic config.CreateMap>() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Media, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) .ForMember(dto => dto.Trashed, expression => expression.MapFrom(content => content.Trashed)) @@ -56,6 +58,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IMedia TO ContentItemDto config.CreateMap>() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Media, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.Published, expression => expression.Ignore()) .ForMember(dto => dto.Updater, expression => expression.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs index 0536efd307..3982302906 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs @@ -61,6 +61,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO MediaItemDisplay config.CreateMap() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) .ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) .ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) @@ -84,6 +85,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO MemberBasic config.CreateMap() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) .ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) @@ -96,9 +98,10 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()); //FROM MembershipUser TO MemberBasic - config.CreateMap() + config.CreateMap() //we're giving this entity an ID of 0 - we cannot really map it but it needs an id so the system knows it's not a new entity .ForMember(member => member.Id, expression => expression.MapFrom(user => int.MaxValue)) + .ForMember(display => display.Udi, expression => expression.Ignore()) .ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate)) .ForMember(member => member.UpdateDate, expression => expression.MapFrom(user => user.LastActivityDate)) .ForMember(member => member.Key, expression => expression.MapFrom(user => user.ProviderUserKey.TryConvertTo().Result.ToString("N"))) @@ -121,6 +124,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO ContentItemDto config.CreateMap>() + .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.Published, expression => expression.Ignore()) .ForMember(dto => dto.Updater, expression => expression.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/OwnerResolver.cs b/src/Umbraco.Web/Models/Mapping/OwnerResolver.cs index 5f3697c3d5..067d495591 100644 --- a/src/Umbraco.Web/Models/Mapping/OwnerResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/OwnerResolver.cs @@ -1,5 +1,6 @@ using AutoMapper; using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Web.Models.ContentEditing; diff --git a/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs index be10cd83e2..ef66f8740e 100644 --- a/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs @@ -1,29 +1,60 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "Content Picker", PropertyEditorValueTypes.Integer, "contentpicker", IsParameterEditor = true, Group = "Pickers")] - public class ContentPickerPropertyEditor : PropertyEditor - { + /// + /// Legacy content property editor that stores Integer Ids + /// + [Obsolete("This editor is obsolete, use ContentPickerPropertyEditor2 instead which stores UDI")] + [PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "(Obsolete) Content Picker", PropertyEditorValueTypes.Integer, "contentpicker", IsParameterEditor = true, Group = "Pickers", IsDeprecated = true)] + public class ContentPickerPropertyEditor : ContentPickerPropertyEditor2 + { public ContentPickerPropertyEditor() { - _internalPreValues = new Dictionary + InternalPreValues["idType"] = "int"; + } + + /// + /// overridden to change the pre-value picker to use INT ids + /// + /// + protected override PreValueEditor CreatePreValueEditor() + { + var preValEditor = base.CreatePreValueEditor(); + preValEditor.Fields.Single(x => x.Key == "startNodeId").Config["idType"] = "int"; + return preValEditor; + } + } + + /// + /// Content property editor that stores UDI + /// + [PropertyEditor(Constants.PropertyEditors.ContentPicker2Alias, "Content Picker", PropertyEditorValueTypes.String, "contentpicker", IsParameterEditor = true, Group = "Pickers")] + public class ContentPickerPropertyEditor2 : PropertyEditor + { + + public ContentPickerPropertyEditor2() + { + InternalPreValues = new Dictionary { {"startNodeId", "-1"}, {"showOpenButton", "0"}, {"showEditButton", "0"}, - {"showPathOnHover", "0"} + {"showPathOnHover", "0"}, + {"idType", "udi"} }; } - private IDictionary _internalPreValues; + internal IDictionary InternalPreValues; public override IDictionary DefaultPreValues { - get { return _internalPreValues; } - set { _internalPreValues = value; } + get { return InternalPreValues; } + set { InternalPreValues = value; } } protected override PreValueEditor CreatePreValueEditor() @@ -33,12 +64,27 @@ namespace Umbraco.Web.PropertyEditors internal class ContentPickerPreValueEditor : PreValueEditor { - [PreValueField("showOpenButton", "Show open button (this feature is in preview!)", "boolean", Description = " Opens the node in a dialog")] - public string ShowOpenButton { get; set; } - - [PreValueField("startNodeId", "Start node", "treepicker")] - public int StartNodeId { get; set; } - + public ContentPickerPreValueEditor() + { + //create the fields + Fields.Add(new PreValueField() + { + Key = "showOpenButton", + View = "boolean", + Name = "Show open button (this feature is in preview!)", + Description = "Opens the node in a dialog" + }); + Fields.Add(new PreValueField() + { + Key = "startNodeId", + View = "treepicker", + Name = "Start node", + Config = new Dictionary + { + {"idType", "udi"} + } + }); + } } } } \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/FolderBrowserPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/FolderBrowserPropertyEditor.cs index bfdbe368d1..5c89b868b8 100644 --- a/src/Umbraco.Web/PropertyEditors/FolderBrowserPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/FolderBrowserPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { [Obsolete("This is no longer used by default, use the ListViewPropertyEditor instead")] - [PropertyEditor(Constants.PropertyEditors.FolderBrowserAlias, "(Obsolete) Folder Browser", "folderbrowser", HideLabel=true, Icon="icon-folder", Group="media")] + [PropertyEditor(Constants.PropertyEditors.FolderBrowserAlias, "(Obsolete) Folder Browser", "folderbrowser", HideLabel=true, Icon="icon-folder", Group="media", IsDeprecated = true)] public class FolderBrowserPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs index 6bb2cda0b0..b3e5390b64 100644 --- a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MacroContainerAlias, "Macro Picker", "macrocontainer", ValueType = PropertyEditorValueTypes.Text, Group="rich content", Icon="icon-settings-alt")] + [PropertyEditor(Constants.PropertyEditors.MacroContainerAlias, "Macro Picker", "macrocontainer", ValueType = PropertyEditorValueTypes.Text, Group="rich content", Icon="icon-settings-alt", IsDeprecated = true)] public class MacroContainerPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs index 7e966d31ad..5da7bf38eb 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs @@ -9,34 +9,23 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "Legacy Media Picker", PropertyEditorValueTypes.Integer, "mediapicker", Group="media", Icon="icon-picture")] - public class MediaPickerPropertyEditor : PropertyEditor + /// + /// Legacy media property editor that stores Integer Ids + /// + [Obsolete("This editor is obsolete, use ContentPickerPropertyEditor2 instead which stores UDI")] + [PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "(Obsolete) Media Picker", PropertyEditorValueTypes.Integer, "mediapicker", Group = "media", Icon = "icon-picture", IsDeprecated = true)] + public class MediaPickerPropertyEditor : MediaPickerPropertyEditor2 { public MediaPickerPropertyEditor() { InternalPreValues = new Dictionary { {"multiPicker", "0"}, - {"onlyImages", "0"} + {"onlyImages", "0"}, + {"idType", "int"} }; } - protected IDictionary InternalPreValues; - - protected override PropertyValueEditor CreateValueEditor() - { - //TODO: Need to add some validation to the ValueEditor to ensure that any media chosen actually exists! - return base.CreateValueEditor(); - } - - - - public override IDictionary DefaultPreValues - { - get { return InternalPreValues; } - set { InternalPreValues = value; } - } - protected override PreValueEditor CreatePreValueEditor() { return new SingleMediaPickerPreValueEditor(); @@ -48,4 +37,70 @@ namespace Umbraco.Web.PropertyEditors public int StartNodeId { get; set; } } } + + /// + /// Media picker property editors that stores UDI + /// + [PropertyEditor(Constants.PropertyEditors.MediaPicker2Alias, "Media Picker", PropertyEditorValueTypes.Text, "mediapicker", Group = "media", Icon = "icon-picture")] + public class MediaPickerPropertyEditor2 : PropertyEditor + { + public MediaPickerPropertyEditor2() + { + InternalPreValues = new Dictionary + { + {"idType", "udi"} + }; + } + + internal IDictionary InternalPreValues; + + public override IDictionary DefaultPreValues + { + get { return InternalPreValues; } + set { InternalPreValues = value; } + } + + protected override PreValueEditor CreatePreValueEditor() + { + return new MediaPickerPreValueEditor(); + } + + internal class MediaPickerPreValueEditor : PreValueEditor + { + public MediaPickerPreValueEditor() + { + //create the fields + Fields.Add(new PreValueField() + { + Key = "multiPicker", + View = "boolean", + Name = "Pick multiple items" + }); + Fields.Add(new PreValueField() + { + Key = "onlyImages", + View = "boolean", + Name = "Pick only images", + Description = "Only let the editor choose images from media." + }); + Fields.Add(new PreValueField() + { + Key = "disableFolderSelect", + View = "boolean", + Name = "Disable folder select", + Description = "Do not allow folders to be picked." + }); + Fields.Add(new PreValueField() + { + Key = "startNodeId", + View = "mediapicker", + Name = "Start node", + Config = new Dictionary + { + {"idType", "udi"} + } + }); + } + } + } } diff --git a/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs index 7dadbfe24c..68f864e9b6 100644 --- a/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs @@ -8,8 +8,33 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Picker", PropertyEditorValueTypes.Integer, "memberpicker", Group = "People", Icon = "icon-user")] - public class MemberPickerPropertyEditor : PropertyEditor + + [Obsolete("This editor is obsolete, use MemberPickerPropertyEditor2 instead which stores UDI")] + [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "(Obsolete) Member Picker", PropertyEditorValueTypes.Integer, "memberpicker", Group = "People", Icon = "icon-user", IsDeprecated = true)] + public class MemberPickerPropertyEditor : MemberPickerPropertyEditor2 { + public MemberPickerPropertyEditor() + { + InternalPreValues["idType"] = "int"; + } + } + + [PropertyEditor(Constants.PropertyEditors.MemberPicker2Alias, "Member Picker", PropertyEditorValueTypes.String, "memberpicker", Group = "People", Icon = "icon-user")] + public class MemberPickerPropertyEditor2 : PropertyEditor + { + public MemberPickerPropertyEditor2() + { + InternalPreValues = new Dictionary + { + {"idType", "udi"} + }; + } + + internal IDictionary InternalPreValues; + public override IDictionary DefaultPreValues + { + get { return InternalPreValues; } + set { InternalPreValues = value; } + } } } diff --git a/src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs index 82daf80e34..fbba130543 100644 --- a/src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs @@ -1,21 +1,45 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MultiNodeTreePickerAlias, "Multinode Treepicker", "contentpicker", Group="pickers", Icon="icon-page-add")] - public class MultiNodeTreePickerPropertyEditor : PropertyEditor + [Obsolete("This editor is obsolete, use MultiNodeTreePickerPropertyEditor2 instead which stores UDI")] + [PropertyEditor(Constants.PropertyEditors.MultiNodeTreePickerAlias, "(Obsolete) Multinode Treepicker", "contentpicker", Group = "pickers", Icon = "icon-page-add", IsDeprecated = true)] + public class MultiNodeTreePickerPropertyEditor : MultiNodeTreePickerPropertyEditor2 { public MultiNodeTreePickerPropertyEditor() { - _internalPreValues = new Dictionary + InternalPreValues["idType"] = "int"; + } + + /// + /// overridden to change the pre-value picker to use INT ids + /// + /// + protected override PreValueEditor CreatePreValueEditor() + { + var preValEditor = base.CreatePreValueEditor(); + preValEditor.Fields.Single(x => x.Key == "startNode").Config["idType"] = "int"; + return preValEditor; + } + } + + [PropertyEditor(Constants.PropertyEditors.MultiNodeTreePicker2Alias, "Multinode Treepicker", PropertyEditorValueTypes.Text, "contentpicker", Group="pickers", Icon="icon-page-add")] + public class MultiNodeTreePickerPropertyEditor2 : PropertyEditor + { + public MultiNodeTreePickerPropertyEditor2() + { + InternalPreValues = new Dictionary { {"multiPicker", "1"}, {"showOpenButton", "0"}, {"showEditButton", "0"}, - {"showPathOnHover", "0"} + {"showPathOnHover", "0"}, + {"idType", "udi"} }; } @@ -24,29 +48,55 @@ namespace Umbraco.Web.PropertyEditors return new MultiNodePickerPreValueEditor(); } - private IDictionary _internalPreValues; + internal IDictionary InternalPreValues; public override IDictionary DefaultPreValues { - get { return _internalPreValues; } - set { _internalPreValues = value; } + get { return InternalPreValues; } + set { InternalPreValues = value; } } internal class MultiNodePickerPreValueEditor : PreValueEditor { - [PreValueField("startNode", "Node type", "treesource")] - public string StartNode { get; set; } - - [PreValueField("filter", "Allow items of type", "textstring", Description = "Separate with comma")] - public string Filter { get; set; } - - [PreValueField("minNumber", "Minimum number of items", "number")] - public string MinNumber { get; set; } - - [PreValueField("maxNumber", "Maximum number of items", "number")] - public string MaxNumber { get; set; } - - [PreValueField("showOpenButton", "Show open button (this feature is in preview!)", "boolean", Description = " Opens the node in a dialog")] - public string ShowOpenButton { get; set; } + public MultiNodePickerPreValueEditor() + { + //create the fields + Fields.Add(new PreValueField() + { + Key = "startNode", + View = "treesource", + Name = "Node type", + Config = new Dictionary + { + {"idType", "udi"} + } + }); + Fields.Add(new PreValueField() + { + Key = "filter", + View = "textstring", + Name = "Allow items of type", + Description = "Separate with comma" + }); + Fields.Add(new PreValueField() + { + Key = "minNumber", + View = "number", + Name = "Minimum number of items" + }); + Fields.Add(new PreValueField() + { + Key = "maxNumber", + View = "number", + Name = "Maximum number of items" + }); + Fields.Add(new PreValueField() + { + Key = "showOpenButton", + View = "boolean", + Name = "Show open button (this feature is in preview!)", + Description = "Opens the node in a dialog" + }); + } /// /// This ensures the multiPicker pre-val is set based on the maxNumber of nodes set diff --git a/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs index 37587d1c54..12aec22e31 100644 --- a/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs @@ -1,35 +1,29 @@ -using Umbraco.Core; +using System; +using System.Linq; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MultipleMediaPickerAlias, "Media Picker", "mediapicker", Group = "media", Icon = "icon-pictures-alt-2")] - public class MultipleMediaPickerPropertyEditor : MediaPickerPropertyEditor - { + [Obsolete("This editor is obsolete, use MultipleMediaPickerPropertyEditor2 instead which stores UDI")] + [PropertyEditor(Constants.PropertyEditors.MultipleMediaPickerAlias, "(Obsolete) Media Picker", "mediapicker", Group = "media", Icon = "icon-pictures-alt-2", IsDeprecated = true)] + public class MultipleMediaPickerPropertyEditor : MediaPickerPropertyEditor2 + { public MultipleMediaPickerPropertyEditor() { - //clear the pre-values so it defaults to a multiple picker. - InternalPreValues.Clear(); - } - - protected override PreValueEditor CreatePreValueEditor() - { - return new MediaPickerPreValueEditor(); - } - - internal class MediaPickerPreValueEditor : PreValueEditor - { - [PreValueField("multiPicker", "Pick multiple items", "boolean")] - public bool MultiPicker { get; set; } - - [PreValueField("onlyImages", "Pick only images", "boolean", Description = "Only let the editor choose images from media.")] - public bool OnlyImages { get; set; } + //default it to multi picker + InternalPreValues["multiPicker"] = "1"; + } - [PreValueField("disableFolderSelect", "Disable folder select", "boolean", Description = "Do not allow folders to be picked.")] - public bool DisableFolderSelect { get; set; } - - [PreValueField("startNodeId", "Start node", "mediapicker")] - public int StartNodeId { get; set; } + /// + /// overridden to change the pre-value picker to use INT ids + /// + /// + protected override PreValueEditor CreatePreValueEditor() + { + var preValEditor = base.CreatePreValueEditor(); + preValEditor.Fields.Single(x => x.Key == "startNodeId").Config["idType"] = "int"; + return preValEditor; } - } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 5e8172b29f..2a5e28496e 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -300,24 +300,31 @@ namespace Umbraco.Web.Trees } /// - /// Get an entity via an id that can be either an integer or a Guid + /// Get an entity via an id that can be either an integer, Guid or UDI /// /// /// internal IUmbracoEntity GetEntityFromId(string id) { IUmbracoEntity entity; + Guid idGuid = Guid.Empty; int idInt; + Udi idUdi; + if (Guid.TryParse(id, out idGuid)) { entity = Services.EntityService.GetByKey(idGuid, UmbracoObjectType); - } else if (int.TryParse(id, out idInt)) { entity = Services.EntityService.Get(idInt, UmbracoObjectType); } + else if (Udi.TryParse(id, out idUdi)) + { + var guidUdi = idUdi as GuidUdi; + entity = guidUdi != null ? Services.EntityService.GetByKey(guidUdi.Guid, UmbracoObjectType) : null; + } else { return null; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a3784ced4e..f3f03d2b83 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -283,6 +283,7 @@ + @@ -342,6 +343,7 @@ + @@ -456,7 +458,6 @@ - diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index 37382d2647..c86118b475 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -183,6 +183,7 @@ namespace UmbracoExamine /// Used to store the path of a content object /// public const string IndexPathFieldName = "__Path"; + public const string NodeKeyFieldName = "__Key"; public const string NodeTypeAliasFieldName = "__NodeTypeAlias"; public const string IconFieldName = "__Icon"; @@ -727,18 +728,23 @@ namespace UmbracoExamine //ensure the special path and node type alias fields is added to the dictionary to be saved to file var path = e.Node.Attribute("path").Value; - if (!e.Fields.ContainsKey(IndexPathFieldName)) + if (e.Fields.ContainsKey(IndexPathFieldName) == false) e.Fields.Add(IndexPathFieldName, path); //this needs to support both schema's so get the nodeTypeAlias if it exists, otherwise the name var nodeTypeAlias = e.Node.Attribute("nodeTypeAlias") == null ? e.Node.Name.LocalName : e.Node.Attribute("nodeTypeAlias").Value; - if (!e.Fields.ContainsKey(NodeTypeAliasFieldName)) + if (e.Fields.ContainsKey(NodeTypeAliasFieldName) == false) e.Fields.Add(NodeTypeAliasFieldName, nodeTypeAlias); //add icon var icon = (string)e.Node.Attribute("icon"); - if (!e.Fields.ContainsKey(IconFieldName)) - e.Fields.Add(IconFieldName, icon); + if (e.Fields.ContainsKey(IconFieldName) == false) + e.Fields.Add(IconFieldName, icon); + + //add guid + var guid = (string)e.Node.Attribute("key"); + if (e.Fields.ContainsKey(NodeKeyFieldName) == false) + e.Fields.Add(NodeKeyFieldName, guid); } /// @@ -769,10 +775,18 @@ namespace UmbracoExamine //adds the special node type alias property to the index fields.Add(NodeTypeAliasFieldName, allValuesForIndexing[NodeTypeAliasFieldName]); - //icon - if (allValuesForIndexing[IconFieldName].IsNullOrWhiteSpace() == false) + //guid + string guidVal; + if (allValuesForIndexing.TryGetValue(NodeKeyFieldName, out guidVal) && guidVal.IsNullOrWhiteSpace() == false) { - fields.Add(IconFieldName, allValuesForIndexing[IconFieldName]); + fields.Add(NodeKeyFieldName, guidVal); + } + + //icon + string iconVal; + if (allValuesForIndexing.TryGetValue(IconFieldName, out iconVal) && iconVal.IsNullOrWhiteSpace() == false) + { + fields.Add(IconFieldName, iconVal); } return fields; diff --git a/src/UmbracoExamine/UmbracoMemberIndexer.cs b/src/UmbracoExamine/UmbracoMemberIndexer.cs index ad393932be..9ca61164eb 100644 --- a/src/UmbracoExamine/UmbracoMemberIndexer.cs +++ b/src/UmbracoExamine/UmbracoMemberIndexer.cs @@ -232,27 +232,8 @@ namespace UmbracoExamine protected override XDocument GetXDocument(string xPath, string type) { throw new NotSupportedException(); - } - - protected override Dictionary GetSpecialFieldsToIndex(Dictionary allValuesForIndexing) - { - var fields = base.GetSpecialFieldsToIndex(allValuesForIndexing); - - //adds the special key property to the index - string valuesForIndexing; - if (allValuesForIndexing.TryGetValue("__key", out valuesForIndexing)) - { - if (fields.ContainsKey("__key") == false) - { - fields.Add("__key", valuesForIndexing); - } - } - - - return fields; - - } - + } + /// /// Add the special __key and _searchEmail fields /// @@ -263,8 +244,8 @@ namespace UmbracoExamine if (e.Node.Attribute("key") != null) { - if (e.Fields.ContainsKey("__key") == false) - e.Fields.Add("__key", e.Node.Attribute("key").Value); + if (e.Fields.ContainsKey(NodeKeyFieldName) == false) + e.Fields.Add(NodeKeyFieldName, e.Node.Attribute("key").Value); } if (e.Node.Attribute("email") != null)