Skip to content

Commit

Permalink
re-introduction of simple conversion to reusable content item
Browse files Browse the repository at this point in the history
  • Loading branch information
tkrch committed Nov 8, 2024
1 parent 687605a commit a9cb03a
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,27 +103,30 @@ public async Task<CommandResult> Handle(MigratePageTypesCommand request, Cancell
bool hasFieldsAlready = true;
foreach (var cmml in classMapping.Mappings.Where(m => m.IsTemplate).ToLookup(x => x.SourceFieldName))
{
var cmm = cmml.FirstOrDefault() ?? throw new InvalidOperationException();
if (fieldInReusableSchemas.ContainsKey(cmm.TargetFieldName))
foreach (var cmm in cmml)
{
// part of reusable schema
continue;
}
if (fieldInReusableSchemas.ContainsKey(cmm.TargetFieldName))
{
// part of reusable schema
continue;
}

var sc = cmsClasses.FirstOrDefault(sc => sc.ClassName.Equals(cmm.SourceClassName, StringComparison.InvariantCultureIgnoreCase))
?? throw new NullReferenceException($"The source class '{cmm.SourceClassName}' does not exist - wrong mapping {classMapping}");
var sc = cmsClasses.FirstOrDefault(sc => sc.ClassName.Equals(cmm.SourceClassName, StringComparison.InvariantCultureIgnoreCase))
?? throw new NullReferenceException($"The source class '{cmm.SourceClassName}' does not exist - wrong mapping {classMapping}");

var fi = new FormInfo(sc.ClassFormDefinition);
if (nfi.GetFormField(cmm.TargetFieldName) is { })
{
}
else
{
var src = fi.GetFormField(cmm.SourceFieldName);
src.Name = cmm.TargetFieldName;
nfi.AddFormItem(src);
hasFieldsAlready = false;
var fi = new FormInfo(sc.ClassFormDefinition);
if (nfi.GetFormField(cmm.TargetFieldName) is { })
{
}
else
{
var src = fi.GetFormField(cmm.SourceFieldName);
src.Name = cmm.TargetFieldName;
nfi.AddFormItem(src);
hasFieldsAlready = false;
}
}
//var cmm = cmml.FirstOrDefault() ?? throw new InvalidOperationException();
}

if (!hasFieldsAlready)
Expand Down Expand Up @@ -242,26 +245,29 @@ public async Task<CommandResult> Handle(MigratePageTypesCommand request, Cancell
var kxoDataClass = kxpClassFacade.GetClass(ksClass.ClassGUID);
protocol.FetchedTarget(kxoDataClass);

if (SaveUsingKxoApi(ksClass, kxoDataClass) is { } targetClassId)
if (SaveUsingKxoApi(ksClass, kxoDataClass) is { } targetClass)
{
foreach (var cmsClassSite in modelFacade.SelectWhere<ICmsClassSite>("ClassID = @classId", new SqlParameter("classId", ksClass.ClassID)))
if (targetClass.ClassContentTypeType is ClassContentTypeType.WEBSITE)
{
if (modelFacade.SelectById<ICmsSite>(cmsClassSite.SiteID) is { SiteGUID: var siteGuid })
foreach (var cmsClassSite in modelFacade.SelectWhere<ICmsClassSite>("ClassID = @classId", new SqlParameter("classId", ksClass.ClassID)))
{
if (ChannelInfoProvider.ProviderObject.Get(siteGuid) is { ChannelID: var channelId })
if (modelFacade.SelectById<ICmsSite>(cmsClassSite.SiteID) is { SiteGUID: var siteGuid })
{
var info = new ContentTypeChannelInfo { ContentTypeChannelChannelID = channelId, ContentTypeChannelContentTypeID = targetClassId };
ContentTypeChannelInfoProvider.ProviderObject.Set(info);
if (ChannelInfoProvider.ProviderObject.Get(siteGuid) is { ChannelID: var channelId })
{
var info = new ContentTypeChannelInfo { ContentTypeChannelChannelID = channelId, ContentTypeChannelContentTypeID = targetClass.ClassID };
ContentTypeChannelInfoProvider.ProviderObject.Set(info);
}
else
{
logger.LogWarning("Channel for site with SiteGUID '{SiteGuid}' not found", siteGuid);
}
}
else
{
logger.LogWarning("Channel for site with SiteGUID '{SiteGuid}' not found", siteGuid);
logger.LogWarning("Source site with SiteID '{SiteId}' not found", cmsClassSite.SiteID);
}
}
else
{
logger.LogWarning("Source site with SiteID '{SiteId}' not found", cmsClassSite.SiteID);
}
}
}
}
Expand Down Expand Up @@ -337,7 +343,7 @@ private async Task MigratePageTemplateConfigurations()
}
}

private int? SaveUsingKxoApi(ICmsClass ksClass, DataClassInfo kxoDataClass)
private DataClassInfo? SaveUsingKxoApi(ICmsClass ksClass, DataClassInfo kxoDataClass)
{
var mapped = dataClassMapper.Map(ksClass, kxoDataClass);
protocol.MappedTarget(mapped);
Expand Down Expand Up @@ -365,7 +371,7 @@ private async Task MigratePageTemplateConfigurations()
dataClassInfo.ClassID
);

