Merge branch 'v14/dev' into contrib
This commit is contained in:
@@ -13,7 +13,7 @@ public static partial class Constants
|
||||
public static readonly string[] UmbracoCoreAssemblyNames =
|
||||
{
|
||||
"Umbraco.Core", "Umbraco.Infrastructure", "Umbraco.PublishedCache.NuCache", "Umbraco.Examine.Lucene",
|
||||
"Umbraco.Web.Common", "Umbraco.Web.BackOffice", "Umbraco.Web.Website",
|
||||
"Umbraco.Web.Common", "Umbraco.Cms.Api.Common","Umbraco.Cms.Api.Delivery","Umbraco.Cms.Api.Management", "Umbraco.Web.Website",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using Umbraco.Cms.Core.Models.Entities;
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods that return udis for Umbraco entities.
|
||||
/// Provides extension methods that return UDIs for Umbraco entities.
|
||||
/// </summary>
|
||||
public static class UdiGetterExtensions
|
||||
{
|
||||
@@ -19,11 +19,177 @@ public static class UdiGetterExtensions
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this ITemplate entity)
|
||||
public static Udi GetUdi(this IEntity entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.Template, entity.Key).EnsureClosed();
|
||||
return entity switch
|
||||
{
|
||||
// Concrete types
|
||||
EntityContainer container => container.GetUdi(),
|
||||
Script script => script.GetUdi(),
|
||||
Stylesheet stylesheet => stylesheet.GetUdi(),
|
||||
// Interfaces
|
||||
IContentBase contentBase => contentBase.GetUdi(),
|
||||
IContentTypeComposition contentTypeComposition => contentTypeComposition.GetUdi(),
|
||||
IDataType dataType => dataType.GetUdi(),
|
||||
IDictionaryItem dictionaryItem => dictionaryItem.GetUdi(),
|
||||
ILanguage language => language.GetUdi(),
|
||||
IMemberGroup memberGroup => memberGroup.GetUdi(),
|
||||
IPartialView partialView => partialView.GetUdi(),
|
||||
IRelationType relationType => relationType.GetUdi(),
|
||||
ITemplate template => template.GetUdi(),
|
||||
IWebhook webhook => webhook.GetUdi(),
|
||||
_ => throw new NotSupportedException($"Entity type {entity.GetType().FullName} is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this EntityContainer entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
string entityType;
|
||||
if (entity.ContainedObjectType == Constants.ObjectTypes.DataType)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.DataTypeContainer;
|
||||
}
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentType)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.DocumentTypeContainer;
|
||||
}
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.MediaType)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.MediaTypeContainer;
|
||||
}
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentBlueprint)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.DocumentBlueprintContainer;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"Contained object type {entity.ContainedObjectType} is not supported.");
|
||||
}
|
||||
|
||||
return new GuidUdi(entityType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this Script entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return GetUdiFromPath(Constants.UdiEntityType.Script, entity.Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this Stylesheet entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return GetUdiFromPath(Constants.UdiEntityType.Stylesheet, entity.Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IContentBase entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return entity switch
|
||||
{
|
||||
IContent content => content.GetUdi(),
|
||||
IMedia media => media.GetUdi(),
|
||||
IMember member => member.GetUdi(),
|
||||
_ => throw new NotSupportedException($"Content base type {entity.GetType().FullName} is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IContent entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
string entityType = entity.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document;
|
||||
|
||||
return new GuidUdi(entityType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IMedia entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.Media, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IMember entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.Member, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IContentTypeComposition entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return entity switch
|
||||
{
|
||||
IContentType contentType => contentType.GetUdi(),
|
||||
IMediaType mediaType => mediaType.GetUdi(),
|
||||
IMemberType memberType => memberType.GetUdi(),
|
||||
_ => throw new NotSupportedException($"Composition type {entity.GetType().FullName} is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,42 +234,6 @@ public static class UdiGetterExtensions
|
||||
return new GuidUdi(Constants.UdiEntityType.MemberType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IMemberGroup entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.MemberGroup, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IContentTypeComposition entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
string entityType = entity switch
|
||||
{
|
||||
IContentType => Constants.UdiEntityType.DocumentType,
|
||||
IMediaType => Constants.UdiEntityType.MediaType,
|
||||
IMemberType => Constants.UdiEntityType.MemberType,
|
||||
_ => throw new NotSupportedException(string.Format("Composition type {0} is not supported.", entity.GetType().FullName)),
|
||||
};
|
||||
|
||||
return new GuidUdi(entityType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
@@ -118,129 +248,6 @@ public static class UdiGetterExtensions
|
||||
return new GuidUdi(Constants.UdiEntityType.DataType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this EntityContainer entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
string entityType;
|
||||
if (entity.ContainedObjectType == Constants.ObjectTypes.DataType)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.DataTypeContainer;
|
||||
}
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentType)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.DocumentTypeContainer;
|
||||
}
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.MediaType)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.MediaTypeContainer;
|
||||
}
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentBlueprint)
|
||||
{
|
||||
entityType = Constants.UdiEntityType.DocumentBlueprintContainer;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException(string.Format("Contained object type {0} is not supported.", entity.ContainedObjectType));
|
||||
}
|
||||
|
||||
return new GuidUdi(entityType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IMedia entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.Media, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IContent entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
string entityType = entity.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document;
|
||||
|
||||
return new GuidUdi(entityType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IMember entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.Member, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this Stylesheet entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return GetUdiFromPath(Constants.UdiEntityType.Stylesheet, entity.Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this Script entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return GetUdiFromPath(Constants.UdiEntityType.Script, entity.Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UDI from a path.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The type of the entity.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
private static StringUdi GetUdiFromPath(string entityType, string path)
|
||||
{
|
||||
string id = path.TrimStart(Constants.CharArrays.ForwardSlash).Replace("\\", "/");
|
||||
|
||||
return new StringUdi(entityType, id).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
@@ -262,11 +269,11 @@ public static class UdiGetterExtensions
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this IPartialView entity)
|
||||
public static StringUdi GetUdi(this ILanguage entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return GetUdiFromPath(Constants.UdiEntityType.PartialView, entity.Path);
|
||||
return new StringUdi(Constants.UdiEntityType.Language, entity.IsoCode).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -276,19 +283,25 @@ public static class UdiGetterExtensions
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this IContentBase entity)
|
||||
public static GuidUdi GetUdi(this IMemberGroup entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
string type = entity switch
|
||||
{
|
||||
IContent => Constants.UdiEntityType.Document,
|
||||
IMedia => Constants.UdiEntityType.Media,
|
||||
IMember => Constants.UdiEntityType.Member,
|
||||
_ => throw new NotSupportedException(string.Format("Content base type {0} is not supported.", entity.GetType().FullName)),
|
||||
};
|
||||
return new GuidUdi(Constants.UdiEntityType.MemberGroup, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
return new GuidUdi(type, entity.Key).EnsureClosed();
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this IPartialView entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return GetUdiFromPath(Constants.UdiEntityType.PartialView, entity.Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -305,6 +318,20 @@ public static class UdiGetterExtensions
|
||||
return new GuidUdi(Constants.UdiEntityType.RelationType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static GuidUdi GetUdi(this ITemplate entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return new GuidUdi(Constants.UdiEntityType.Template, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
@@ -320,56 +347,17 @@ public static class UdiGetterExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// Gets the UDI from a path.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <param name="entityType">The type of the entity.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static StringUdi GetUdi(this ILanguage entity)
|
||||
private static StringUdi GetUdiFromPath(string entityType, string path)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
string id = path.TrimStart(Constants.CharArrays.ForwardSlash).Replace("\\", "/");
|
||||
|
||||
return new StringUdi(Constants.UdiEntityType.Language, entity.IsoCode).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>
|
||||
/// The entity identifier of the entity.
|
||||
/// </returns>
|
||||
public static Udi GetUdi(this IEntity entity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
|
||||
return entity switch
|
||||
{
|
||||
// Concrete types
|
||||
EntityContainer container => container.GetUdi(),
|
||||
Stylesheet stylesheet => stylesheet.GetUdi(),
|
||||
Script script => script.GetUdi(),
|
||||
// Content types
|
||||
IContentType contentType => contentType.GetUdi(),
|
||||
IMediaType mediaType => mediaType.GetUdi(),
|
||||
IMemberType memberType => memberType.GetUdi(),
|
||||
IContentTypeComposition contentTypeComposition => contentTypeComposition.GetUdi(),
|
||||
// Content
|
||||
IContent content => content.GetUdi(),
|
||||
IMedia media => media.GetUdi(),
|
||||
IMember member => member.GetUdi(),
|
||||
IContentBase contentBase => contentBase.GetUdi(),
|
||||
// Other
|
||||
IDataType dataTypeComposition => dataTypeComposition.GetUdi(),
|
||||
IDictionaryItem dictionaryItem => dictionaryItem.GetUdi(),
|
||||
ILanguage language => language.GetUdi(),
|
||||
IMemberGroup memberGroup => memberGroup.GetUdi(),
|
||||
IPartialView partialView => partialView.GetUdi(),
|
||||
IRelationType relationType => relationType.GetUdi(),
|
||||
ITemplate template => template.GetUdi(),
|
||||
IWebhook webhook => webhook.GetUdi(),
|
||||
_ => throw new NotSupportedException(string.Format("Entity type {0} is not supported.", entity.GetType().FullName)),
|
||||
};
|
||||
return new StringUdi(entityType, id).EnsureClosed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,16 @@ namespace Umbraco.Cms.Core.Media.EmbedProviders;
|
||||
/// Wrapper class for OEmbed response.
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class OEmbedResponse : OEmbedResponseBase<double>;
|
||||
public class OEmbedResponse : OEmbedResponseBase<double>
|
||||
{
|
||||
|
||||
// these is only here to avoid breaking changes. In theory it should still be source code compatible to remove them.
|
||||
public new double? ThumbnailHeight => base.ThumbnailHeight;
|
||||
|
||||
public new double? ThumbnailWidth => base.ThumbnailWidth;
|
||||
|
||||
public new double? Height => base.Height;
|
||||
|
||||
public new double? Width => base.Width;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public abstract class OEmbedResponseBase<T>
|
||||
public string? ThumbnailUrl { get; set; }
|
||||
|
||||
[DataMember(Name = "thumbnail_height")]
|
||||
public T? ThumbnailHeight { get; set; }
|
||||
public virtual T? ThumbnailHeight { get; set; }
|
||||
|
||||
[DataMember(Name = "thumbnail_width")]
|
||||
public T? ThumbnailWidth { get; set; }
|
||||
|
||||
@@ -16,14 +16,10 @@ public class UpgradeCheckRepository : IUpgradeCheckRepository
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_httpClient == null)
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
_httpClient ??= new HttpClient { Timeout = TimeSpan.FromSeconds(1) };
|
||||
|
||||
using var content = new StringContent(_jsonSerializer.Serialize(new CheckUpgradeDto(version)), Encoding.UTF8, "application/json");
|
||||
|
||||
_httpClient.Timeout = TimeSpan.FromSeconds(1);
|
||||
using HttpResponseMessage task = await _httpClient.PostAsync(RestApiUpgradeChecklUrl, content);
|
||||
var json = await task.Content.ReadAsStringAsync();
|
||||
UpgradeResult? result = _jsonSerializer.Deserialize<UpgradeResult>(json);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.Validators;
|
||||
/// <summary>
|
||||
/// A validator that validates that the value is not null or empty (if it is a string)
|
||||
/// </summary>
|
||||
public sealed class RequiredValidator : IValueRequiredValidator, IValueValidator
|
||||
public class RequiredValidator : IValueRequiredValidator, IValueValidator
|
||||
{
|
||||
[Obsolete($"Use the constructor that does not accept {nameof(ILocalizedTextService)}. Will be removed in V15.")]
|
||||
public RequiredValidator(ILocalizedTextService textService)
|
||||
@@ -24,7 +24,7 @@ public sealed class RequiredValidator : IValueRequiredValidator, IValueValidator
|
||||
ValidateRequired(value, valueType);
|
||||
|
||||
/// <inheritdoc cref="IValueRequiredValidator.ValidateRequired" />
|
||||
public IEnumerable<ValidationResult> ValidateRequired(object? value, string? valueType)
|
||||
public virtual IEnumerable<ValidationResult> ValidateRequired(object? value, string? valueType)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -12,7 +16,11 @@ internal sealed class ContentEditingService
|
||||
{
|
||||
private readonly ITemplateService _templateService;
|
||||
private readonly ILogger<ContentEditingService> _logger;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly ILanguageService _languageService;
|
||||
|
||||
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 16.")]
|
||||
public ContentEditingService(
|
||||
IContentService contentService,
|
||||
IContentTypeService contentTypeService,
|
||||
@@ -24,10 +32,46 @@ internal sealed class ContentEditingService
|
||||
IUserIdKeyResolver userIdKeyResolver,
|
||||
ITreeEntitySortingService treeEntitySortingService,
|
||||
IContentValidationService contentValidationService)
|
||||
: this(
|
||||
contentService,
|
||||
contentTypeService,
|
||||
propertyEditorCollection,
|
||||
dataTypeService,
|
||||
templateService,
|
||||
logger,
|
||||
scopeProvider,
|
||||
userIdKeyResolver,
|
||||
treeEntitySortingService,
|
||||
contentValidationService,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IUserService>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILanguageService>()
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ContentEditingService(
|
||||
IContentService contentService,
|
||||
IContentTypeService contentTypeService,
|
||||
PropertyEditorCollection propertyEditorCollection,
|
||||
IDataTypeService dataTypeService,
|
||||
ITemplateService templateService,
|
||||
ILogger<ContentEditingService> logger,
|
||||
ICoreScopeProvider scopeProvider,
|
||||
IUserIdKeyResolver userIdKeyResolver,
|
||||
ITreeEntitySortingService treeEntitySortingService,
|
||||
IContentValidationService contentValidationService,
|
||||
IUserService userService,
|
||||
ILocalizationService localizationService,
|
||||
ILanguageService languageService)
|
||||
: base(contentService, contentTypeService, propertyEditorCollection, dataTypeService, logger, scopeProvider, userIdKeyResolver, contentValidationService, treeEntitySortingService)
|
||||
{
|
||||
_templateService = templateService;
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
_localizationService = localizationService;
|
||||
_languageService = languageService;
|
||||
}
|
||||
|
||||
public async Task<IContent?> GetAsync(Guid key)
|
||||
@@ -65,7 +109,7 @@ internal sealed class ContentEditingService
|
||||
ContentEditingOperationStatus validationStatus = result.Status;
|
||||
ContentValidationResult validationResult = result.Result.ValidationResult;
|
||||
|
||||
IContent content = result.Result.Content!;
|
||||
IContent content = await EnsureOnlyAllowedFieldsAreUpdated(result.Result.Content!, userKey);
|
||||
ContentEditingOperationStatus updateTemplateStatus = await UpdateTemplateAsync(content, createModel.TemplateKey);
|
||||
if (updateTemplateStatus != ContentEditingOperationStatus.Success)
|
||||
{
|
||||
@@ -78,6 +122,53 @@ internal sealed class ContentEditingService
|
||||
: Attempt.FailWithStatus(saveStatus, new ContentCreateResult { Content = content });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A temporary method that ensures the data is sent in is overridden by the original data, in cases where the user do not have permissions to change the data.
|
||||
/// </summary>
|
||||
private async Task<IContent> EnsureOnlyAllowedFieldsAreUpdated(IContent contentWithPotentialUnallowedChanges, Guid userKey)
|
||||
{
|
||||
if (contentWithPotentialUnallowedChanges.ContentType.VariesByCulture() is false)
|
||||
{
|
||||
return contentWithPotentialUnallowedChanges;
|
||||
}
|
||||
|
||||
IContent? existingContent = await GetAsync(contentWithPotentialUnallowedChanges.Key);
|
||||
|
||||
IUser? user = await _userService.GetAsync(userKey);
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
return contentWithPotentialUnallowedChanges;
|
||||
}
|
||||
|
||||
var allowedLanguageIds = user.CalculateAllowedLanguageIds(_localizationService)!;
|
||||
|
||||
var allowedCultures = (await _languageService.GetIsoCodesByIdsAsync(allowedLanguageIds)).ToHashSet();
|
||||
|
||||
foreach (var culture in contentWithPotentialUnallowedChanges.EditedCultures ?? contentWithPotentialUnallowedChanges.PublishedCultures)
|
||||
{
|
||||
if (allowedCultures.Contains(culture))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// else override the updates values with the original values.
|
||||
foreach (IProperty property in contentWithPotentialUnallowedChanges.Properties)
|
||||
{
|
||||
if (property.PropertyType.VariesByCulture() is false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var value = existingContent?.Properties.First(x=>x.Alias == property.Alias).GetValue(culture, null, false);
|
||||
property.SetValue(value, culture, null);
|
||||
}
|
||||
}
|
||||
|
||||
return contentWithPotentialUnallowedChanges;
|
||||
}
|
||||
|
||||
public async Task<Attempt<ContentUpdateResult, ContentEditingOperationStatus>> UpdateAsync(Guid key, ContentUpdateModel updateModel, Guid userKey)
|
||||
{
|
||||
IContent? content = ContentService.GetById(key);
|
||||
@@ -102,6 +193,8 @@ internal sealed class ContentEditingService
|
||||
ContentEditingOperationStatus validationStatus = result.Status;
|
||||
ContentValidationResult validationResult = result.Result.ValidationResult;
|
||||
|
||||
content = await EnsureOnlyAllowedFieldsAreUpdated(content, userKey);
|
||||
|
||||
ContentEditingOperationStatus updateTemplateStatus = await UpdateTemplateAsync(content, updateModel.TemplateKey);
|
||||
if (updateTemplateStatus != ContentEditingOperationStatus.Success)
|
||||
{
|
||||
|
||||
@@ -523,8 +523,6 @@ public class FileService : RepositoryService, IFileService
|
||||
/// </summary>
|
||||
/// <param name="templates">List of <see cref="Template" /> to save</param>
|
||||
/// <param name="userId">Optional id of the user</param>
|
||||
// FIXME: we need to re-implement PackageDataInstallation.ImportTemplates so it imports templates in the correct order
|
||||
// instead of relying on being able to save invalid templates (child templates whose master has yet to be created)
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public void SaveTemplate(IEnumerable<ITemplate> templates, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
|
||||
@@ -196,7 +196,7 @@ public interface IDataTypeService : IService
|
||||
/// </summary>
|
||||
/// <param name="propertyEditorAlias">Alias of the property editor</param>
|
||||
/// <returns>Collection of <see cref="IDataType" /> configured for the property editor</returns>
|
||||
Task<IEnumerable<IDataType>> GetByEditorAliasAsync(string propertyEditorAlias);
|
||||
Task<IEnumerable<IDataType>> GetByEditorAliasAsync(string propertyEditorAlias) => Task.FromResult(GetByEditorAlias(propertyEditorAlias));
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="IDataType" /> for a given editor UI alias
|
||||
@@ -246,5 +246,5 @@ public interface IDataTypeService : IService
|
||||
/// </summary>
|
||||
/// <param name="propertyEditorAlias">Aliases of the property editors</param>
|
||||
/// <returns>Collection of <see cref="IDataType" /> configured for the property editors</returns>
|
||||
Task<IEnumerable<IDataType>> GetByEditorAliasAsync(string[] propertyEditorAlias);
|
||||
Task<IEnumerable<IDataType>> GetByEditorAliasAsync(string[] propertyEditorAlias) => Task.FromResult(propertyEditorAlias.SelectMany(x=>GetByEditorAlias(x)));
|
||||
}
|
||||
|
||||
@@ -13,4 +13,8 @@ namespace Umbraco.Cms.Core.Services;
|
||||
public interface IIndexedEntitySearchService
|
||||
{
|
||||
PagedModel<IEntitySlim> Search(UmbracoObjectTypes objectType, string query, int skip = 0, int take = 100, bool ignoreUserStartNodes = false);
|
||||
|
||||
// default implementation to avoid breaking changes falls back to old behaviour
|
||||
PagedModel<IEntitySlim> Search(UmbracoObjectTypes objectType, string query, Guid? parentId, int skip = 0, int take = 100, bool ignoreUserStartNodes = false)
|
||||
=> Search(objectType,query, skip, take, ignoreUserStartNodes);
|
||||
}
|
||||
|
||||
@@ -65,16 +65,28 @@ public interface IPackageDataInstallation
|
||||
/// <returns>An enumerable list of generated languages</returns>
|
||||
IReadOnlyList<ILanguage> ImportLanguages(IEnumerable<XElement> languageElements, int userId);
|
||||
|
||||
[Obsolete("Use Async version instead, Scheduled to be removed in v17")]
|
||||
IEnumerable<ITemplate> ImportTemplate(XElement templateElement, int userId);
|
||||
|
||||
Task<IEnumerable<ITemplate>> ImportTemplateAsync(XElement templateElement, int userId) => Task.FromResult(ImportTemplate(templateElement, userId));
|
||||
|
||||
/// <summary>
|
||||
/// Imports and saves package xml as <see cref="ITemplate"/>
|
||||
/// </summary>
|
||||
/// <param name="templateElements">Xml to import</param>
|
||||
/// <param name="userId">Optional user id</param>
|
||||
/// <returns>An enumerable list of generated Templates</returns>
|
||||
[Obsolete("Use Async version instead, Scheduled to be removed in v17")]
|
||||
IReadOnlyList<ITemplate> ImportTemplates(IReadOnlyCollection<XElement> templateElements, int userId);
|
||||
|
||||
/// <summary>
|
||||
/// Imports and saves package xml as <see cref="ITemplate"/>
|
||||
/// </summary>
|
||||
/// <param name="templateElements">Xml to import</param>
|
||||
/// <param name="userId">Optional user id</param>
|
||||
/// <returns>An enumerable list of generated Templates</returns>
|
||||
Task<IReadOnlyList<ITemplate>> ImportTemplatesAsync(IReadOnlyCollection<XElement> templateElements, int userId) => Task.FromResult(ImportTemplates(templateElements, userId));
|
||||
|
||||
Guid GetContentTypeKey(XElement contentType);
|
||||
|
||||
string? GetEntityTypeAlias(XElement entityType);
|
||||
|
||||
@@ -5,10 +5,7 @@ public enum ContentTypeOperationStatus
|
||||
Success,
|
||||
DuplicateAlias,
|
||||
InvalidAlias,
|
||||
NameCannotBeEmpty,
|
||||
NameTooLong,
|
||||
InvalidPropertyTypeAlias,
|
||||
PropertyTypeAliasCannotEqualContentTypeAlias,
|
||||
DuplicatePropertyTypeAlias,
|
||||
DataTypeNotFound,
|
||||
InvalidInheritance,
|
||||
@@ -21,6 +18,9 @@ public enum ContentTypeOperationStatus
|
||||
NotFound,
|
||||
NotAllowed,
|
||||
CancelledByNotification,
|
||||
PropertyTypeAliasCannotEqualContentTypeAlias,
|
||||
NameCannotBeEmpty,
|
||||
NameTooLong,
|
||||
InvalidElementFlagDocumentHasContent,
|
||||
InvalidElementFlagElementIsUsedInPropertyEditorConfiguration,
|
||||
InvalidElementFlagComparedToParent,
|
||||
|
||||
Reference in New Issue
Block a user