Fixes issues with creation of documents from blueprints that have populated file upload properties (#19655)
* Fixes issue where content created from blueprint would not persist file upload property values. * Ensure a copy of a file upload is created when scaffolding content from a blueprint, like we do when copying content. * Clarified comment. * Removed unneeded usings. * Fixed spelling. * Handle create of blueprint from content to create a new uploaded file. Handle delete of blueprint to delete uploaded files.
This commit is contained in:
@@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// A notification that is used to trigger the IContentService when the SavedBlueprint method is called in the API.
|
||||
/// </summary>
|
||||
@@ -14,8 +15,21 @@ public sealed class ContentSavedBlueprintNotification : ObjectNotification<ICont
|
||||
: base(target, messages)
|
||||
{
|
||||
}
|
||||
|
||||
public ContentSavedBlueprintNotification(IContent target, IContent? createdFromContent, EventMessages messages)
|
||||
: base(target, messages)
|
||||
{
|
||||
CreatedFromContent = createdFromContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Getting the saved blueprint <see cref="IContent"/> object.
|
||||
/// </summary>
|
||||
public IContent SavedBlueprint => Target;
|
||||
|
||||
/// <summary>
|
||||
/// Getting the saved blueprint <see cref="IContent"/> object.
|
||||
/// </summary>
|
||||
public IContent? CreatedFromContent { get; }
|
||||
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ internal sealed class ContentBlueprintEditingService
|
||||
}
|
||||
|
||||
// Save blueprint
|
||||
await SaveAsync(blueprint, userKey);
|
||||
await SaveAsync(blueprint, userKey, content);
|
||||
|
||||
return Attempt.SucceedWithStatus(ContentEditingOperationStatus.Success, new ContentCreateResult { Content = blueprint });
|
||||
}
|
||||
@@ -240,10 +240,10 @@ internal sealed class ContentBlueprintEditingService
|
||||
|
||||
protected override OperationResult? Delete(IContent content, int userId) => throw new NotImplementedException();
|
||||
|
||||
private async Task SaveAsync(IContent blueprint, Guid userKey)
|
||||
private async Task SaveAsync(IContent blueprint, Guid userKey, IContent? createdFromContent = null)
|
||||
{
|
||||
var currentUserId = await GetUserIdAsync(userKey);
|
||||
ContentService.SaveBlueprint(blueprint, currentUserId);
|
||||
ContentService.SaveBlueprint(blueprint, createdFromContent, currentUserId);
|
||||
}
|
||||
|
||||
private bool ValidateUniqueName(string name, IContent content)
|
||||
|
||||
@@ -3611,6 +3611,9 @@ public class ContentService : RepositoryService, IContentService
|
||||
}
|
||||
|
||||
public void SaveBlueprint(IContent content, int userId = Constants.Security.SuperUserId)
|
||||
=> SaveBlueprint(content, null, userId);
|
||||
|
||||
public void SaveBlueprint(IContent content, IContent? createdFromContent, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
EventMessages evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
@@ -3631,7 +3634,7 @@ public class ContentService : RepositoryService, IContentService
|
||||
|
||||
Audit(AuditType.Save, userId, content.Id, $"Saved content template: {content.Name}");
|
||||
|
||||
scope.Notifications.Publish(new ContentSavedBlueprintNotification(content, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentSavedBlueprintNotification(content, createdFromContent, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshNode, evtMsgs));
|
||||
|
||||
scope.Complete();
|
||||
|
||||
@@ -47,8 +47,17 @@ public interface IContentService : IContentServiceBase<IContent>
|
||||
/// <summary>
|
||||
/// Saves a blueprint.
|
||||
/// </summary>
|
||||
[Obsolete("Please use the method taking all parameters. Scheduled for removal in Umbraco 18.")]
|
||||
void SaveBlueprint(IContent content, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a blueprint.
|
||||
/// </summary>
|
||||
void SaveBlueprint(IContent content, IContent? createdFromContent, int userId = Constants.Security.SuperUserId)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
=> SaveBlueprint(content, userId);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a blueprint.
|
||||
/// </summary>
|
||||
|
||||
@@ -356,11 +356,14 @@ public static partial class UmbracoBuilderExtensions
|
||||
.AddNotificationHandler<ContentSavingNotification, RichTextPropertyNotificationHandler>()
|
||||
.AddNotificationHandler<ContentCopyingNotification, RichTextPropertyNotificationHandler>()
|
||||
.AddNotificationHandler<ContentScaffoldedNotification, RichTextPropertyNotificationHandler>()
|
||||
.AddNotificationHandler<ContentCopiedNotification, FileUploadContentCopiedNotificationHandler>()
|
||||
.AddNotificationHandler<ContentCopiedNotification, FileUploadContentCopiedOrScaffoldedNotificationHandler>()
|
||||
.AddNotificationHandler<ContentScaffoldedNotification, FileUploadContentCopiedOrScaffoldedNotificationHandler>()
|
||||
.AddNotificationHandler<ContentSavedBlueprintNotification, FileUploadContentCopiedOrScaffoldedNotificationHandler>()
|
||||
.AddNotificationHandler<ContentDeletedNotification, FileUploadContentDeletedNotificationHandler>()
|
||||
.AddNotificationHandler<MediaDeletedNotification, FileUploadMediaDeletedNotificationHandler>()
|
||||
.AddNotificationHandler<ContentDeletedBlueprintNotification, FileUploadContentDeletedNotificationHandler>()
|
||||
.AddNotificationHandler<MediaDeletedNotification, FileUploadContentDeletedNotificationHandler>()
|
||||
.AddNotificationHandler<MemberDeletedNotification, FileUploadContentDeletedNotificationHandler>()
|
||||
.AddNotificationHandler<MediaSavingNotification, FileUploadMediaSavingNotificationHandler>()
|
||||
.AddNotificationHandler<MemberDeletedNotification, FileUploadMemberDeletedNotificationHandler>()
|
||||
.AddNotificationHandler<ContentCopiedNotification, ImageCropperPropertyEditor>()
|
||||
.AddNotificationHandler<ContentDeletedNotification, ImageCropperPropertyEditor>()
|
||||
.AddNotificationHandler<MediaDeletedNotification, ImageCropperPropertyEditor>()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
@@ -63,7 +63,7 @@ public class MoveDocumentBlueprintsToFolders : MigrationBase
|
||||
}
|
||||
|
||||
blueprint.ParentId = container.Id;
|
||||
_contentService.SaveBlueprint(blueprint);
|
||||
_contentService.SaveBlueprint(blueprint, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,13 +92,10 @@ internal class FileUploadPropertyValueEditor : DataValueEditor
|
||||
{
|
||||
FileUploadValue? editorModelValue = _valueParser.Parse(editorValue.Value);
|
||||
|
||||
// no change?
|
||||
// No change or created from blueprint.
|
||||
if (editorModelValue?.TemporaryFileId.HasValue is not true && string.IsNullOrEmpty(editorModelValue?.Src) is false)
|
||||
{
|
||||
// since current value can be json string, we have to parse value
|
||||
FileUploadValue? currentModelValue = _valueParser.Parse(currentValue);
|
||||
|
||||
return currentModelValue?.Src;
|
||||
return editorModelValue.Src;
|
||||
}
|
||||
|
||||
// the current editor value (if any) is the path to the file
|
||||
|
||||
@@ -14,24 +14,26 @@ using Umbraco.Cms.Core.Services;
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.NotificationHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Implements a notification handler that processes file uploads when content is copied, making sure the copied contetnt relates to a new instance
|
||||
/// of the file.
|
||||
/// Implements a notification handler that processes file uploads when content is copied or scaffolded from a blueprint, making
|
||||
/// sure the new content references a new instance of the file.
|
||||
/// </summary>
|
||||
internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNotificationHandlerBase, INotificationHandler<ContentCopiedNotification>
|
||||
internal sealed class FileUploadContentCopiedOrScaffoldedNotificationHandler : FileUploadNotificationHandlerBase,
|
||||
INotificationHandler<ContentCopiedNotification>,
|
||||
INotificationHandler<ContentScaffoldedNotification>,
|
||||
INotificationHandler<ContentSavedBlueprintNotification>
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
|
||||
private readonly BlockEditorValues<BlockListValue, BlockListLayoutItem> _blockListEditorValues;
|
||||
private readonly BlockEditorValues<BlockGridValue, BlockGridLayoutItem> _blockGridEditorValues;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileUploadContentCopiedNotificationHandler"/> class.
|
||||
/// Initializes a new instance of the <see cref="FileUploadContentCopiedOrScaffoldedNotificationHandler"/> class.
|
||||
/// </summary>
|
||||
public FileUploadContentCopiedNotificationHandler(
|
||||
public FileUploadContentCopiedOrScaffoldedNotificationHandler(
|
||||
IJsonSerializer jsonSerializer,
|
||||
MediaFileManager mediaFileManager,
|
||||
IBlockEditorElementTypeCache elementTypeCache,
|
||||
ILogger<FileUploadContentCopiedNotificationHandler> logger,
|
||||
ILogger<FileUploadContentCopiedOrScaffoldedNotificationHandler> logger,
|
||||
IContentService contentService)
|
||||
: base(jsonSerializer, mediaFileManager, elementTypeCache)
|
||||
{
|
||||
@@ -41,51 +43,66 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(ContentCopiedNotification notification)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(notification);
|
||||
public void Handle(ContentCopiedNotification notification) => Handle(notification.Original, notification.Copy, (IContent c) => _contentService.Save(c));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(ContentScaffoldedNotification notification) => Handle(notification.Original, notification.Scaffold);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(ContentSavedBlueprintNotification notification)
|
||||
{
|
||||
if (notification.CreatedFromContent is null)
|
||||
{
|
||||
// If there is no original content, we don't need to copy files.
|
||||
return;
|
||||
}
|
||||
|
||||
Handle(notification.CreatedFromContent, notification.SavedBlueprint, (IContent c) => _contentService.SaveBlueprint(c, null));
|
||||
}
|
||||
|
||||
private void Handle(IContent source, IContent destination, Action<IContent>? postUpdateAction = null)
|
||||
{
|
||||
var isUpdated = false;
|
||||
|
||||
foreach (IProperty property in notification.Original.Properties)
|
||||
foreach (IProperty property in source.Properties)
|
||||
{
|
||||
if (IsUploadFieldPropertyType(property.PropertyType))
|
||||
{
|
||||
isUpdated |= UpdateUploadFieldProperty(notification, property);
|
||||
isUpdated |= UpdateUploadFieldProperty(destination, property);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockListPropertyType(property.PropertyType))
|
||||
{
|
||||
isUpdated |= UpdateBlockProperty(notification, property, _blockListEditorValues);
|
||||
isUpdated |= UpdateBlockProperty(destination, property, _blockListEditorValues);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockGridPropertyType(property.PropertyType))
|
||||
{
|
||||
isUpdated |= UpdateBlockProperty(notification, property, _blockGridEditorValues);
|
||||
isUpdated |= UpdateBlockProperty(destination, property, _blockGridEditorValues);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsRichTextPropertyType(property.PropertyType))
|
||||
{
|
||||
isUpdated |= UpdateRichTextProperty(notification, property);
|
||||
isUpdated |= UpdateRichTextProperty(destination, property);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if updated, re-save the copy with the updated value
|
||||
if (isUpdated)
|
||||
// If updated, re-save the destination with the updated value.
|
||||
if (isUpdated && postUpdateAction is not null)
|
||||
{
|
||||
_contentService.Save(notification.Copy);
|
||||
postUpdateAction(destination);
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpdateUploadFieldProperty(ContentCopiedNotification notification, IProperty property)
|
||||
private bool UpdateUploadFieldProperty(IContent content, IProperty property)
|
||||
{
|
||||
var isUpdated = false;
|
||||
|
||||
@@ -98,9 +115,9 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
continue;
|
||||
}
|
||||
|
||||
var copyUrl = CopyFile(sourceUrl, notification.Copy, property.PropertyType);
|
||||
var copyUrl = CopyFile(sourceUrl, content, property.PropertyType);
|
||||
|
||||
notification.Copy.SetValue(property.Alias, copyUrl, propertyValue.Culture, propertyValue.Segment);
|
||||
content.SetValue(property.Alias, copyUrl, propertyValue.Culture, propertyValue.Segment);
|
||||
|
||||
isUpdated = true;
|
||||
}
|
||||
@@ -108,7 +125,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
private bool UpdateBlockProperty<TValue, TLayout>(ContentCopiedNotification notification, IProperty property, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
private bool UpdateBlockProperty<TValue, TLayout>(IContent content, IProperty property, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
@@ -120,11 +137,11 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
|
||||
BlockEditorData<TValue, TLayout>? blockEditorData = GetBlockEditorData(rawBlockPropertyValue, blockEditorValues);
|
||||
|
||||
(bool hasUpdates, string? updatedValue) = UpdateBlockEditorData(notification, blockEditorData);
|
||||
(bool hasUpdates, string? updatedValue) = UpdateBlockEditorData(content, blockEditorData);
|
||||
|
||||
if (hasUpdates)
|
||||
{
|
||||
notification.Copy.SetValue(property.Alias, updatedValue, blockPropertyValue.Culture, blockPropertyValue.Segment);
|
||||
content.SetValue(property.Alias, updatedValue, blockPropertyValue.Culture, blockPropertyValue.Segment);
|
||||
}
|
||||
|
||||
isUpdated |= hasUpdates;
|
||||
@@ -133,7 +150,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
private (bool, string?) UpdateBlockEditorData<TValue, TLayout>(ContentCopiedNotification notification, BlockEditorData<TValue, TLayout>? blockEditorData)
|
||||
private (bool, string?) UpdateBlockEditorData<TValue, TLayout>(IContent content, BlockEditorData<TValue, TLayout>? blockEditorData)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
@@ -148,14 +165,14 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
.Concat(blockEditorData.BlockValue.SettingsData)
|
||||
.SelectMany(x => x.Values);
|
||||
|
||||
isUpdated = UpdateBlockPropertyValues(notification, isUpdated, blockPropertyValues);
|
||||
isUpdated = UpdateBlockPropertyValues(content, isUpdated, blockPropertyValues);
|
||||
|
||||
var updatedValue = JsonSerializer.Serialize(blockEditorData.BlockValue);
|
||||
|
||||
return (isUpdated, updatedValue);
|
||||
}
|
||||
|
||||
private bool UpdateRichTextProperty(ContentCopiedNotification notification, IProperty property)
|
||||
private bool UpdateRichTextProperty(IContent content, IProperty property)
|
||||
{
|
||||
var isUpdated = false;
|
||||
|
||||
@@ -165,7 +182,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
|
||||
RichTextBlockValue? richTextBlockValue = GetRichTextBlockValue(rawBlockPropertyValue);
|
||||
|
||||
(bool hasUpdates, string? updatedValue) = UpdateBlockEditorData(notification, richTextBlockValue);
|
||||
(bool hasUpdates, string? updatedValue) = UpdateBlockEditorData(content, richTextBlockValue);
|
||||
|
||||
if (hasUpdates && string.IsNullOrEmpty(updatedValue) is false)
|
||||
{
|
||||
@@ -173,7 +190,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
if (richTextEditorValue is not null)
|
||||
{
|
||||
richTextEditorValue.Blocks = JsonSerializer.Deserialize<RichTextBlockValue>(updatedValue);
|
||||
notification.Copy.SetValue(property.Alias, JsonSerializer.Serialize(richTextEditorValue), blockPropertyValue.Culture, blockPropertyValue.Segment);
|
||||
content.SetValue(property.Alias, JsonSerializer.Serialize(richTextEditorValue), blockPropertyValue.Culture, blockPropertyValue.Segment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +200,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
private (bool, string?) UpdateBlockEditorData(ContentCopiedNotification notification, RichTextBlockValue? richTextBlockValue)
|
||||
private (bool, string?) UpdateBlockEditorData(IContent content, RichTextBlockValue? richTextBlockValue)
|
||||
{
|
||||
var isUpdated = false;
|
||||
|
||||
@@ -196,14 +213,14 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
.Concat(richTextBlockValue.SettingsData)
|
||||
.SelectMany(x => x.Values);
|
||||
|
||||
isUpdated = UpdateBlockPropertyValues(notification, isUpdated, blockPropertyValues);
|
||||
isUpdated = UpdateBlockPropertyValues(content, isUpdated, blockPropertyValues);
|
||||
|
||||
var updatedValue = JsonSerializer.Serialize(richTextBlockValue);
|
||||
|
||||
return (isUpdated, updatedValue);
|
||||
}
|
||||
|
||||
private bool UpdateBlockPropertyValues(ContentCopiedNotification notification, bool isUpdated, IEnumerable<BlockPropertyValue> blockPropertyValues)
|
||||
private bool UpdateBlockPropertyValues(IContent content, bool isUpdated, IEnumerable<BlockPropertyValue> blockPropertyValues)
|
||||
{
|
||||
foreach (BlockPropertyValue blockPropertyValue in blockPropertyValues)
|
||||
{
|
||||
@@ -221,14 +238,14 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
|
||||
if (IsUploadFieldPropertyType(propertyType))
|
||||
{
|
||||
isUpdated |= UpdateUploadFieldBlockPropertyValue(blockPropertyValue, notification, propertyType);
|
||||
isUpdated |= UpdateUploadFieldBlockPropertyValue(blockPropertyValue, content, propertyType);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockListPropertyType(propertyType))
|
||||
{
|
||||
(bool hasUpdates, string? newValue) = UpdateBlockPropertyValue(blockPropertyValue, notification, _blockListEditorValues);
|
||||
(bool hasUpdates, string? newValue) = UpdateBlockPropertyValue(blockPropertyValue, content, _blockListEditorValues);
|
||||
|
||||
isUpdated |= hasUpdates;
|
||||
|
||||
@@ -239,7 +256,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
|
||||
if (IsBlockGridPropertyType(propertyType))
|
||||
{
|
||||
(bool hasUpdates, string? newValue) = UpdateBlockPropertyValue(blockPropertyValue, notification, _blockGridEditorValues);
|
||||
(bool hasUpdates, string? newValue) = UpdateBlockPropertyValue(blockPropertyValue, content, _blockGridEditorValues);
|
||||
|
||||
isUpdated |= hasUpdates;
|
||||
|
||||
@@ -250,7 +267,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
|
||||
if (IsRichTextPropertyType(propertyType))
|
||||
{
|
||||
(bool hasUpdates, string? newValue) = UpdateRichTextPropertyValue(blockPropertyValue, notification);
|
||||
(bool hasUpdates, string? newValue) = UpdateRichTextPropertyValue(blockPropertyValue, content);
|
||||
|
||||
if (hasUpdates && string.IsNullOrEmpty(newValue) is false)
|
||||
{
|
||||
@@ -271,7 +288,7 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
private bool UpdateUploadFieldBlockPropertyValue(BlockPropertyValue blockItemDataValue, ContentCopiedNotification notification, IPropertyType propertyType)
|
||||
private bool UpdateUploadFieldBlockPropertyValue(BlockPropertyValue blockItemDataValue, IContent content, IPropertyType propertyType)
|
||||
{
|
||||
FileUploadValue? fileUploadValue = FileUploadValueParser.Parse(blockItemDataValue.Value);
|
||||
|
||||
@@ -281,26 +298,26 @@ internal sealed class FileUploadContentCopiedNotificationHandler : FileUploadNot
|
||||
return false;
|
||||
}
|
||||
|
||||
var copyFileUrl = CopyFile(fileUploadValue.Src, notification.Copy, propertyType);
|
||||
var copyFileUrl = CopyFile(fileUploadValue.Src, content, propertyType);
|
||||
|
||||
blockItemDataValue.Value = copyFileUrl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private (bool, string?) UpdateBlockPropertyValue<TValue, TLayout>(BlockPropertyValue blockItemDataValue, ContentCopiedNotification notification, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
private (bool, string?) UpdateBlockPropertyValue<TValue, TLayout>(BlockPropertyValue blockItemDataValue, IContent content, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
BlockEditorData<TValue, TLayout>? blockItemEditorDataValue = GetBlockEditorData(blockItemDataValue.Value, blockEditorValues);
|
||||
|
||||
return UpdateBlockEditorData(notification, blockItemEditorDataValue);
|
||||
return UpdateBlockEditorData(content, blockItemEditorDataValue);
|
||||
}
|
||||
|
||||
private (bool, string?) UpdateRichTextPropertyValue(BlockPropertyValue blockItemDataValue, ContentCopiedNotification notification)
|
||||
private (bool, string?) UpdateRichTextPropertyValue(BlockPropertyValue blockItemDataValue, IContent content)
|
||||
{
|
||||
RichTextBlockValue? richTextBlockValue = GetRichTextBlockValue(blockItemDataValue.Value);
|
||||
return UpdateBlockEditorData(notification, richTextBlockValue);
|
||||
return UpdateBlockEditorData(content, richTextBlockValue);
|
||||
}
|
||||
|
||||
private string CopyFile(string sourceUrl, IContent destinationContent, IPropertyType propertyType)
|
||||
@@ -1,17 +1,30 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.NotificationHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Implements a notification handler that processes file uploads when content is deleted, removing associated files.
|
||||
/// Provides base class for notification handler that processes file uploads when a content entity is deleted, removing associated files.
|
||||
/// </summary>
|
||||
internal sealed class FileUploadContentDeletedNotificationHandler : FileUploadEntityDeletedNotificationHandlerBase, INotificationHandler<ContentDeletedNotification>
|
||||
internal sealed class FileUploadContentDeletedNotificationHandler : FileUploadNotificationHandlerBase,
|
||||
INotificationHandler<ContentDeletedNotification>,
|
||||
INotificationHandler<ContentDeletedBlueprintNotification>,
|
||||
INotificationHandler<MediaDeletedNotification>,
|
||||
INotificationHandler<MemberDeletedNotification>
|
||||
{
|
||||
private readonly BlockEditorValues<BlockListValue, BlockListLayoutItem> _blockListEditorValues;
|
||||
private readonly BlockEditorValues<BlockGridValue, BlockGridLayoutItem> _blockGridEditorValues;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileUploadContentDeletedNotificationHandler"/> class.
|
||||
/// </summary>
|
||||
@@ -20,10 +33,204 @@ internal sealed class FileUploadContentDeletedNotificationHandler : FileUploadEn
|
||||
MediaFileManager mediaFileManager,
|
||||
IBlockEditorElementTypeCache elementTypeCache,
|
||||
ILogger<FileUploadContentDeletedNotificationHandler> logger)
|
||||
: base(jsonSerializer, mediaFileManager, elementTypeCache, logger)
|
||||
: base(jsonSerializer, mediaFileManager, elementTypeCache)
|
||||
{
|
||||
_blockListEditorValues = new(new BlockListEditorDataConverter(jsonSerializer), elementTypeCache, logger);
|
||||
_blockGridEditorValues = new(new BlockGridEditorDataConverter(jsonSerializer), elementTypeCache, logger);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(ContentDeletedNotification notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(ContentDeletedBlueprintNotification notification) => DeleteContainedFiles(notification.DeletedBlueprints);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(MediaDeletedNotification notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(MemberDeletedNotification notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all file upload property files contained within a collection of content entities.
|
||||
/// </summary>
|
||||
/// <param name="deletedEntities"></param>
|
||||
private void DeleteContainedFiles(IEnumerable<IContentBase> deletedEntities)
|
||||
{
|
||||
IReadOnlyList<string> filePathsToDelete = ContainedFilePaths(deletedEntities);
|
||||
MediaFileManager.DeleteMediaFiles(filePathsToDelete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the paths to all file upload property files contained within a collection of content entities.
|
||||
/// </summary>
|
||||
private IReadOnlyList<string> ContainedFilePaths(IEnumerable<IContentBase> entities)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
foreach (IProperty? property in entities.SelectMany(x => x.Properties))
|
||||
{
|
||||
if (IsUploadFieldPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromUploadFieldProperty(property));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockListPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockProperty(property, _blockListEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockGridPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockProperty(property, _blockGridEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsRichTextPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromRichTextProperty(property));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return paths.Distinct().ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetPathsFromUploadFieldProperty(IProperty property)
|
||||
{
|
||||
foreach (IPropertyValue propertyValue in property.Values)
|
||||
{
|
||||
if (propertyValue.PublishedValue != null && propertyValue.PublishedValue is string publishedUrl && !string.IsNullOrWhiteSpace(publishedUrl))
|
||||
{
|
||||
yield return MediaFileManager.FileSystem.GetRelativePath(publishedUrl);
|
||||
}
|
||||
|
||||
if (propertyValue.EditedValue != null && propertyValue.EditedValue is string editedUrl && !string.IsNullOrWhiteSpace(editedUrl))
|
||||
{
|
||||
yield return MediaFileManager.FileSystem.GetRelativePath(editedUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromBlockProperty<TValue, TLayout>(IProperty property, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
foreach (IPropertyValue blockPropertyValue in property.Values)
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockValue(GetBlockEditorData(blockPropertyValue.PublishedValue, blockEditorValues)?.BlockValue));
|
||||
paths.AddRange(GetPathsFromBlockValue(GetBlockEditorData(blockPropertyValue.EditedValue, blockEditorValues)?.BlockValue));
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromBlockValue(BlockValue? blockValue)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
if (blockValue is null)
|
||||
{
|
||||
return paths;
|
||||
}
|
||||
|
||||
IEnumerable<BlockPropertyValue> blockPropertyValues = blockValue.ContentData
|
||||
.Concat(blockValue.SettingsData)
|
||||
.SelectMany(x => x.Values);
|
||||
|
||||
foreach (BlockPropertyValue blockPropertyValue in blockPropertyValues)
|
||||
{
|
||||
if (blockPropertyValue.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IPropertyType? propertyType = blockPropertyValue.PropertyType;
|
||||
|
||||
if (propertyType == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsUploadFieldPropertyType(propertyType))
|
||||
{
|
||||
FileUploadValue? originalValue = FileUploadValueParser.Parse(blockPropertyValue.Value);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(originalValue?.Src))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
paths.Add(MediaFileManager.FileSystem.GetRelativePath(originalValue.Src));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockListPropertyType(propertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockPropertyValue(blockPropertyValue, _blockListEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockGridPropertyType(propertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockPropertyValue(blockPropertyValue, _blockGridEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsRichTextPropertyType(propertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromRichTextPropertyValue(blockPropertyValue));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromBlockPropertyValue<TValue, TLayout>(BlockPropertyValue blockItemDataValue, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
BlockEditorData<TValue, TLayout>? blockItemEditorDataValue = GetBlockEditorData(blockItemDataValue.Value, blockEditorValues);
|
||||
|
||||
return GetPathsFromBlockValue(blockItemEditorDataValue?.BlockValue);
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromRichTextProperty(IProperty property)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
IPropertyValue? propertyValue = property.Values.FirstOrDefault();
|
||||
if (propertyValue is null)
|
||||
{
|
||||
return paths;
|
||||
}
|
||||
|
||||
paths.AddRange(GetPathsFromBlockValue(GetRichTextBlockValue(propertyValue.PublishedValue)));
|
||||
paths.AddRange(GetPathsFromBlockValue(GetRichTextBlockValue(propertyValue.EditedValue)));
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromRichTextPropertyValue(BlockPropertyValue blockItemDataValue)
|
||||
{
|
||||
RichTextEditorValue? richTextEditorValue = GetRichTextEditorValue(blockItemDataValue.Value);
|
||||
|
||||
// Ensure the property type is populated on all blocks.
|
||||
richTextEditorValue?.EnsurePropertyTypePopulatedOnBlocks(ElementTypeCache);
|
||||
|
||||
return GetPathsFromBlockValue(richTextEditorValue?.Blocks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache.PropertyEditors;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.NotificationHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides base class for notification handler that processes file uploads when a content entity is deleted, removing associated files.
|
||||
/// </summary>
|
||||
internal abstract class FileUploadEntityDeletedNotificationHandlerBase : FileUploadNotificationHandlerBase
|
||||
{
|
||||
private readonly BlockEditorValues<BlockListValue, BlockListLayoutItem> _blockListEditorValues;
|
||||
private readonly BlockEditorValues<BlockGridValue, BlockGridLayoutItem> _blockGridEditorValues;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileUploadEntityDeletedNotificationHandlerBase"/> class.
|
||||
/// </summary>
|
||||
protected FileUploadEntityDeletedNotificationHandlerBase(
|
||||
IJsonSerializer jsonSerializer,
|
||||
MediaFileManager mediaFileManager,
|
||||
IBlockEditorElementTypeCache elementTypeCache,
|
||||
ILogger logger)
|
||||
: base(jsonSerializer, mediaFileManager, elementTypeCache)
|
||||
{
|
||||
_blockListEditorValues = new(new BlockListEditorDataConverter(jsonSerializer), elementTypeCache, logger);
|
||||
_blockGridEditorValues = new(new BlockGridEditorDataConverter(jsonSerializer), elementTypeCache, logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all file upload property files contained within a collection of content entities.
|
||||
/// </summary>
|
||||
/// <param name="deletedEntities"></param>
|
||||
protected void DeleteContainedFiles(IEnumerable<IContentBase> deletedEntities)
|
||||
{
|
||||
IReadOnlyList<string> filePathsToDelete = ContainedFilePaths(deletedEntities);
|
||||
MediaFileManager.DeleteMediaFiles(filePathsToDelete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the paths to all file upload property files contained within a collection of content entities.
|
||||
/// </summary>
|
||||
private IReadOnlyList<string> ContainedFilePaths(IEnumerable<IContentBase> entities)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
foreach (IProperty? property in entities.SelectMany(x => x.Properties))
|
||||
{
|
||||
if (IsUploadFieldPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromUploadFieldProperty(property));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockListPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockProperty(property, _blockListEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockGridPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockProperty(property, _blockGridEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsRichTextPropertyType(property.PropertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromRichTextProperty(property));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return paths.Distinct().ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetPathsFromUploadFieldProperty(IProperty property)
|
||||
{
|
||||
foreach (IPropertyValue propertyValue in property.Values)
|
||||
{
|
||||
if (propertyValue.PublishedValue != null && propertyValue.PublishedValue is string publishedUrl && !string.IsNullOrWhiteSpace(publishedUrl))
|
||||
{
|
||||
yield return MediaFileManager.FileSystem.GetRelativePath(publishedUrl);
|
||||
}
|
||||
|
||||
if (propertyValue.EditedValue != null && propertyValue.EditedValue is string editedUrl && !string.IsNullOrWhiteSpace(editedUrl))
|
||||
{
|
||||
yield return MediaFileManager.FileSystem.GetRelativePath(editedUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromBlockProperty<TValue, TLayout>(IProperty property, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
foreach (IPropertyValue blockPropertyValue in property.Values)
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockValue(GetBlockEditorData(blockPropertyValue.PublishedValue, blockEditorValues)?.BlockValue));
|
||||
paths.AddRange(GetPathsFromBlockValue(GetBlockEditorData(blockPropertyValue.EditedValue, blockEditorValues)?.BlockValue));
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromBlockValue(BlockValue? blockValue)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
if (blockValue is null)
|
||||
{
|
||||
return paths;
|
||||
}
|
||||
|
||||
IEnumerable<BlockPropertyValue> blockPropertyValues = blockValue.ContentData
|
||||
.Concat(blockValue.SettingsData)
|
||||
.SelectMany(x => x.Values);
|
||||
|
||||
foreach (BlockPropertyValue blockPropertyValue in blockPropertyValues)
|
||||
{
|
||||
if (blockPropertyValue.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IPropertyType? propertyType = blockPropertyValue.PropertyType;
|
||||
|
||||
if (propertyType == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsUploadFieldPropertyType(propertyType))
|
||||
{
|
||||
FileUploadValue? originalValue = FileUploadValueParser.Parse(blockPropertyValue.Value);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(originalValue?.Src))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
paths.Add(MediaFileManager.FileSystem.GetRelativePath(originalValue.Src));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockListPropertyType(propertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockPropertyValue(blockPropertyValue, _blockListEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockGridPropertyType(propertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromBlockPropertyValue(blockPropertyValue, _blockGridEditorValues));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsRichTextPropertyType(propertyType))
|
||||
{
|
||||
paths.AddRange(GetPathsFromRichTextPropertyValue(blockPropertyValue));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromBlockPropertyValue<TValue, TLayout>(BlockPropertyValue blockItemDataValue, BlockEditorValues<TValue, TLayout> blockEditorValues)
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
BlockEditorData<TValue, TLayout>? blockItemEditorDataValue = GetBlockEditorData(blockItemDataValue.Value, blockEditorValues);
|
||||
|
||||
return GetPathsFromBlockValue(blockItemEditorDataValue?.BlockValue);
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromRichTextProperty(IProperty property)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
IPropertyValue? propertyValue = property.Values.FirstOrDefault();
|
||||
if (propertyValue is null)
|
||||
{
|
||||
return paths;
|
||||
}
|
||||
|
||||
paths.AddRange(GetPathsFromBlockValue(GetRichTextBlockValue(propertyValue.PublishedValue)));
|
||||
paths.AddRange(GetPathsFromBlockValue(GetRichTextBlockValue(propertyValue.EditedValue)));
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> GetPathsFromRichTextPropertyValue(BlockPropertyValue blockItemDataValue)
|
||||
{
|
||||
RichTextEditorValue? richTextEditorValue = GetRichTextEditorValue(blockItemDataValue.Value);
|
||||
|
||||
// Ensure the property type is populated on all blocks.
|
||||
richTextEditorValue?.EnsurePropertyTypePopulatedOnBlocks(ElementTypeCache);
|
||||
|
||||
return GetPathsFromBlockValue(richTextEditorValue?.Blocks);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.Cache.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.NotificationHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Implements a notification handler that processes file uploads when media is deleted, removing associated files.
|
||||
/// </summary>
|
||||
internal sealed class FileUploadMediaDeletedNotificationHandler : FileUploadEntityDeletedNotificationHandlerBase, INotificationHandler<MediaDeletedNotification>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileUploadMediaDeletedNotificationHandler"/> class.
|
||||
/// </summary>
|
||||
public FileUploadMediaDeletedNotificationHandler(
|
||||
IJsonSerializer jsonSerializer,
|
||||
MediaFileManager mediaFileManager,
|
||||
IBlockEditorElementTypeCache elementTypeCache,
|
||||
ILogger<FileUploadContentDeletedNotificationHandler> logger)
|
||||
: base(jsonSerializer, mediaFileManager, elementTypeCache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(MediaDeletedNotification notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.Cache.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.NotificationHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Implements a notification handler that processes file uploads when a member is deleted, removing associated files.
|
||||
/// </summary>
|
||||
internal sealed class FileUploadMemberDeletedNotificationHandler : FileUploadEntityDeletedNotificationHandlerBase, INotificationHandler<MemberDeletedNotification>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileUploadMemberDeletedNotificationHandler"/> class.
|
||||
/// </summary>
|
||||
public FileUploadMemberDeletedNotificationHandler(
|
||||
IJsonSerializer jsonSerializer,
|
||||
MediaFileManager mediaFileManager,
|
||||
IBlockEditorElementTypeCache elementTypeCache,
|
||||
ILogger<FileUploadContentDeletedNotificationHandler> logger)
|
||||
: base(jsonSerializer, mediaFileManager, elementTypeCache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Handle(MemberDeletedNotification notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
blueprint.SetValue("keywords", "blueprint 3");
|
||||
blueprint.SetValue("description", "blueprint 4");
|
||||
|
||||
ContentService.SaveBlueprint(blueprint);
|
||||
ContentService.SaveBlueprint(blueprint, null);
|
||||
|
||||
var found = ContentService.GetBlueprintsForContentTypes().ToArray();
|
||||
Assert.AreEqual(1, found.Length);
|
||||
@@ -121,7 +121,7 @@ internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
blueprint.SetValue("keywords", "blueprint 3");
|
||||
blueprint.SetValue("description", "blueprint 4");
|
||||
|
||||
ContentService.SaveBlueprint(blueprint);
|
||||
ContentService.SaveBlueprint(blueprint, null);
|
||||
|
||||
ContentService.DeleteBlueprint(blueprint);
|
||||
|
||||
@@ -148,7 +148,7 @@ internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
ContentService.Save(originalPage);
|
||||
|
||||
var fromContent = ContentService.CreateBlueprintFromContent(originalPage, "hello world");
|
||||
ContentService.SaveBlueprint(fromContent);
|
||||
ContentService.SaveBlueprint(fromContent, originalPage);
|
||||
|
||||
Assert.IsTrue(fromContent.HasIdentity);
|
||||
Assert.AreEqual("blueprint 1", fromContent.Properties["title"]?.GetValue());
|
||||
@@ -176,7 +176,7 @@ internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
var blueprint =
|
||||
ContentBuilder.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, Constants.System.Root);
|
||||
ContentService.SaveBlueprint(blueprint);
|
||||
ContentService.SaveBlueprint(blueprint, null);
|
||||
}
|
||||
|
||||
var found = ContentService.GetBlueprintsForContentTypes().ToArray();
|
||||
|
||||
@@ -116,7 +116,7 @@ internal sealed class TelemetryProviderTests : UmbracoIntegrationTest
|
||||
blueprint.SetValue("keywords", "blueprint 3");
|
||||
blueprint.SetValue("description", "blueprint 4");
|
||||
|
||||
ContentService.SaveBlueprint(blueprint);
|
||||
ContentService.SaveBlueprint(blueprint, null);
|
||||
|
||||
var fromBlueprint = await ContentBlueprintEditingService.GetScaffoldedAsync(blueprint.Key);
|
||||
Assert.IsNotNull(fromBlueprint);
|
||||
|
||||
Reference in New Issue
Block a user