return dataClassInfo.ClassID;
return dataClassInfo;
}
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ public async Task<CommandResult> Handle(MigratePagesCommand request, Cancellatio
{
switch (await importer.ImportAsync(umtModel))
{
case { Success: false } result:
{
logger.LogError("Failed to import: {Exception}, {ValidationResults}", result.Exception, JsonConvert.SerializeObject(result.ModelValidationResults));
break;
}
case { Success: true, Imported: ContentItemCommonDataInfo ccid }:
{
commonDataInfos.Add(ccid);
Expand Down
7 changes: 5 additions & 2 deletions KVA/Migration.Tool.Source/Mappers/CmsClassMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public class CmsClassMapper(
PrimaryKeyMappingContext primaryKeyMappingContext,
IProtocol protocol,
FieldMigrationService fieldMigrationService,
ModelFacade modelFacade
ModelFacade modelFacade,
ToolConfiguration configuration
)
: EntityMapperBase<ICmsClass, DataClassInfo>(logger,
primaryKeyMappingContext, protocol)
Expand Down Expand Up @@ -188,7 +189,9 @@ protected override DataClassInfo MapInternal(ICmsClass source, DataClassInfo tar
}:
{
target.ClassType = ClassType.CONTENT_TYPE;
target.ClassContentTypeType = ClassContentTypeType.WEBSITE;
target.ClassContentTypeType = configuration.ClassNamesConvertToContentHub.Contains(target.ClassName)
? ClassContentTypeType.REUSABLE
: ClassContentTypeType.WEBSITE;

target = PatchDataClassInfo(target, out string? oldPrimaryKeyName, out string? documentNameField);
break;
Expand Down
2 changes: 1 addition & 1 deletion KVA/Migration.Tool.Source/Mappers/ContentItemMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ protected override IEnumerable<IUmtModel> MapInternal(CmsTreeMapperSource source
bool migratedAsContentFolder = sourceNodeClass.ClassName.Equals("cms.folder", StringComparison.InvariantCultureIgnoreCase) && !configuration.UseDeprecatedFolderPageType.GetValueOrDefault(false);

var contentItemGuid = spoiledGuidContext.EnsureNodeGuid(cmsTree.NodeGUID, cmsTree.NodeSiteID, cmsTree.NodeID);
bool isMappedTypeReusable = targetClassInfo?.ClassContentTypeType is ClassContentTypeType.REUSABLE;
bool isMappedTypeReusable = (targetClassInfo?.ClassContentTypeType is ClassContentTypeType.REUSABLE) || configuration.ClassNamesConvertToContentHub.Contains(sourceNodeClass.ClassName);
yield return new ContentItemModel
{
ContentItemGUID = contentItemGuid,
Expand Down
1 change: 1 addition & 0 deletions Migration.Tool.Common/ConfigurationNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ConfigurationNames
public const string UseDeprecatedFolderPageType = "UseDeprecatedFolderPageType";

public const string ExcludeCodeNames = "ExcludeCodeNames";
public const string ConvertClassesToContentHub = "ConvertClassesToContentHub";
public const string ExplicitPrimaryKeyMapping = "ExplicitPrimaryKeyMapping";

public const string SiteName = "SiteName";
Expand Down
9 changes: 9 additions & 0 deletions Migration.Tool.Common/ToolConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,19 @@ public class ToolConfiguration
[ConfigurationKeyName(ConfigurationNames.CreateReusableFieldSchemaForClasses)]
public string? CreateReusableFieldSchemaForClasses { get; set; }

[ConfigurationKeyName(ConfigurationNames.ConvertClassesToContentHub)]
public string? ConvertClassesToContentHub { get; set; }

public IReadOnlySet<string> ClassNamesCreateReusableSchema => classNamesCreateReusableSchema ??= new HashSet<string>(
(CreateReusableFieldSchemaForClasses?.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) ?? []).Select(x => x.Trim()),
StringComparer.InvariantCultureIgnoreCase
);

public IReadOnlySet<string> ClassNamesConvertToContentHub => classNamesConvertToContentHub ??= new HashSet<string>(
(ConvertClassesToContentHub?.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) ?? []).Select(x => x.Trim()),
StringComparer.InvariantCultureIgnoreCase
);

#region Opt-in features

[ConfigurationKeyName(ConfigurationNames.OptInFeatures)]
Expand Down Expand Up @@ -95,6 +103,7 @@ public void SetXbKConnectionStringIfNotEmpty(string? connectionString)

#region Path to root directory of target instance

private HashSet<string>? classNamesConvertToContentHub;
private HashSet<string>? classNamesCreateReusableSchema;
private string? xbKConnectionString;

Expand Down
6 changes: 6 additions & 0 deletions Migration.Tool.Extensions/ClassMappings/ClassMappingSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public static IServiceCollection AddReusableRemodelingSample(this IServiceCollec
.SetFrom(sourceClassName, "CoffeeFarm", true)
.WithFieldPatch(f => f.SetPropertyValue(FormFieldPropertyEnum.FieldCaption, "Farm RM"));

// field clone sample
m
.BuildField("FarmRM_Clone")
.SetFrom(sourceClassName, "CoffeeFarm", true)
.WithFieldPatch(f => f.SetPropertyValue(FormFieldPropertyEnum.FieldCaption, "Farm RM Clone"));

m
.BuildField("CoffeeCountryRM")
.WithFieldPatch(f => f.Caption = "Country RM")
Expand Down
4 changes: 4 additions & 0 deletions Migration.Tool.Extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ To create custom widget migration:
Samples:
- [Sample BannerWidget migration](./CommunityMigrations/SampleWidgetMigration.cs)

### Convert page type to reusable content item (content hub)

demonstrated in method `AddReusableRemodelingSample`. Please note, that all information unique to page will be lost

## Custom widget property migrations

To create custom widget property migration:
Expand Down

0 comments on commit a9cb03a

Please sign in to comment.