diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs index 23a6bcfe5b..92bdf3c790 100644 --- a/src/Umbraco.Core/Models/UmbracoEntity.cs +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Models @@ -48,11 +47,13 @@ namespace Umbraco.Core.Models public UmbracoEntity() { AdditionalData = new Dictionary(); + UmbracoProperties = new List(); } public UmbracoEntity(bool trashed) { AdditionalData = new Dictionary(); + UmbracoProperties = new List(); Trashed = trashed; } @@ -60,6 +61,7 @@ namespace Umbraco.Core.Models public UmbracoEntity(UInt64 trashed) { AdditionalData = new Dictionary(); + UmbracoProperties = new List(); Trashed = trashed == 1; } @@ -285,31 +287,15 @@ namespace Umbraco.Core.Models } } - public override object DeepClone() - { - var clone = (UmbracoEntity) base.DeepClone(); - - //This ensures that any value in the dictionary that is deep cloneable is cloned too - foreach (var key in clone.AdditionalData.Keys.ToArray()) - { - var deepCloneable = clone.AdditionalData[key] as IDeepCloneable; - if (deepCloneable != null) - { - clone.AdditionalData[key] = deepCloneable.DeepClone(); - } - } - - return clone; - } - /// - /// A struction that can be contained in the additional data of an UmbracoEntity representing - /// a user defined property + /// Some entities may expose additional data that other's might not, this custom data will be available in this collection /// - public class EntityProperty : IDeepCloneable + public IList UmbracoProperties { get; set; } + + internal class UmbracoProperty : IDeepCloneable { public string PropertyEditorAlias { get; set; } - public object Value { get; set; } + public string Value { get; set; } public object DeepClone() { //Memberwise clone on Entity will work since it doesn't have any deep elements @@ -318,7 +304,7 @@ namespace Umbraco.Core.Models return clone; } - protected bool Equals(EntityProperty other) + protected bool Equals(UmbracoProperty other) { return PropertyEditorAlias.Equals(other.PropertyEditorAlias) && string.Equals(Value, other.Value); } @@ -328,7 +314,7 @@ namespace Umbraco.Core.Models if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; - return Equals((EntityProperty) obj); + return Equals((UmbracoProperty) obj); } public override int GetHashCode() diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs index f33ae1af2f..db1a99bc45 100644 --- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs @@ -44,6 +44,7 @@ namespace Umbraco.Core.Persistence.Factories ContentTypeAlias = asDictionary.ContainsKey("alias") ? (d.alias ?? string.Empty) : string.Empty, ContentTypeIcon = asDictionary.ContainsKey("icon") ? (d.icon ?? string.Empty) : string.Empty, ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty, + UmbracoProperties = new List() }; var publishedVersion = default(Guid); @@ -86,6 +87,7 @@ namespace Umbraco.Core.Persistence.Factories ContentTypeAlias = dto.Alias ?? string.Empty, ContentTypeIcon = dto.Icon ?? string.Empty, ContentTypeThumbnail = dto.Thumbnail ?? string.Empty, + UmbracoProperties = new List() }; entity.IsPublished = dto.PublishedVersion != default(Guid) || (dto.NewestVersion != default(Guid) && dto.PublishedVersion == dto.NewestVersion); @@ -96,13 +98,12 @@ namespace Umbraco.Core.Persistence.Factories { foreach (var propertyDto in dto.UmbracoPropertyDtos) { - entity.AdditionalData[propertyDto.PropertyAlias] = new UmbracoEntity.EntityProperty - { - PropertyEditorAlias = propertyDto.PropertyEditorAlias, - Value = propertyDto.NTextValue.IsNullOrWhiteSpace() - ? propertyDto.NVarcharValue - : propertyDto.NTextValue.ConvertToJsonIfPossible() - }; + entity.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty + { + PropertyEditorAlias = + propertyDto.PropertyEditorAlias, + Value = propertyDto.UmbracoFile + }); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs index 5f721f7141..7336e36ab7 100644 --- a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs @@ -66,31 +66,15 @@ namespace Umbraco.Core.Persistence.Repositories { bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, key).Append(GetGroupBy(isContent, isMedia)); + var nodeDto = _work.Database.FirstOrDefault(sql); + if (nodeDto == null) + return null; - var sql = GetFullSqlForEntityType(key, isContent, isMedia, objectTypeId); - - if (isMedia) - { - //for now treat media differently - //TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields - var entities = _work.Database.Fetch( - new UmbracoEntityRelator().Map, sql); + var factory = new UmbracoEntityFactory(); + var entity = factory.BuildEntityFromDynamic(nodeDto); - return entities.FirstOrDefault(); - } - else - { - var nodeDto = _work.Database.FirstOrDefault(sql); - if (nodeDto == null) - return null; - - var factory = new UmbracoEntityFactory(); - var entity = factory.BuildEntityFromDynamic(nodeDto); - - return entity; - } - - + return entity; } public virtual IUmbracoEntity Get(int id) @@ -110,31 +94,16 @@ namespace Umbraco.Core.Persistence.Repositories { bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, id).Append(GetGroupBy(isContent, isMedia)); - var sql = GetFullSqlForEntityType(id, isContent, isMedia, objectTypeId); - - if (isMedia) - { - //for now treat media differently - //TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields - var entities = _work.Database.Fetch( - new UmbracoEntityRelator().Map, sql); + var nodeDto = _work.Database.FirstOrDefault(sql); + if (nodeDto == null) + return null; - return entities.FirstOrDefault(); - } - else - { - var nodeDto = _work.Database.FirstOrDefault(sql); - if (nodeDto == null) - return null; + var factory = new UmbracoEntityFactory(); + var entity = factory.BuildEntityFromDynamic(nodeDto); - var factory = new UmbracoEntityFactory(); - var entity = factory.BuildEntityFromDynamic(nodeDto); - - return entity; - } - - + return entity; } public virtual IEnumerable GetAll(Guid objectTypeId, params int[] ids) @@ -150,8 +119,8 @@ namespace Umbraco.Core.Persistence.Repositories { bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media); - var sql = GetFullSqlForEntityType(isContent, isMedia, objectTypeId, string.Empty); - + var sql = GetBaseWhere(GetBase, isContent, isMedia, string.Empty, objectTypeId).Append(GetGroupBy(isContent, isMedia)); + var factory = new UmbracoEntityFactory(); if (isMedia) @@ -197,28 +166,24 @@ namespace Umbraco.Core.Persistence.Repositories bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media); var wheres = string.Concat(" AND ", string.Join(" AND ", ((Query)query).WhereClauses())); - var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, wheres, objectTypeId); - var translator = new SqlTranslator(sqlClause, query); - var entitySql = translator.Translate(); + var sql = translator.Translate().Append(GetGroupBy(isContent, isMedia)); var factory = new UmbracoEntityFactory(); if (isMedia) { - var mediaSql = GetFullSqlForMedia(entitySql, wheres); - //treat media differently for now //TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields var entities = _work.Database.Fetch( - new UmbracoEntityRelator().Map, mediaSql); + new UmbracoEntityRelator().Map, sql); return entities; } else { //use dynamic so that we can get ALL properties from the SQL so we can chuck that data into our AdditionalData - var dtos = _work.Database.Fetch(entitySql.Append(GetGroupBy(isContent, false))); + var dtos = _work.Database.Fetch(sql); return dtos.Select(factory.BuildEntityFromDynamic).Cast().ToList(); } } @@ -228,62 +193,6 @@ namespace Umbraco.Core.Persistence.Repositories #region Sql Statements - protected Sql GetFullSqlForEntityType(Guid key, bool isContent, bool isMedia, Guid objectTypeId) - { - var entitySql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, key); - - if (isMedia == false) return entitySql.Append(GetGroupBy(isContent, false)); - - return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false))); - } - - protected Sql GetFullSqlForEntityType(int id, bool isContent, bool isMedia, Guid objectTypeId) - { - var entitySql = GetBaseWhere(GetBase, isContent, isMedia, objectTypeId, id); - - if (isMedia == false) return entitySql.Append(GetGroupBy(isContent, false)); - - return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false))); - } - - protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectTypeId, string additionalWhereClause) - { - var entitySql = GetBaseWhere(GetBase, isContent, isMedia, additionalWhereClause, objectTypeId); - - if (isMedia == false) return entitySql.Append(GetGroupBy(isContent, false)); - - return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false))); - } - - private Sql GetFullSqlForMedia(Sql entitySql, string additionWhereStatement = "") - { - //this will add any dataNvarchar property to the output which can be added to the additional properties - - var joinSql = new Sql() - .Select("contentNodeId, versionId, dataNvarchar, dataNtext, propertyEditorAlias, alias as propertyTypeAlias") - .From() - .InnerJoin() - .On(dto => dto.NodeId, dto => dto.NodeId) - .InnerJoin() - .On(dto => dto.Id, dto => dto.PropertyTypeId) - .InnerJoin() - .On(dto => dto.DataTypeId, dto => dto.DataTypeId) - .Where("umbracoNode.nodeObjectType = @nodeObjectType" + additionWhereStatement, new {nodeObjectType = Constants.ObjectTypes.Media}); - - //We're going to create a query to query against the entity SQL - // because we cannot group by nText columns and we have a COUNT in the entitySql we cannot simply left join - // the entitySql query, we have to join the wrapped query to get the ntext in the result - - var wrappedSql = new Sql("SELECT * FROM (") - .Append(entitySql) - .Append(new Sql(") tmpTbl LEFT JOIN (")) - .Append(joinSql) - .Append(new Sql(") as property ON id = property.contentNodeId")) - .OrderBy("sortOrder"); - - return wrappedSql; - } - protected virtual Sql GetBase(bool isContent, bool isMedia, string additionWhereStatement = "") { var columns = new List @@ -312,9 +221,13 @@ namespace Umbraco.Core.Persistence.Repositories columns.Add("contenttype.isContainer"); } - //Creates an SQL query to return a single row for the entity + if (isMedia) + { + columns.Add("property.dataNvarchar as umbracoFile"); + columns.Add("property.propertyEditorAlias"); + } - var entitySql = new Sql() + var sql = new Sql() .Select(columns.ToArray()) .From("umbracoNode umbracoNode") .LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id"); @@ -322,7 +235,7 @@ namespace Umbraco.Core.Persistence.Repositories if (isContent || isMedia) { - entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id") + sql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id") .LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType") .LeftJoin( "(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published") @@ -332,7 +245,18 @@ namespace Umbraco.Core.Persistence.Repositories .On("umbracoNode.id = latest.nodeId"); } - return entitySql; + if (isMedia) + { + sql.LeftJoin( + "(SELECT contentNodeId, versionId, dataNvarchar, propertyEditorAlias FROM cmsPropertyData " + + "INNER JOIN umbracoNode ON cmsPropertyData.contentNodeId = umbracoNode.id " + + "INNER JOIN cmsPropertyType ON cmsPropertyType.id = cmsPropertyData.propertytypeid " + + "INNER JOIN cmsDataType ON cmsPropertyType.dataTypeId = cmsDataType.nodeId "+ + "WHERE umbracoNode.nodeObjectType = '" + Constants.ObjectTypes.Media + "'" + additionWhereStatement + ") as property") + .On("umbracoNode.id = property.contentNodeId"); + } + + return sql; } protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, bool isMedia, string additionWhereStatement, Guid nodeObjectType) @@ -374,7 +298,7 @@ namespace Umbraco.Core.Persistence.Repositories return sql; } - protected virtual Sql GetGroupBy(bool isContent, bool isMedia, bool includeSort = true) + protected virtual Sql GetGroupBy(bool isContent, bool isMedia) { var columns = new List { @@ -400,18 +324,19 @@ namespace Umbraco.Core.Persistence.Repositories columns.Add("contenttype.thumbnail"); columns.Add("contenttype.isContainer"); } - - var sql = new Sql() - .GroupBy(columns.ToArray()); - if (includeSort) + if (isMedia) { - sql = sql.OrderBy("umbracoNode.sortOrder"); + columns.Add("property.dataNvarchar"); + columns.Add("property.propertyEditorAlias"); } + var sql = new Sql() + .GroupBy(columns.ToArray()) + .OrderBy("umbracoNode.sortOrder"); return sql; } - + #endregion /// @@ -452,21 +377,15 @@ namespace Umbraco.Core.Persistence.Repositories [ResultColumn] public List UmbracoPropertyDtos { get; set; } } - + [ExplicitColumns] internal class UmbracoPropertyDto { [Column("propertyEditorAlias")] public string PropertyEditorAlias { get; set; } - [Column("propertyTypeAlias")] - public string PropertyAlias { get; set; } - - [Column("dataNvarchar")] - public string NVarcharValue { get; set; } - - [Column("dataNtext")] - public string NTextValue { get; set; } + [Column("umbracoFile")] + public string UmbracoFile { get; set; } } /// @@ -493,15 +412,16 @@ namespace Umbraco.Core.Persistence.Repositories // Is this the same UmbracoEntity as the current one we're processing if (Current != null && Current.Key == a.uniqueID) { - // Add this UmbracoProperty to the current additional data - Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty + // Yes, just add this UmbracoProperty to the current UmbracoEntity's collection + if (Current.UmbracoProperties == null) { - PropertyEditorAlias = p.PropertyEditorAlias, - Value = p.NTextValue.IsNullOrWhiteSpace() - ? p.NVarcharValue - : p.NTextValue.ConvertToJsonIfPossible() - }; - + Current.UmbracoProperties = new List(); + } + Current.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty + { + PropertyEditorAlias = p.PropertyEditorAlias, + Value = p.UmbracoFile + }); // Return null to indicate we're not done with this UmbracoEntity yet return null; } @@ -517,13 +437,14 @@ namespace Umbraco.Core.Persistence.Repositories Current = _factory.BuildEntityFromDynamic(a); //add the property/create the prop list if null - Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty - { - PropertyEditorAlias = p.PropertyEditorAlias, - Value = p.NTextValue.IsNullOrWhiteSpace() - ? p.NVarcharValue - : p.NTextValue.ConvertToJsonIfPossible() - }; + Current.UmbracoProperties = new List + { + new UmbracoEntity.UmbracoProperty + { + PropertyEditorAlias = p.PropertyEditorAlias, + Value = p.UmbracoFile + } + }; // Return the now populated previous UmbracoEntity (or null if first time through) return prev; diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index d1b20cce30..395f9cea0c 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -10,7 +10,6 @@ using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Xml; -using Newtonsoft.Json; using Umbraco.Core.Configuration; using System.Web.Security; using Umbraco.Core.Strings; @@ -53,28 +52,6 @@ namespace Umbraco.Core || (input.StartsWith("[") && input.EndsWith("]")); } - /// - /// Returns a JObject/JArray instance if the string can be converted to json, otherwise returns the string - /// - /// - /// - internal static object ConvertToJsonIfPossible(this string input) - { - if (input.DetectIsJson() == false) - { - return input; - } - try - { - var obj = JsonConvert.DeserializeObject(input); - return obj; - } - catch (Exception ex) - { - return input; - } - } - internal static string ReplaceNonAlphanumericChars(this string input, char replacement) { //any character that is not alphanumeric, convert to a hyphen diff --git a/src/Umbraco.Tests/Models/UmbracoEntityTests.cs b/src/Umbraco.Tests/Models/UmbracoEntityTests.cs index 52513d551d..ac70364e67 100644 --- a/src/Umbraco.Tests/Models/UmbracoEntityTests.cs +++ b/src/Umbraco.Tests/Models/UmbracoEntityTests.cs @@ -47,13 +47,12 @@ namespace Umbraco.Tests.Models }; item.AdditionalData.Add("test1", 3); item.AdditionalData.Add("test2", "valuie"); - - item.AdditionalData.Add("test3", new UmbracoEntity.EntityProperty() + item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty() { Value = "test", PropertyEditorAlias = "TestPropertyEditor" }); - item.AdditionalData.Add("test4", new UmbracoEntity.EntityProperty() + item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty() { Value = "test2", PropertyEditorAlias = "TestPropertyEditor2" @@ -83,6 +82,12 @@ namespace Umbraco.Tests.Models Assert.AreEqual(clone.UpdateDate, item.UpdateDate); Assert.AreEqual(clone.AdditionalData.Count, item.AdditionalData.Count); Assert.AreEqual(clone.AdditionalData, item.AdditionalData); + Assert.AreEqual(clone.UmbracoProperties.Count, item.UmbracoProperties.Count); + for (var i = 0; i < clone.UmbracoProperties.Count; i++) + { + Assert.AreNotSame(clone.UmbracoProperties[i], item.UmbracoProperties[i]); + Assert.AreEqual(clone.UmbracoProperties[i], item.UmbracoProperties[i]); + } //This double verifies by reflection var allProps = clone.GetType().GetProperties(); @@ -120,12 +125,12 @@ namespace Umbraco.Tests.Models }; item.AdditionalData.Add("test1", 3); item.AdditionalData.Add("test2", "valuie"); - item.AdditionalData.Add("test3", new UmbracoEntity.EntityProperty() + item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty() { Value = "test", PropertyEditorAlias = "TestPropertyEditor" }); - item.AdditionalData.Add("test4", new UmbracoEntity.EntityProperty() + item.UmbracoProperties.Add(new UmbracoEntity.UmbracoProperty() { Value = "test2", PropertyEditorAlias = "TestPropertyEditor2" diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests/Services/EntityServiceTests.cs index 9826e9fc3f..82cc2c7560 100644 --- a/src/Umbraco.Tests/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests/Services/EntityServiceTests.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.Services { var service = ServiceContext.EntityService; - var entities = service.GetAll(UmbracoObjectTypes.Document).ToArray(); + var entities = service.GetAll(UmbracoObjectTypes.Document); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(4)); @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Services var service = ServiceContext.EntityService; var objectTypeId = new Guid(Constants.ObjectTypes.Document); - var entities = service.GetAll(objectTypeId).ToArray(); + var entities = service.GetAll(objectTypeId); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(4)); @@ -57,7 +57,7 @@ namespace Umbraco.Tests.Services { var service = ServiceContext.EntityService; - var entities = service.GetAll().ToArray(); + var entities = service.GetAll(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(4)); @@ -69,7 +69,7 @@ namespace Umbraco.Tests.Services { var service = ServiceContext.EntityService; - var entities = service.GetChildren(-1, UmbracoObjectTypes.Document).ToArray(); + var entities = service.GetChildren(-1, UmbracoObjectTypes.Document); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -92,7 +92,7 @@ namespace Umbraco.Tests.Services { var service = ServiceContext.EntityService; - var entities = service.GetAll(UmbracoObjectTypes.DocumentType).ToArray(); + var entities = service.GetAll(UmbracoObjectTypes.DocumentType); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -104,7 +104,7 @@ namespace Umbraco.Tests.Services var service = ServiceContext.EntityService; var objectTypeId = new Guid(Constants.ObjectTypes.DocumentType); - var entities = service.GetAll(objectTypeId).ToArray(); + var entities = service.GetAll(objectTypeId); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -115,7 +115,7 @@ namespace Umbraco.Tests.Services { var service = ServiceContext.EntityService; - var entities = service.GetAll().ToArray(); + var entities = service.GetAll(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -126,16 +126,16 @@ namespace Umbraco.Tests.Services { var service = ServiceContext.EntityService; - var entities = service.GetAll(UmbracoObjectTypes.Media).ToArray(); + var entities = service.GetAll(UmbracoObjectTypes.Media); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(3)); - + //Assert.That(entities.Any(x => ((UmbracoEntity)x).UmbracoFile != string.Empty), Is.True); Assert.That( entities.Any( x => - x.AdditionalData.Any(y => y.Value is UmbracoEntity.EntityProperty - && ((UmbracoEntity.EntityProperty)y.Value).PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias)), Is.True); + ((UmbracoEntity) x).UmbracoProperties.Any( + y => y.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias)), Is.True); } private static bool _isSetup = false; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js index 67dbcecc54..2e06bc1656 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js @@ -129,79 +129,30 @@ function mediaHelper(umbRequestHelper) { _mediaFileResolvers[propertyEditorAlias] = func; }, - /** - * @ngdoc function - * @name umbraco.services.mediaHelper#resolveFileFromEntity - * @methodOf umbraco.services.mediaHelper - * @function - * - * @description - * Gets the media file url for a media entity returned with the entityResource - * - * @param {object} mediaEntity A media Entity returned from the entityResource - * @param {boolean} thumbnail Whether to return the thumbnail url or normal url - */ - resolveFileFromEntity : function(mediaEntity, thumbnail) { - - if (!angular.isObject(mediaEntity.metaData)) { - throw "Cannot resolve the file url from the mediaEntity, it does not contain the required metaData"; - } - - var values = _.values(mediaEntity.metaData); - for (var i = 0; i < values.length; i++) { - var val = values[i]; - if (angular.isObject(val) && val.PropertyEditorAlias) { - for (var resolver in _mediaFileResolvers) { - if (val.PropertyEditorAlias === resolver) { - //we need to format a property variable that coincides with how the property would be structured - // if it came from the mediaResource just to keep things slightly easier for the file resolvers. - var property = { value: val.Value }; - - return _mediaFileResolvers[resolver](property, mediaEntity, thumbnail); - } - } - } - } - - return ""; - }, - - /** - * @ngdoc function - * @name umbraco.services.mediaHelper#resolveFile - * @methodOf umbraco.services.mediaHelper - * @function - * - * @description - * Gets the media file url for a media object returned with the mediaResource - * - * @param {object} mediaEntity A media Entity returned from the entityResource - * @param {boolean} thumbnail Whether to return the thumbnail url or normal url - */ /*jshint loopfunc: true */ resolveFile : function(mediaItem, thumbnail){ - - function iterateProps(props){ - var res = null; + var _props = []; + function _iterateProps(props){ + var result = null; for(var resolver in _mediaFileResolvers) { - var property = _.find(props, function(prop){ return prop.editor === resolver; }); + var property = _.find(props, function(property){ return property.editor === resolver; }); if(property){ - res = _mediaFileResolvers[resolver](property, mediaItem, thumbnail); + result = _mediaFileResolvers[resolver](property, mediaItem, thumbnail); break; } } - return res; + return result; } //we either have properties raw on the object, or spread out on tabs var result = ""; if(mediaItem.properties){ - result = iterateProps(mediaItem.properties); + result = _iterateProps(mediaItem.properties); }else if(mediaItem.tabs){ for(var tab in mediaItem.tabs) { if(mediaItem.tabs[tab].properties){ - result = iterateProps(mediaItem.tabs[tab].properties); + result = _iterateProps(mediaItem.tabs[tab].properties); if(result){ break; } @@ -213,26 +164,26 @@ function mediaHelper(umbRequestHelper) { /*jshint loopfunc: true */ hasFilePropertyType : function(mediaItem){ - function iterateProps(props){ - var res = false; + function _iterateProps(props){ + var result = false; for(var resolver in _mediaFileResolvers) { - var property = _.find(props, function(prop){ return prop.editor === resolver; }); + var property = _.find(props, function(property){ return property.editor === resolver; }); if(property){ - res = true; + result = true; break; } } - return res; + return result; } //we either have properties raw on the object, or spread out on tabs var result = false; if(mediaItem.properties){ - result = iterateProps(mediaItem.properties); + result = _iterateProps(mediaItem.properties); }else if(mediaItem.tabs){ for(var tab in mediaItem.tabs) { if(mediaItem.tabs[tab].properties){ - result = iterateProps(mediaItem.tabs[tab].properties); + result = _iterateProps(mediaItem.tabs[tab].properties); if(result){ break; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js index 7aa65473a6..0224853e7b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js @@ -125,15 +125,11 @@ function fileUploadController($scope, $element, $compile, imageHelper, fileManag angular.module("umbraco") .controller('Umbraco.PropertyEditors.FileUploadController', fileUploadController) .run(function(mediaHelper, umbRequestHelper){ - if (mediaHelper && mediaHelper.registerFileResolver) { - - //NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource - // they contain different data structures so if we need to query against it we need to be aware of this. + if(mediaHelper && mediaHelper.registerFileResolver){ mediaHelper.registerFileResolver("Umbraco.UploadField", function(property, entity, thumbnail){ if (thumbnail) { if (mediaHelper.detectIfImageByExtension(property.value)) { - var thumbnailUrl = umbRequestHelper.getApiUrl( "imagesApiBaseUrl", "GetBigThumbnail", diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js index 7189ca504a..abcdb0852f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js @@ -98,14 +98,11 @@ angular.module('umbraco') }) .run(function (mediaHelper, umbRequestHelper) { if (mediaHelper && mediaHelper.registerFileResolver) { - - //NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource - // they contain different data structures so if we need to query against it we need to be aware of this. mediaHelper.registerFileResolver("Umbraco.ImageCropper", function (property, entity, thumbnail) { if (property.value.src) { if (thumbnail === true) { - return property.value.src + "?width=500&mode=max"; + return property.value.src + "?width=600&mode=max"; } else { return property.value.src; @@ -117,7 +114,6 @@ angular.module('umbraco') if (thumbnail) { if (mediaHelper.detectIfImageByExtension(property.value)) { - var thumbnailUrl = umbRequestHelper.getApiUrl( "imagesApiBaseUrl", "GetBigThumbnail", 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 0a1066cda3..e17a03473c 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 @@ -1,7 +1,7 @@ //this controller simply tells the dialogs service to open a mediaPicker window //with a specified callback, this callback will receive an object with a selection on it angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerController", - function ($rootScope, $scope, dialogService, entityResource, mediaResource, mediaHelper, $timeout) { + function($rootScope, $scope, dialogService, mediaResource, mediaHelper, $timeout) { //check the pre-values for multi-picker var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false; @@ -17,24 +17,18 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl if ($scope.model.value) { var ids = $scope.model.value.split(','); - //NOTE: We need to use the entityResource NOT the mediaResource here because - // the mediaResource has server side auth configured for which the user must have - // access to the media section, if they don't they'll get auth errors. The entityResource - // acts differently in that it allows access if the user has access to any of the apps that - // might require it's use. Therefore we need to use the metatData property to get at the thumbnail - // value. - - entityResource.getByIds(ids, "Media").then(function (medias) { - + mediaResource.getByIds(ids).then(function (medias) { + //img.media = media; _.each(medias, function (media, i) { //only show non-trashed items - if (media.parentId >= -1) { - - if (!media.thumbnail) { - media.thumbnail = mediaHelper.resolveFileFromEntity(media, true); + if(media.parentId >= -1){ + if(!media.thumbnail){ + media.thumbnail = mediaHelper.resolveFile(media, true); } + //media.src = mediaHelper.getImagePropertyValue({ imageModel: media }); + //media.thumbnail = mediaHelper.getThumbnailFromPath(media.src); $scope.images.push(media); $scope.ids.push(media.id); } @@ -66,10 +60,10 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl _.each(data, function(media, i) { - if (!media.thumbnail) { - media.thumbnail = mediaHelper.resolveFileFromEntity(media, true); + if(!media.thumbnail){ + media.thumbnail = mediaHelper.resolveFile(media, true); } - + $scope.images.push(media); $scope.ids.push(media.id); }); diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 507c229122..52d60e566f 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -531,9 +531,8 @@ namespace Umbraco.Web.Editors var objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var result = ids.Select(id => Mapper.Map(Services.EntityService.Get(id, objectType.Value))) + return ids.Select(id => Mapper.Map(Services.EntityService.Get(id, objectType.Value))) .WhereNotNull(); - return result; } //now we need to convert the unknown ones switch (entityType) diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index 54938be76d..39b872af6d 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -104,8 +104,6 @@ namespace Umbraco.Web.Editors return GetResized(imagePath, width, Convert.ToString(width)); } - //TODO: We should delegate this to ImageProcessing - /// /// Gets a resized image - if the requested max width is greater than the original image, only the original image will be returned. /// diff --git a/src/Umbraco.Web/WebServices/FolderBrowserService.cs b/src/Umbraco.Web/WebServices/FolderBrowserService.cs index bf5a3f1bd5..2c8cff527d 100644 --- a/src/Umbraco.Web/WebServices/FolderBrowserService.cs +++ b/src/Umbraco.Web/WebServices/FolderBrowserService.cs @@ -32,14 +32,9 @@ namespace Umbraco.Web.WebServices var entities = service.GetChildren(parentId, UmbracoObjectTypes.Media); foreach (UmbracoEntity entity in entities) { - var uploadFieldProperty = entity.AdditionalData - .Select(x => x.Value as UmbracoEntity.EntityProperty) - .Where(x => x != null) - .FirstOrDefault(x => x.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias); - - //var uploadFieldProperty = entity.UmbracoProperties.FirstOrDefault(x => x.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias); - - var thumbnailUrl = uploadFieldProperty == null ? "" : ThumbnailProvidersResolver.Current.GetThumbnailUrl((string)uploadFieldProperty.Value); + var uploadFieldProperty = entity.UmbracoProperties.FirstOrDefault(x => x.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias); + + var thumbnailUrl = uploadFieldProperty == null ? "" : ThumbnailProvidersResolver.Current.GetThumbnailUrl(uploadFieldProperty.Value); var item = new { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs index f72457d867..0b48f7a2e1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs @@ -21,28 +21,28 @@ namespace umbraco.cms.presentation.Trees { [Obsolete("This is no longer used and will be removed from the codebase in the future")] - public abstract class BaseMediaTree : BaseTree - { + public abstract class BaseMediaTree : BaseTree + { private User _user; - public BaseMediaTree(string application) - : base(application) - { - - } - - /// - /// Returns the current User. This ensures that we don't instantiate a new User object - /// each time. - /// - protected User CurrentUser - { - get - { - return (_user == null ? (_user = UmbracoEnsuredPage.CurrentUser) : _user); - } - } + public BaseMediaTree(string application) + : base(application) + { + + } + /// + /// Returns the current User. This ensures that we don't instantiate a new User object + /// each time. + /// + protected User CurrentUser + { + get + { + return (_user == null ? (_user = UmbracoEnsuredPage.CurrentUser) : _user); + } + } + public override void RenderJS(ref StringBuilder Javascript) { if (!string.IsNullOrEmpty(this.FunctionToCall)) @@ -54,7 +54,7 @@ namespace umbraco.cms.presentation.Trees else if (!this.IsDialog) { Javascript.Append( - @" + @" function openMedia(id) { " + ClientTools.Scripts.GetContentFrame() + ".location.href = 'editMedia.aspx?id=' + id;" + @" } @@ -98,12 +98,12 @@ function openMedia(id) { // to call so that is fine. var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Media).ToArray(); - + foreach (UmbracoEntity entity in entities) { var e = entity; var xNode = PerformNodeRender(e.Id, entity.Name, e.HasChildren, e.ContentTypeIcon, e.ContentTypeAlias, () => GetLinkValue(e)); - + OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty); if (xNode != null) { @@ -111,7 +111,7 @@ function openMedia(id) { OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty); } } - } + } } private XmlTreeNode PerformNodeRender(int nodeId, string nodeName, bool hasChildren, string icon, string contentTypeAlias, Func getLinkValue) @@ -164,28 +164,28 @@ function openMedia(id) { return xNode; } - + /// - /// Returns the value for a link in WYSIWYG mode, by default only media items that have a - /// DataTypeUploadField are linkable, however, a custom tree can be created which overrides - /// this method, or another GUID for a custom data type can be added to the LinkableMediaDataTypes - /// list on application startup. - /// - /// - /// - /// + /// Returns the value for a link in WYSIWYG mode, by default only media items that have a + /// DataTypeUploadField are linkable, however, a custom tree can be created which overrides + /// this method, or another GUID for a custom data type can be added to the LinkableMediaDataTypes + /// list on application startup. + /// + /// + /// + /// public virtual string GetLinkValue(Media dd, string nodeLink) { var props = dd.GenericProperties; - foreach (Property p in props) - { - Guid currId = p.PropertyType.DataTypeDefinition.DataType.Id; - if (LinkableMediaDataTypes.Contains(currId) && string.IsNullOrEmpty(p.Value.ToString()) == false) - { - return p.Value.ToString(); - } - } + foreach (Property p in props) + { + Guid currId = p.PropertyType.DataTypeDefinition.DataType.Id; + if (LinkableMediaDataTypes.Contains(currId) && string.IsNullOrEmpty(p.Value.ToString()) == false) + { + return p.Value.ToString(); + } + } return ""; } @@ -200,34 +200,29 @@ function openMedia(id) { /// internal virtual string GetLinkValue(UmbracoEntity entity) { - foreach (var property in entity.AdditionalData - .Select(x => x.Value as UmbracoEntity.EntityProperty) - .Where(x => x != null)) + foreach (var property in entity.UmbracoProperties) { - - //required for backwards compatibility with v7 with changing the GUID -> alias var controlId = LegacyPropertyEditorIdToAliasConverter.GetLegacyIdFromAlias(property.PropertyEditorAlias, LegacyPropertyEditorIdToAliasConverter.NotFoundLegacyIdResponseBehavior.ReturnNull); if (controlId != null) { - if (LinkableMediaDataTypes.Contains(controlId.Value) - && string.IsNullOrEmpty((string)property.Value) == false) - - return property.Value.ToString(); - } + if (LinkableMediaDataTypes.Contains(controlId.Value) && + string.IsNullOrEmpty(property.Value) == false) + return property.Value; + } } return ""; } - /// - /// By default, any media type that is to be "linkable" in the WYSIWYG editor must contain - /// a DataTypeUploadField data type which will ouput the value for the link, however, if - /// a developer wants the WYSIWYG editor to link to a custom media type, they will either have - /// to create their own media tree and inherit from this one and override the GetLinkValue - /// or add another GUID to the LinkableMediaDataType list on application startup that matches - /// the GUID of a custom data type. The order of property types on the media item definition will determine the output value. - /// - public static List LinkableMediaDataTypes { get; protected set; } + /// + /// By default, any media type that is to be "linkable" in the WYSIWYG editor must contain + /// a DataTypeUploadField data type which will ouput the value for the link, however, if + /// a developer wants the WYSIWYG editor to link to a custom media type, they will either have + /// to create their own media tree and inherit from this one and override the GetLinkValue + /// or add another GUID to the LinkableMediaDataType list on application startup that matches + /// the GUID of a custom data type. The order of property types on the media item definition will determine the output value. + /// + public static List LinkableMediaDataTypes { get; protected set; } /// /// Returns true if we can use the EntityService to render the tree or revert to the original way @@ -250,5 +245,5 @@ function openMedia(id) { } } - } + } }