Merge branch 'v14/dev' into contrib

This commit is contained in:
Sebastiaan Janssen
2024-09-27 08:54:49 +02:00
147 changed files with 6317 additions and 1436 deletions

View File

@@ -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",
};
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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; }

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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)));
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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,