Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions uSync.BackOffice/SyncHandlers/Handlers/TemplateHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using uSync.BackOffice.SyncHandlers.Models;
using uSync.Core;
using uSync.Core.Serialization;
using uSync.Core.Templates;

using static Umbraco.Cms.Core.Constants;

Expand All @@ -42,7 +43,7 @@ public class TemplateHandler : SyncHandlerLevelBase<ITemplate>, ISyncHandler, IS
INotificationAsyncHandler<MovingNotification<ITemplate>>
{
private readonly IFileSystem? _viewFileSystem;
private readonly ITemplateService _templateService;
private readonly ISyncTemplateService _templateService;

private readonly ITemplateContentParserService _templateContentParserService;

Expand All @@ -51,20 +52,20 @@ public class TemplateHandler : SyncHandlerLevelBase<ITemplate>, ISyncHandler, IS
public TemplateHandler(
ILogger<TemplateHandler> logger,
IEntityService entityService,
ITemplateService templateService,
FileSystems fileSystems,
ITemplateContentParserService templateContentParserService,
AppCaches appCaches,
IShortStringHelper shortStringHelper,
ISyncFileService syncFileService,
ISyncEventService mutexService,
ISyncConfigService uSyncConfig,
ISyncItemFactory syncItemFactory)
ISyncItemFactory syncItemFactory,
ISyncTemplateService syncTemplateService)
: base(logger, entityService, appCaches, shortStringHelper, syncFileService, mutexService, uSyncConfig, syncItemFactory)
{
_templateService = templateService;
_viewFileSystem = fileSystems.MvcViewsFileSystem;
_templateContentParserService = templateContentParserService;
_templateService = syncTemplateService;
}

/// <inheritdoc/>
Expand Down
11 changes: 6 additions & 5 deletions uSync.Core/Serialization/Serializers/ContentSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using uSync.Core.Extensions;
using uSync.Core.Mapping;
using uSync.Core.Models;
using uSync.Core.Templates;

namespace uSync.Core.Serialization.Serializers;

Expand All @@ -23,7 +24,7 @@ public class ContentSerializer : ContentSerializerBase<IContent>, ISyncSerialize
protected readonly IContentService contentService;
protected readonly IUserService userService;

protected readonly ITemplateService _templateService;
protected readonly ISyncTemplateService _templateService;
protected readonly ISyncDocumentUrlCleaner? _urlCleaner;

[Obsolete("Use the constructor with urlCleaner, will be removed in v19")]
Expand All @@ -36,8 +37,8 @@ public ContentSerializer(
IContentService contentService,
SyncValueMapperCollection syncMappers,
IUserService userService,
ITemplateService templateService
) : this(entityService, languageService, relationService, shortStringHelper, logger, contentService, syncMappers, userService, templateService, null)
ISyncTemplateService syncTemplateService
) : this(entityService, languageService, relationService, shortStringHelper, logger, contentService, syncMappers, userService, syncTemplateService, null)
{ }

