Skip to content

Commit b5195ed

Browse files
authored
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.
1 parent 4c87cc5 commit b5195ed

14 files changed

+313
-339
lines changed

src/Umbraco.Core/Notifications/ContentSavedBlueprintNotification.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Umbraco.Cms.Core.Models;
66

77
namespace Umbraco.Cms.Core.Notifications;
8+
89
/// <summary>
910
/// A notification that is used to trigger the IContentService when the SavedBlueprint method is called in the API.
1011
/// </summary>
@@ -14,8 +15,21 @@ public ContentSavedBlueprintNotification(IContent target, EventMessages messages
1415
: base(target, messages)
1516
{
1617
}
18+
19+
public ContentSavedBlueprintNotification(IContent target, IContent? createdFromContent, EventMessages messages)
20+
: base(target, messages)
21+
{
22+
CreatedFromContent = createdFromContent;
23+
}
24+
1725
/// <summary>
1826
/// Getting the saved blueprint <see cref="IContent"/> object.
1927
/// </summary>
2028
public IContent SavedBlueprint => Target;
29+
30+
/// <summary>
31+
/// Getting the saved blueprint <see cref="IContent"/> object.
32+
/// </summary>
33+
public IContent? CreatedFromContent { get; }
34+
2135
}

src/Umbraco.Core/Services/ContentBlueprintEditingService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public async Task<Attempt<ContentCreateResult, ContentEditingOperationStatus>> C
122122
}
123123

124124
// Save blueprint
125-
await SaveAsync(blueprint, userKey);
125+
await SaveAsync(blueprint, userKey, content);
126126

127127
return Attempt.SucceedWithStatus(ContentEditingOperationStatus.Success, new ContentCreateResult { Content = blueprint });
128128
}
@@ -240,10 +240,10 @@ protected override IContent New(string? name, int parentId, IContentType content
240240

241241
protected override OperationResult? Delete(IContent content, int userId) => throw new NotImplementedException();
242242

243-
private async Task SaveAsync(IContent blueprint, Guid userKey)
243+
private async Task SaveAsync(IContent blueprint, Guid userKey, IContent? createdFromContent = null)
244244
{
245245
var currentUserId = await GetUserIdAsync(userKey);
246-
ContentService.SaveBlueprint(blueprint, currentUserId);
246+
ContentService.SaveBlueprint(blueprint, createdFromContent, currentUserId);
247247
}
248248

249249
private bool ValidateUniqueName(string name, IContent content)

src/Umbraco.Core/Services/ContentService.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3611,6 +3611,9 @@ private IContentType GetContentType(string contentTypeAlias)
36113611
}
36123612

36133613
public void SaveBlueprint(IContent content, int userId = Constants.Security.SuperUserId)
3614+
=> SaveBlueprint(content, null, userId);
3615+
3616+
public void SaveBlueprint(IContent content, IContent? createdFromContent, int userId = Constants.Security.SuperUserId)
36143617
{
36153618
EventMessages evtMsgs = EventMessagesFactory.Get();
36163619

@@ -3631,7 +3634,7 @@ public void SaveBlueprint(IContent content, int userId = Constants.Security.Supe
36313634

36323635
Audit(AuditType.Save, userId, content.Id, $"Saved content template: {content.Name}");
36333636

3634-
scope.Notifications.Publish(new ContentSavedBlueprintNotification(content, evtMsgs));
3637+
scope.Notifications.Publish(new ContentSavedBlueprintNotification(content, createdFromContent, evtMsgs));
36353638
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshNode, evtMsgs));
36363639

36373640
scope.Complete();

src/Umbraco.Core/Services/IContentService.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,17 @@ public interface IContentService : IContentServiceBase<IContent>
4747
/// <summary>
4848
/// Saves a blueprint.
4949
/// </summary>
50+
[Obsolete("Please use the method taking all parameters. Scheduled for removal in Umbraco 18.")]
5051
void SaveBlueprint(IContent content, int userId = Constants.Security.SuperUserId);
5152

