Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix resolving aliases for newly migrated Archetype data types #301

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class ArchetypeComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.Services.TryAddSingleton<IArchetypeMigrationConfigurer, DefaultArchetypeMigrationConfigurer>();
builder.Services.TryAddSingleton<IArchetypeAliasResolver, DefaultArchetypeAliasResolver>();
builder.Services.AddOptions<ArchetypeMigrationOptions>().Configure<IConfiguration>((settings, configuration)
=> configuration.GetSection(ArchetypeMigrationOptions.Section).Bind(settings));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Extensions;

using uSync.Migrations.Migrators.Community.Archetype.Models;

namespace uSync.Migrations.Migrators.Community.Archetype;
Expand All @@ -15,11 +13,16 @@ namespace uSync.Migrations.Migrators.Community.Archetype;
[SyncMigratorVersion(7)]
public class ArchetypeToBlockListMigrator : SyncPropertyMigratorBase
{
private readonly IArchetypeMigrationConfigurer _archetypeMigrationConfigurer;
private static readonly JsonSerializerSettings SerializerSettings = new()
{
DateParseHandling = DateParseHandling.None
};

public ArchetypeToBlockListMigrator(IArchetypeMigrationConfigurer archetypeMigrationConfigurer)
private readonly IArchetypeAliasResolver _archetypeAliasResolver;

public ArchetypeToBlockListMigrator(IArchetypeAliasResolver archetypeAliasResolver)
{
_archetypeMigrationConfigurer = archetypeMigrationConfigurer;
_archetypeAliasResolver = archetypeAliasResolver;
}

public override string GetEditorAlias(SyncMigrationDataTypeProperty dataTypeProperty, SyncMigrationContext context)
Expand All @@ -28,34 +31,43 @@ public override string GetEditorAlias(SyncMigrationDataTypeProperty dataTypeProp
public override string GetDatabaseType(SyncMigrationDataTypeProperty dataTypeProperty, SyncMigrationContext context)
=> nameof(ValueStorageType.Ntext);

public override object? GetConfigValues(SyncMigrationDataTypeProperty dataTypeProperty, SyncMigrationContext context)
public override object? GetConfigValues(SyncMigrationDataTypeProperty dataTypeProperty,
SyncMigrationContext context)
{
var config = new BlockListConfiguration();

var configPreValue = dataTypeProperty.PreValues?.FirstOrDefault(p => p.Alias == "archetypeConfig")?.Value;

if (string.IsNullOrEmpty(configPreValue))
{
return string.Empty;
}

var archetypeConfiguration = JsonConvert.DeserializeObject<ArchetypePreValue>(configPreValue);

if (archetypeConfiguration is null) return config;
if (archetypeConfiguration is null)
return config;

config.ValidationLimit = new BlockListConfiguration.NumberRange()
config.ValidationLimit = new BlockListConfiguration.NumberRange
{
Max = archetypeConfiguration.MaxFieldsets == default ? null : archetypeConfiguration.MaxFieldsets,
Min = archetypeConfiguration.MinFieldsets == default ? null : archetypeConfiguration.MinFieldsets,
};
config.UseSingleBlockMode = archetypeConfiguration.MaxFieldsets == 1 && archetypeConfiguration.MinFieldsets == 1 && archetypeConfiguration.Fieldsets.Count() == 1;

config.UseSingleBlockMode = archetypeConfiguration.MaxFieldsets == 1 &&
archetypeConfiguration.MinFieldsets == 1 &&
archetypeConfiguration.Fieldsets.Count() == 1;

config.UseLiveEditing = true;

config.UseInlineEditingAsDefault = true;

var blocks = new List<BlockListConfiguration.BlockConfiguration>();

foreach (var fieldSet in archetypeConfiguration.Fieldsets)
{
var alias = _archetypeMigrationConfigurer?.GetBlockElementAlias(fieldSet, dataTypeProperty, context);
if (string.IsNullOrEmpty(alias)) continue;
var alias = _archetypeAliasResolver?.GetBlockElementAlias(fieldSet.Alias!, dataTypeProperty.DataTypeAlias);

if (string.IsNullOrEmpty(alias))
continue;

var newContentType = new NewContentTypeInfo(
key: alias.ToGuid(),
Expand All @@ -73,20 +85,21 @@ public override string GetDatabaseType(SyncMigrationDataTypeProperty dataTypePro
.Select(p =>
{
var dataType = context.DataTypes.GetByDefinition(p.DataTypeGuid);

if (dataType == null)
{
return null;
}

return new NewContentTypeProperty(
alias: p.Alias!,
name: p.Label ?? p.Alias!,
dataTypeAlias: dataType.DataTypeName,
orginalEditorAlias: string.IsNullOrWhiteSpace(p.PropertyEditorAlias) ? dataType.OriginalEditorAlias : p.PropertyEditorAlias);
orginalEditorAlias: string.IsNullOrWhiteSpace(p.PropertyEditorAlias)
? dataType.OriginalEditorAlias
: p.PropertyEditorAlias);
})
.WhereNotNull()
.ToList();
};
}

context.ContentTypes.AddNewContentType(newContentType);
context.ContentTypes.AddAliasAndKey(newContentType.Alias, newContentType.Key);
Expand All @@ -95,7 +108,7 @@ public override string GetDatabaseType(SyncMigrationDataTypeProperty dataTypePro
blocks.Add(new BlockListConfiguration.BlockConfiguration
{
ContentElementTypeKey = newContentType.Key,
Label = fieldSet.LabelTemplate,
Label = fieldSet.LabelTemplate.IfNullOrWhiteSpace(fieldSet.Label),
});
}

Expand All @@ -107,39 +120,45 @@ public override string GetDatabaseType(SyncMigrationDataTypeProperty dataTypePro
public override string? GetContentValue(SyncMigrationContentProperty contentProperty, SyncMigrationContext context)
{
if (string.IsNullOrWhiteSpace(contentProperty?.Value))
{
return string.Empty;
}

var archetype = JsonConvert.DeserializeObject<ArchetypeModel>(contentProperty.Value, new JsonSerializerSettings() { DateParseHandling = DateParseHandling.None });
if (archetype == null)
{
var archetype = JsonConvert.DeserializeObject<ArchetypeModel>(contentProperty.Value, SerializerSettings);

if (archetype is null)
return string.Empty;
}

var items = archetype.Fieldsets?.Where(f => !f.Disabled);
var items = archetype.Fieldsets
.Where(f => !f.Disabled)
.ToList();

if (items?.Any() != true)
{
if (!items.Any())
return string.Empty;
}

var contentData = new List<BlockItemData>();

var layout = new List<BlockListLayoutItem>();

var dataTypeAlias = _archetypeAliasResolver.GetDataTypeAlias(contentProperty, context);

foreach (var item in items)
{
var blockElementAlias = _archetypeMigrationConfigurer?.GetBlockElementAlias(item, contentProperty, context);
if (blockElementAlias is null) continue;
var blockElementAlias = _archetypeAliasResolver.GetBlockElementAlias(item.Alias!, dataTypeAlias);

if (string.IsNullOrEmpty(blockElementAlias))
continue;

var rawValues = new Dictionary<string, object?>();

foreach (var property in item.Properties)
{
if (string.IsNullOrEmpty(property.Alias)) continue;
if (string.IsNullOrEmpty(property.Alias))
continue;

var editorAlias = context.ContentTypes
.GetEditorAliasByTypeAndProperty(blockElementAlias, property.Alias);

var editorAlias = context.ContentTypes.GetEditorAliasByTypeAndProperty(blockElementAlias, property.Alias);
if (editorAlias is null) continue;
if (editorAlias is null)
continue;

var migrator = context.Migrators.TryGetMigrator(editorAlias.OriginalEditorAlias);

Expand All @@ -151,30 +170,32 @@ public override string GetDatabaseType(SyncMigrationDataTypeProperty dataTypePro

var childProperty = new SyncMigrationContentProperty(
contentTypeAlias: blockElementAlias,
propertyAlias: contentProperty.PropertyAlias,
propertyAlias: property.Alias,
editorAlias: editorAlias.OriginalEditorAlias,
value: property.Value?.ToString() ?? string.Empty);

rawValues[property.Alias] = migrator.GetContentValue(childProperty, context);
}

var key = context.ContentTypes.GetKeyByAlias(blockElementAlias);

var block = new BlockItemData
{
ContentTypeKey = key,
Udi = Udi.Create(UmbConstants.UdiEntityType.Element, item.Id),
RawPropertyValues = rawValues,
};

layout.Add(new BlockListLayoutItem { ContentUdi = block.Udi });
layout.Add(new BlockListLayoutItem
{
ContentUdi = block.Udi
});

contentData.Add(block);
}

if (contentData.Any() == false)
{
if (!contentData.Any())
return string.Empty;
}

var model = new BlockValue
{
Expand All @@ -187,4 +208,4 @@ public override string GetDatabaseType(SyncMigrationDataTypeProperty dataTypePro

return JsonConvert.SerializeObject(model, Formatting.Indented);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;

namespace uSync.Migrations.Migrators.Community.Archetype;

public class DefaultArchetypeAliasResolver : IArchetypeAliasResolver
{
private readonly ArchetypeMigrationOptions _options;
private readonly IShortStringHelper _shortStringHelper;

public DefaultArchetypeAliasResolver(
IOptions<ArchetypeMigrationOptions> options,
IShortStringHelper shortStringHelper)
{
_options = options.Value;
_shortStringHelper = shortStringHelper;
}

/// <summary>
/// Gets the unique block element alias for the provided <paramref name="fieldSetAlias"/> and <paramref name="dataTypeAlias"/>
/// </summary>
/// <param name="fieldSetAlias">the archetype fieldset alias</param>
/// <param name="dataTypeAlias">the data type alias</param>
/// <returns></returns>
public string GetBlockElementAlias(string fieldSetAlias, string dataTypeAlias) =>
GetRenamedAlias(GetUniqueAlias(fieldSetAlias, dataTypeAlias));

/// <summary>
/// Locates the alias for the data type
/// </summary>
/// <param name="contentProperty"></param>
/// <param name="context"></param>
/// <returns></returns>
public string GetDataTypeAlias(SyncMigrationContentProperty contentProperty, SyncMigrationContext context)
{
// Locate based on the content type
var contentTypeDataTypeAlias = context.ContentTypes
.GetDataTypeAlias(contentProperty.ContentTypeAlias, contentProperty.PropertyAlias);

if (!string.IsNullOrEmpty(contentTypeDataTypeAlias))
return contentTypeDataTypeAlias;

// Locate based on the composition content type
if (context.ContentTypes.TryGetCompositionsByAlias(contentProperty.ContentTypeAlias, out var compositions))
{
foreach (var compositionAlias in compositions.EmptyNull())
{
var compositionDataTypeAlias = context.ContentTypes
.GetDataTypeAlias(compositionAlias, contentProperty.PropertyAlias);

if (!string.IsNullOrEmpty(compositionDataTypeAlias))
return compositionDataTypeAlias;
}
}

// Locate based on the new content types
var newContentType = context.ContentTypes.GetNewContentTypes()
.FirstOrDefault(ct => ct.Alias == contentProperty.ContentTypeAlias);

if (newContentType is null)
return string.Empty;

var newPropertyType = newContentType.Properties
.FirstOrDefault(pt => pt.Alias == contentProperty.PropertyAlias);

if (newPropertyType is not null)
return newPropertyType.DataTypeAlias;

return string.Empty;
}

/// <summary>
/// Filters out document types marked as not mergable and generates a unique alias
/// </summary>
/// <param name="fieldSetAlias"></param>
/// <param name="dataTypeAlias"></param>
/// <returns></returns>
private string GetUniqueAlias(string fieldSetAlias, string dataTypeAlias)
{
string suffix = _options.NotMergableDocumentTypes.EmptyNull().Contains(fieldSetAlias)
? dataTypeAlias.ToCleanString(_shortStringHelper, CleanStringType.Alias).ToFirstUpper()
: string.Empty;

return fieldSetAlias.ToFirstLower() + suffix;
}

/// <summary>
/// Switches for the renamed document type given the provided <paramref name="alias"/>
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
private string GetRenamedAlias(string alias)
{
if (_options.RenamedDocumentTypesAliases is not null &&
_options.RenamedDocumentTypesAliases.TryGetValue(alias, out string? renamedAlias))
return renamedAlias;

return alias;
}
}

This file was deleted.

Loading
Loading