public ContentSerializer(
Expand All @@ -49,15 +50,15 @@ public ContentSerializer(
IContentService contentService,
SyncValueMapperCollection syncMappers,
IUserService userService,
ITemplateService templateService,
ISyncTemplateService syncTemplateService,
ISyncDocumentUrlCleaner? urlCleaner)
: base(entityService, languageService, relationService, shortStringHelper, logger, UmbracoObjectTypes.Document, syncMappers)
{
this.contentService = contentService;

this.relationAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias;
this.userService = userService;
_templateService = templateService;
_templateService = syncTemplateService;
_urlCleaner = urlCleaner;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using uSync.Core.Extensions;
using uSync.Core.Mapping;
using uSync.Core.Models;
using uSync.Core.Templates;

namespace uSync.Core.Serialization.Serializers;

Expand All @@ -30,7 +31,7 @@ public ContentTemplateSerializer(
IContentTypeService contentTypeService,
SyncValueMapperCollection syncMappers,
IUserService userService,
ITemplateService templateService,
ISyncTemplateService templateService,
ISyncDocumentUrlCleaner urlCleaner)
: base(entityService, languageService, relationService, shortStringHelper, logger, contentService, syncMappers, userService, templateService, urlCleaner)
{
Expand Down
33 changes: 13 additions & 20 deletions uSync.Core/Serialization/Serializers/TemplateSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Lucene.Net.Queries.Function.ValueSources;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

Expand All @@ -10,21 +8,20 @@
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;

using uSync.Core.Models;
using uSync.Core.Templates;
using uSync.Core.Versions;

namespace uSync.Core.Serialization.Serializers;

[SyncSerializer("D0E0769D-CCAE-47B4-AD34-4182C587B08A", "Template Serializer", uSyncConstants.Serialization.Template)]
public class TemplateSerializer : SyncSerializerBase<ITemplate>, ISyncSerializer<ITemplate>
{
private readonly IShortStringHelper _shortStringHelper;
private readonly IFileSystem? _viewFileSystem;

private readonly ITemplateService _templateService;
private readonly ISyncTemplateService _templateService;
private readonly IUserIdKeyResolver _userIdKeyResolver;

private readonly uSyncCapabilityChecker _capabilityChecker;
Expand All @@ -34,21 +31,18 @@ public class TemplateSerializer : SyncSerializerBase<ITemplate>, ISyncSerializer
public TemplateSerializer(
IEntityService entityService,
ILogger<TemplateSerializer> logger,
IShortStringHelper shortStringHelper,
FileSystems fileSystems,
IConfiguration configuration,
uSyncCapabilityChecker capabilityChecker,
ITemplateService templateService,
IUserIdKeyResolver userIdKeyResolver)
IUserIdKeyResolver userIdKeyResolver,
ISyncTemplateService syncTemplateService)
: base(entityService, logger)
{
_shortStringHelper = shortStringHelper;

_viewFileSystem = fileSystems.MvcViewsFileSystem;
_configuration = configuration;
_capabilityChecker = capabilityChecker;
_templateService = templateService;
_userIdKeyResolver = userIdKeyResolver;
_templateService = syncTemplateService;
}

protected override async Task<SyncAttempt<ITemplate>> ProcessDeleteAsync(Guid key, string alias, SerializerFlags flags)
Expand Down Expand Up @@ -103,7 +97,13 @@ protected override async Task<SyncAttempt<ITemplate>> DeserializeCoreAsync(XElem
userKey, key);

if (attempt.Success is false)
return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import, "Failed to create template");
{
logger.LogWarning("Failed to create template {alias} {name} - {error} - {status}",
alias, name, attempt.Exception?.Message ?? "Unknown error", attempt.Status);

return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import,
$"Failed to create template {alias} {name} - {attempt.Exception?.Message ?? "Unknown error"} - {attempt.Status}");
}

item = attempt.Result;
details.AddNew(alias, alias, "Template");
Expand All @@ -115,13 +115,6 @@ protected override async Task<SyncAttempt<ITemplate>> DeserializeCoreAsync(XElem
return SyncAttempt<ITemplate>.Succeed(name, item, ChangeType.Import, "Created", true, details);
}

if (item is null)
{
// creating went wrong
logger.LogWarning("Failed to create template");
return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import, "Failed to create template");
}