53+
/// <summary>
54+
/// Saves a blueprint.
55+
/// </summary>
56+
void SaveBlueprint(IContent content, IContent? createdFromContent, int userId = Constants.Security.SuperUserId)
57+
#pragma warning disable CS0618 // Type or member is obsolete
58+
=> SaveBlueprint(content, userId);
59+
#pragma warning restore CS0618 // Type or member is obsolete
60+
5261
/// <summary>
5362
/// Deletes a blueprint.
5463
/// </summary>

src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,14 @@ public static IUmbracoBuilder AddCoreNotifications(this IUmbracoBuilder builder)
356356
.AddNotificationHandler<ContentSavingNotification, RichTextPropertyNotificationHandler>()
357357
.AddNotificationHandler<ContentCopyingNotification, RichTextPropertyNotificationHandler>()
358358
.AddNotificationHandler<ContentScaffoldedNotification, RichTextPropertyNotificationHandler>()
359-
.AddNotificationHandler<ContentCopiedNotification, FileUploadContentCopiedNotificationHandler>()
359+
.AddNotificationHandler<ContentCopiedNotification, FileUploadContentCopiedOrScaffoldedNotificationHandler>()
360+
.AddNotificationHandler<ContentScaffoldedNotification, FileUploadContentCopiedOrScaffoldedNotificationHandler>()
361+
.AddNotificationHandler<ContentSavedBlueprintNotification, FileUploadContentCopiedOrScaffoldedNotificationHandler>()
360362
.AddNotificationHandler<ContentDeletedNotification, FileUploadContentDeletedNotificationHandler>()
361-
.AddNotificationHandler<MediaDeletedNotification, FileUploadMediaDeletedNotificationHandler>()
363+
.AddNotificationHandler<ContentDeletedBlueprintNotification, FileUploadContentDeletedNotificationHandler>()
364+
.AddNotificationHandler<MediaDeletedNotification, FileUploadContentDeletedNotificationHandler>()
365+
.AddNotificationHandler<MemberDeletedNotification, FileUploadContentDeletedNotificationHandler>()
362366
.AddNotificationHandler<MediaSavingNotification, FileUploadMediaSavingNotificationHandler>()
363-
.AddNotificationHandler<MemberDeletedNotification, FileUploadMemberDeletedNotificationHandler>()
364367
.AddNotificationHandler<ContentCopiedNotification, ImageCropperPropertyEditor>()
365368
.AddNotificationHandler<ContentDeletedNotification, ImageCropperPropertyEditor>()
366369
.AddNotificationHandler<MediaDeletedNotification, ImageCropperPropertyEditor>()

src/Umbraco.Infrastructure/Migrations/Upgrade/V_14_0_0/MoveDocumentBlueprintsToFolders.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Umbraco.Cms.Core;
1+
using Umbraco.Cms.Core;
22
using Umbraco.Cms.Core.Models;
33
using Umbraco.Cms.Core.Persistence.Repositories;
44
using Umbraco.Cms.Core.Services;
@@ -63,7 +63,7 @@ protected override void Migrate()
6363
}
6464

6565
blueprint.ParentId = container.Id;
66-
_contentService.SaveBlueprint(blueprint);
66+
_contentService.SaveBlueprint(blueprint, null);
6767
}
6868
}
6969
}

src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,10 @@ public FileUploadPropertyValueEditor(
9292
{
9393
FileUploadValue? editorModelValue = _valueParser.Parse(editorValue.Value);
9494

95-
// no change?
95+
// No change or created from blueprint.
9696
if (editorModelValue?.TemporaryFileId.HasValue is not true && string.IsNullOrEmpty(editorModelValue?.Src) is false)
9797
{
98-
// since current value can be json string, we have to parse value
99-
FileUploadValue? currentModelValue = _valueParser.Parse(currentValue);
100-
101-
return currentModelValue?.Src;
98+
return editorModelValue.Src;
10299
}
103100

104101
// the current editor value (if any) is the path to the file

0 commit comments

Comments
 (0)