diff --git a/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs b/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs index 39ece5fa10..8536b1ded3 100644 --- a/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs +++ b/src/Umbraco.Core/Models/Entities/DocumentEntitySlim.cs @@ -3,6 +3,7 @@ using System.Linq; namespace Umbraco.Core.Models.Entities { + /// /// Implements . /// diff --git a/src/Umbraco.Core/Models/Entities/EntitySlim.cs b/src/Umbraco.Core/Models/Entities/EntitySlim.cs index 3b8f997602..b095965056 100644 --- a/src/Umbraco.Core/Models/Entities/EntitySlim.cs +++ b/src/Umbraco.Core/Models/Entities/EntitySlim.cs @@ -111,52 +111,6 @@ namespace Umbraco.Core.Models.Entities public virtual bool IsContainer { get; set; } - /// - /// Represents a lightweight property. - /// - public class PropertySlim - { - /// - /// Initializes a new instance of the class. - /// - public PropertySlim(string editorAlias, object value) - { - PropertyEditorAlias = editorAlias; - Value = value; - } - - /// - /// Gets the property editor alias. - /// - public string PropertyEditorAlias { get; } - - /// - /// Gets the property value. - /// - public object Value { get; } - - protected bool Equals(PropertySlim other) - { - return PropertyEditorAlias.Equals(other.PropertyEditorAlias) && Equals(Value, other.Value); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((PropertySlim) obj); - } - - public override int GetHashCode() - { - unchecked - { - return (PropertyEditorAlias.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0); - } - } - } - #region IDeepCloneable /// diff --git a/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs b/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs index 38fd9a02f1..0258d49114 100644 --- a/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs +++ b/src/Umbraco.Core/Models/Entities/IDocumentEntitySlim.cs @@ -2,6 +2,7 @@ namespace Umbraco.Core.Models.Entities { + /// /// Represents a lightweight document entity, managed by the entity service. /// diff --git a/src/Umbraco.Core/Models/Entities/IMediaEntitySlim.cs b/src/Umbraco.Core/Models/Entities/IMediaEntitySlim.cs new file mode 100644 index 0000000000..9440000146 --- /dev/null +++ b/src/Umbraco.Core/Models/Entities/IMediaEntitySlim.cs @@ -0,0 +1,14 @@ +namespace Umbraco.Core.Models.Entities +{ + /// + /// Represents a lightweight media entity, managed by the entity service. + /// + public interface IMediaEntitySlim : IContentEntitySlim + { + + /// + /// The media file's path/url + /// + string MediaPath { get; } + } +} diff --git a/src/Umbraco.Core/Models/Entities/MediaEntitySlim.cs b/src/Umbraco.Core/Models/Entities/MediaEntitySlim.cs new file mode 100644 index 0000000000..6292a5a35a --- /dev/null +++ b/src/Umbraco.Core/Models/Entities/MediaEntitySlim.cs @@ -0,0 +1,10 @@ +namespace Umbraco.Core.Models.Entities +{ + /// + /// Implements . + /// + public class MediaEntitySlim : ContentEntitySlim, IMediaEntitySlim + { + public string MediaPath { get; set; } + } +} diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs index 9983f97d70..30de08edc5 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs @@ -75,6 +75,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement dtos = page.Items; totalRecords = page.TotalItems; } + else if (isMedia) + { + var page = Database.Page(pageIndexToFetch, pageSize, sql); + dtos = page.Items; + totalRecords = page.TotalItems; + } else { var page = Database.Page(pageIndexToFetch, pageSize, sql); @@ -87,10 +93,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (isContent) BuildVariants(entities.Cast()); - //// TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media - //if (isMedia) - // BuildProperties(entities, dtos.ToList()); - return entities; } @@ -112,14 +114,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return cdtos.Count == 0 ? null : BuildVariants(BuildDocumentEntity(cdtos[0])); } - var dto = Database.FirstOrDefault(sql); + var dto = isMedia + ? Database.FirstOrDefault(sql) + : Database.FirstOrDefault(sql); + if (dto == null) return null; var entity = BuildEntity(false, isMedia, dto); - //if (isMedia) - // BuildProperties(entity, dto); - return entity; } @@ -174,15 +176,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : BuildVariants(cdtos.Select(BuildDocumentEntity)).ToList(); } - var dtos = Database.Fetch(sql); - if (dtos.Count == 0) return Enumerable.Empty(); + var dtos = isMedia + ? (IEnumerable)Database.Fetch(sql) + : Database.Fetch(sql); var entities = dtos.Select(x => BuildEntity(false, isMedia, x)).ToArray(); - //// TODO: See https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media - //if (isMedia && loadMediaProperties) - // BuildProperties(entities, dtos); - return entities; } @@ -424,7 +423,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // gets the base SELECT + FROM [+ filter] sql // always from the 'current' content version protected Sql GetBase(bool isContent, bool isMedia, Action> filter, bool isCount = false) - { + { var sql = Sql(); if (isCount) @@ -448,6 +447,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement sql .AndSelect(x => x.Published, x => x.Edited); } + + if (isMedia) + { + sql + .AndSelect(x => Alias(x.Path, "MediaPath")); + } } sql @@ -467,6 +472,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement .InnerJoin().On((left, right) => left.NodeId == right.NodeId); } + if (isMedia) + { + sql + .InnerJoin().On((left, right) => left.Id == right.Id); + } + //Any LeftJoin statements need to come last if (isCount == false) { @@ -536,6 +547,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement .AndBy(x => x.Published, x => x.Edited); } + if (isMedia) + { + sql + .AndBy(x => Alias(x.Path, "MediaPath")); + } + if (isContent || isMedia) sql @@ -594,6 +611,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public bool Edited { get; set; } } + private class MediaEntityDto : BaseDto + { + public string MediaPath { get; set; } + } + public class VariantInfoDto { public int NodeId { get; set; } @@ -645,7 +667,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (isContent) return BuildDocumentEntity(dto); if (isMedia) - return BuildContentEntity(dto); + return BuildMediaEntity(dto); // EntitySlim does not track changes var entity = new EntitySlim(); @@ -678,11 +700,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.ContentTypeThumbnail = dto.Thumbnail; } - private static EntitySlim BuildContentEntity(BaseDto dto) + private MediaEntitySlim BuildMediaEntity(BaseDto dto) { // EntitySlim does not track changes - var entity = new ContentEntitySlim(); + var entity = new MediaEntitySlim(); BuildContentEntity(entity, dto); + + if (dto is MediaEntityDto contentDto) + { + // fill in the media info + entity.MediaPath = contentDto.MediaPath; + } + return entity; } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 8a6acc107e..4f165f9914 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -249,6 +249,8 @@ + + diff --git a/src/Umbraco.Tests/Models/LightEntityTest.cs b/src/Umbraco.Tests/Models/LightEntityTest.cs index f1752a7681..41ce830cff 100644 --- a/src/Umbraco.Tests/Models/LightEntityTest.cs +++ b/src/Umbraco.Tests/Models/LightEntityTest.cs @@ -37,9 +37,7 @@ namespace Umbraco.Tests.Models }; item.AdditionalData.Add("test1", 3); item.AdditionalData.Add("test2", "valuie"); - item.AdditionalData.Add("test3", new EntitySlim.PropertySlim("TestPropertyEditor", "test")); - item.AdditionalData.Add("test4", new EntitySlim.PropertySlim("TestPropertyEditor2", "test2")); - + var result = ss.ToStream(item); var json = result.ResultStream.ToJsonString(); Debug.Print(json); // FIXME: compare with v7 diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests/Services/EntityServiceTests.cs index 2425f8b74a..0598b8cea2 100644 --- a/src/Umbraco.Tests/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests/Services/EntityServiceTests.cs @@ -675,15 +675,10 @@ namespace Umbraco.Tests.Services foreach (var entity in entities) { - Console.WriteLine(); - foreach (var data in entity.AdditionalData) - { - Console.WriteLine($"{entity.Id} {data.Key} {data.Value} {(data.Value is EntitySlim.PropertySlim p ? p.PropertyEditorAlias : "")}"); - } + Assert.IsTrue(entity.GetType().Implements()); + Console.WriteLine(((IMediaEntitySlim)entity).MediaPath); + Assert.IsNotEmpty(((IMediaEntitySlim)entity).MediaPath); } - - Assert.That(entities.Any(x => - x.AdditionalData.Any(y => y.Value is EntitySlim.PropertySlim && ((EntitySlim.PropertySlim)y.Value).PropertyEditorAlias == Constants.PropertyEditors.Aliases.UploadField)), Is.True); } [Test] 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 16c5b38a79..d85a59d836 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 @@ -143,27 +143,21 @@ function mediaHelper(umbRequestHelper) { */ resolveFileFromEntity: function (mediaEntity, thumbnail) { - if (!angular.isObject(mediaEntity.metaData)) { + if (!angular.isObject(mediaEntity.metaData) || !mediaEntity.metaData.MediaPath) { 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); - } - } + if (thumbnail) { + if (this.detectIfImageByExtension(mediaEntity.metaData.MediaPath)) { + return this.getThumbnailFromPath(mediaEntity.metaData.MediaPath); + } + else { + return null; } } - - return ""; + else { + return mediaEntity.metaData.MediaPath; + } }, /** diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index 0eb0f54882..b29c166765 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -61,7 +61,7 @@ namespace Umbraco.Web.Editors //redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file var response = Request.CreateResponse(HttpStatusCode.Found); var imageLastModified = _mediaFileSystem.GetLastModified(imagePath); - response.Headers.Location = new Uri($"{imagePath}?rnd={imageLastModified:yyyyMMddHHmmss}&upscale=false&width={width}", UriKind.Relative); + response.Headers.Location = new Uri($"{imagePath}?rnd={imageLastModified:yyyyMMddHHmmss}&upscale=false&width={width}&animationprocessmode=first&mode=max", UriKind.Relative); return response; } diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs index 94698f84bd..2598523bd5 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs @@ -45,6 +45,12 @@ namespace Umbraco.Web.Models.Mapping if (source.NodeObjectType == Constants.ObjectTypes.Member && target.Icon.IsNullOrWhiteSpace()) target.Icon = "icon-user"; + if (source.NodeObjectType == Constants.ObjectTypes.Media && source is IContentEntitySlim contentSlim) + source.AdditionalData["ContentTypeAlias"] = contentSlim.ContentTypeAlias; + + if (source.NodeObjectType == Constants.ObjectTypes.Media && source is IMediaEntitySlim mediaSlim) + source.AdditionalData["MediaPath"] = mediaSlim.MediaPath; + // NOTE: we're mapping the objects in AdditionalData by object reference here. // it works fine for now, but it's something to keep in mind in the future foreach(var kvp in source.AdditionalData)