if (item.Key != key)
{
details.AddUpdate(uSyncConstants.Xml.Key, item.Key, key);
Expand Down
16 changes: 16 additions & 0 deletions uSync.Core/Templates/ISyncTemplateService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.OperationStatus;

namespace uSync.Core.Templates;

public interface ISyncTemplateService
{
Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(string name, string alias, string? content, Guid userKey, Guid key);
Task DeleteAsync(string alias, Guid userKey);
Task<ITemplate?> GetAsync(string alias);
Task<ITemplate?> GetAsync(Guid key);
Task<ITemplate?> GetAsync(int id);
Task<IEnumerable<ITemplate>> GetChildrenAsync(int templateId);
Task<Attempt<ITemplate, TemplateOperationStatus>> UpdateAsync(ITemplate template, Guid userKey);
}
106 changes: 106 additions & 0 deletions uSync.Core/Templates/SyncTemplateService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using Microsoft.Extensions.Configuration;

using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Core.Strings;

using uSync.Core.Versions;

namespace uSync.Core.Templates;

/// <summary>
/// handles creation of templates, especially when running in production mode.
/// </summary>
internal class SyncTemplateService : ISyncTemplateService
{
private readonly ITemplateService _templateService;
private readonly IConfiguration _configuration;
private readonly ICoreScopeProvider _scopeProvider;

private readonly ITemplateRepository _templateRepository;
private readonly IShortStringHelper _shortStringHelper;

public SyncTemplateService(ITemplateService templateService, IConfiguration configuration, ICoreScopeProvider scopeProvider, ITemplateRepository templateRepository, IShortStringHelper shortStringHelper)
{
_templateService = templateService;
_configuration = configuration;
_scopeProvider = scopeProvider;
_templateRepository = templateRepository;
_shortStringHelper = shortStringHelper;
}

/// <summary>
/// creates a template, using the service when possible and falling back to the repository
/// when already in production mode or when the service returns <see cref="TemplateOperationStatus.NotAllowedInProductionMode"/>.
/// </summary>
/// <param name="name">The display name of the template.</param>
/// <param name="alias">The alias of the template.</param>
/// <param name="content">The template content.</param>
/// <param name="userKey">The key of the user performing the operation.</param>
/// <param name="key">The key to assign to the new template.</param>
/// <returns></returns>
Comment thread
KevinJump marked this conversation as resolved.
public async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(string name, string alias, string? content, Guid userKey, Guid key)
{
if (IsInProductionMode() is false)
{
var attempt = await _templateService.CreateAsync(name, alias, content, userKey, key);
if (attempt.Success)
return attempt;

// only fall back to the repository when blocked by production mode restrictions
if (attempt.Status is not TemplateOperationStatus.NotAllowedInProductionMode)
return attempt;
}

// in production mode (or blocked by it) - use the repository directly
// https://github.com/umbraco/Umbraco-CMS/pull/21600#issuecomment-4205232583
return await CreateTemplateInternal(name, alias, content, userKey, key);
}

private Task<Attempt<ITemplate, TemplateOperationStatus>> CreateTemplateInternal(string name, string alias, string? content, Guid userKey, Guid key)
{
var template = new Template(_shortStringHelper, name, alias)
{
Content = content,
Key = key,
};

try
{
using var scope = _scopeProvider.CreateCoreScope(autoComplete: true);
_templateRepository.Save(template);

return Task.FromResult(Attempt.SucceedWithStatus<ITemplate, TemplateOperationStatus>(TemplateOperationStatus.Success, template));
}
catch (Exception ex)
{
return Task.FromResult(Attempt.FailWithStatus<ITemplate, TemplateOperationStatus>(TemplateOperationStatus.NotAllowedInProductionMode, template, ex));
}
}


public async Task<ITemplate?> GetAsync(Guid key)
=> await _templateService.GetAsync(key);

public async Task<ITemplate?> GetAsync(string alias)
=> await _templateService.GetAsync(alias);

public async Task<ITemplate?> GetAsync(int id)
=> await _templateService.GetAsync(id);

public async Task<Attempt<ITemplate, TemplateOperationStatus>> UpdateAsync(ITemplate template, Guid userKey)
=> await _templateService.UpdateAsync(template, userKey);

public async Task DeleteAsync(string alias, Guid userKey)
=> await _templateService.DeleteAsync(alias, userKey);

public async Task<IEnumerable<ITemplate>> GetChildrenAsync(int templateId)
=> await _templateService.GetChildrenAsync(templateId);

private bool IsInProductionMode()
=> _configuration.IsUmbracoRunningInProductionMode();
}
4 changes: 4 additions & 0 deletions uSync.Core/uSyncCoreBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using uSync.Core.Mapping.Tracking;
using uSync.Core.Roots.Configs;
using uSync.Core.Serialization;
using uSync.Core.Templates;
using uSync.Core.Tracking;

namespace uSync.Core;
Expand Down Expand Up @@ -41,6 +42,9 @@ public static IUmbracoBuilder AdduSyncCore(this IUmbracoBuilder builder)
// cache for entity items, we use it to speed up lookups.
builder.Services.AddSingleton<SyncEntityCache>();

// templates have a wrapper service because we have to do work when in production mode
builder.Services.AddSingleton<ISyncTemplateService, SyncTemplateService>();

// register *all* ConfigurationSerializers except those marked [HideFromTypeFinder]
// has to happen before the DataTypeSerializer is loaded, because that is where
// they are used
Expand Down
Loading