From b318df120ca5aa3bb2cbc5f194138deac9be7c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Krch?= Date: Sun, 14 Jul 2024 22:41:32 +0200 Subject: [PATCH 1/2] #184 deprecation of XbKConnectionString --- .../ConfigurationValidator.cs | 4 +- Migration.Toolkit.CLI/Program.cs | 7 +- .../ConfigurationNames.cs | 1 + .../ToolkitConfiguration.cs | 68 ++----- .../CmsClass/EditableAreasConfiguration.cs | 187 ------------------ .../Services/CmsClass/PageSelectorItem.cs | 11 -- .../CmsClass/PageTemplateConfiguration.cs | 29 --- 7 files changed, 21 insertions(+), 286 deletions(-) delete mode 100644 Migration.Toolkit.Core.KX13/Services/CmsClass/EditableAreasConfiguration.cs delete mode 100644 Migration.Toolkit.Core.KX13/Services/CmsClass/PageSelectorItem.cs delete mode 100644 Migration.Toolkit.Core.KX13/Services/CmsClass/PageTemplateConfiguration.cs diff --git a/Migration.Toolkit.CLI/ConfigurationValidator.cs b/Migration.Toolkit.CLI/ConfigurationValidator.cs index 1dac9638..6672635d 100644 --- a/Migration.Toolkit.CLI/ConfigurationValidator.cs +++ b/Migration.Toolkit.CLI/ConfigurationValidator.cs @@ -37,9 +37,9 @@ public static IEnumerable GetValidationErrors(IConfigurationR yield return new ValidationMessage(ValidationMessageType.Warning, Resources.ConfigurationValidator_GetValidationErrors_SourceCmsDirPath_IsRecommended); } - if (CheckCfgValue(settings?.GetValue(ConfigurationNames.XbKConnectionString))) + if (settings?.GetValue(ConfigurationNames.XbKConnectionString) is {}) { - yield return new ValidationMessage(ValidationMessageType.Error, Resources.ConfigurationValidator_GetValidationErrors_TargetConnectionString_IsRequired); + yield return new ValidationMessage(ValidationMessageType.Warning, $"Configuration key '{ConfigurationNames.XbKConnectionString}' is deprecated, use 'Settings:ConnectionStrings:CMSConnectionString' instead"); } if (CheckCfgValue(settings?.GetValue(ConfigurationNames.XbKDirPath))) diff --git a/Migration.Toolkit.CLI/Program.cs b/Migration.Toolkit.CLI/Program.cs index bb14a9e7..49b5fc72 100644 --- a/Migration.Toolkit.CLI/Program.cs +++ b/Migration.Toolkit.CLI/Program.cs @@ -81,8 +81,9 @@ } var settingsSection = config.GetRequiredSection(ConfigurationNames.Settings); -var settings = settingsSection.Get(); -settings.EntityConfigurations ??= new EntityConfigurations(); +var settings = settingsSection.Get() ?? new(); +var kxpApiSettings = settingsSection.GetSection(ConfigurationNames.XbKApiSettings); +settings.SetXbKConnectionStringIfNotEmpty(kxpApiSettings["ConnectionStrings:CMSConnectionString"]); var services = new ServiceCollection(); @@ -150,7 +151,7 @@ services.UseKxpDbContext(settings); -var kxpApiSettings = settingsSection.GetSection(ConfigurationNames.XbKApiSettings); + services.UseKxpApi(kxpApiSettings, settings.XbKDirPath); services.AddSingleton(settings); services.AddSingleton(); diff --git a/Migration.Toolkit.Common/ConfigurationNames.cs b/Migration.Toolkit.Common/ConfigurationNames.cs index e6a5ae5f..2ccdd997 100644 --- a/Migration.Toolkit.Common/ConfigurationNames.cs +++ b/Migration.Toolkit.Common/ConfigurationNames.cs @@ -5,6 +5,7 @@ public class ConfigurationNames public const string KxConnectionString = "KxConnectionString"; public const string KxCmsDirPath = "KxCmsDirPath"; + [Obsolete("not needed anymore, connection string from Kentico config section is used")] public const string XbKConnectionString = "XbKConnectionString"; public const string XbKDirPath = "XbKDirPath"; diff --git a/Migration.Toolkit.Common/ToolkitConfiguration.cs b/Migration.Toolkit.Common/ToolkitConfiguration.cs index a8af69ba..8874ecd5 100644 --- a/Migration.Toolkit.Common/ToolkitConfiguration.cs +++ b/Migration.Toolkit.Common/ToolkitConfiguration.cs @@ -42,13 +42,26 @@ public string KxConnectionString #region Connection string of target instance [ConfigurationKeyName(ConfigurationNames.XbKConnectionString)] - public string? XbKConnectionString { get; set; } + public string XbKConnectionString + { + get => _xbKConnectionString!; + set => _xbKConnectionString = value; + } + + public void SetXbKConnectionStringIfNotEmpty(string? connectionString) + { + if (!string.IsNullOrWhiteSpace(connectionString)) + { + _xbKConnectionString = connectionString; + } + } #endregion #region Path to root directory of target instance private HashSet? _classNamesCreateReusableSchema; + private string? _xbKConnectionString; [ConfigurationKeyName(ConfigurationNames.XbKDirPath)] public string? XbKDirPath { get; set; } = null; @@ -82,59 +95,6 @@ public string KxConnectionString StringComparer.InvariantCultureIgnoreCase ); - public Dictionary RequireExplicitMapping(Expression> keyNameSelector) - { - var memberName = keyNameSelector.GetMemberName(); - var migratedIds = EntityConfigurations?.GetEntityConfiguration()?.ExplicitPrimaryKeyMapping[memberName]; - if (migratedIds == null) - { - throw new InvalidOperationException(string.Format(Resources.Exception_MappingIsRequired, typeof(TEntityType).Name, memberName)); - } - - return migratedIds.ToDictionary(kvp => - { - if (int.TryParse(kvp.Key, out var id)) - { - return id; - } - - throw new InvalidOperationException(string.Format(Resources.Exception_MappingIsRequired, typeof(TEntityType).Name, memberName)); - }, kvp => - { - if (kvp.Value is { } id) - { - return id; - } - - throw new InvalidOperationException(string.Format(Resources.Exception_MappingIsRequired, typeof(TEntityType).Name, memberName)); - }); - } - - public void AddExplicitMapping(Expression> keyNameSelector, int sourceId, int targetId) - { - var memberName = keyNameSelector.GetMemberName(); - EntityConfigurations ??= new EntityConfigurations(); - - var entityConfiguration = EntityConfigurations.GetEntityConfiguration(); - var mapping = entityConfiguration.ExplicitPrimaryKeyMapping; - if (!mapping.ContainsKey(memberName)) - { - mapping.Add(memberName, new()); - } - - if (!mapping[memberName].ContainsKey(sourceId.ToString())) - { - mapping[memberName].Add(sourceId.ToString(), targetId); - } - else - { - mapping[memberName][sourceId.ToString()] = targetId; - } - - EntityConfigurations.SetEntityConfiguration(entityConfiguration); - } - - #region Opt-in features [ConfigurationKeyName(ConfigurationNames.OptInFeatures)] diff --git a/Migration.Toolkit.Core.KX13/Services/CmsClass/EditableAreasConfiguration.cs b/Migration.Toolkit.Core.KX13/Services/CmsClass/EditableAreasConfiguration.cs deleted file mode 100644 index 634f8de2..00000000 --- a/Migration.Toolkit.Core.KX13/Services/CmsClass/EditableAreasConfiguration.cs +++ /dev/null @@ -1,187 +0,0 @@ -namespace Migration.Toolkit.Core.KX13.Services.CmsClass; - -using System.Runtime.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -#region Copied from Kentico assembly - -[DataContract(Name = "Configuration", Namespace = "")] -public sealed class EditableAreasConfiguration -{ - /// Editable areas within the page. - [DataMember] - [JsonProperty("editableAreas")] - public List EditableAreas { get; private set; } - - /// - /// Creates an instance of class. - /// - public EditableAreasConfiguration() => this.EditableAreas = new List(); -} - -/// -/// Represents configuration of editable area within the instance. -/// -[DataContract(Name = "EditableArea", Namespace = "")] -public sealed class EditableAreaConfiguration -{ - /// Identifier of the editable area. - [DataMember] - [JsonProperty("identifier")] - public string Identifier { get; set; } - - /// Sections within editable area. - [DataMember] - [JsonProperty("sections")] - public List Sections { get; private set; } - - /// - /// A flag indicating whether the output of the individual widgets within the editable area can be cached. The default value is false. - /// - public bool AllowWidgetOutputCache { get; set; } - - /// - /// An absolute expiration date for the cached output of the individual widgets. - /// - public DateTimeOffset? WidgetOutputCacheExpiresOn { get; set; } - - /// - /// The length of time from the first request to cache the output of the individual widgets. - /// - public TimeSpan? WidgetOutputCacheExpiresAfter { get; set; } - - /// - /// The time after which the cached output of the individual widgets should be evicted if it has not been accessed. - /// - public TimeSpan? WidgetOutputCacheExpiresSliding { get; set; } - - /// - /// Creates an instance of class. - /// - public EditableAreaConfiguration() => this.Sections = new List(); -} - -/// -/// Represents configuration of section within the instance. -/// -[DataContract(Name = "Section", Namespace = "")] -public sealed class SectionConfiguration -{ - /// Identifier of the section. - [DataMember] - [JsonProperty("identifier")] - public Guid Identifier { get; set; } - - /// Type section identifier. - [DataMember] - [JsonProperty("type")] - public string TypeIdentifier { get; set; } - - /// Section properties. - [DataMember] - [JsonProperty("properties")] - // public ISectionProperties Properties { get; set; } - public JObject? Properties { get; set; } - - /// Zones within the section. - [DataMember] - [JsonProperty("zones")] - public List Zones { get; private set; } - - /// - /// Creates an instance of class. - /// - public SectionConfiguration() => this.Zones = new List(); -} - -/// -/// Represents the zone within the configuration class. -/// -[DataContract(Name = "Zone", Namespace = "")] -public sealed class ZoneConfiguration -{ - /// Identifier of the widget zone. - [DataMember] - [JsonProperty("identifier")] - public Guid Identifier { get; set; } - - /// Name of the widget zone. - [DataMember] - [JsonProperty("name")] - public string Name { get; set; } - - /// List of widgets within the zone. - [DataMember] - [JsonProperty("widgets")] - public List Widgets { get; private set; } - - /// - /// Creates an instance of class. - /// - public ZoneConfiguration() => this.Widgets = new List(); -} - -/// -/// Represents the configuration of a widget within the list. -/// -[DataContract(Name = "Widget", Namespace = "")] -public sealed class WidgetConfiguration -{ - /// Identifier of the widget instance. - [DataMember] - [JsonProperty("identifier")] - public Guid Identifier { get; set; } - - /// Type widget identifier. - [DataMember] - [JsonProperty("type")] - public string TypeIdentifier { get; set; } - - /// Personalization condition type identifier. - [DataMember] - [JsonProperty("conditionType")] - public string PersonalizationConditionTypeIdentifier { get; set; } - - /// List of widget variants. - [DataMember] - [JsonProperty("variants")] - public List Variants { get; set; } - - /// - /// Creates an instance of class. - /// - public WidgetConfiguration() => this.Variants = new List(); -} - -/// -/// Represents the configuration variant of a widget within the list. -/// -[DataContract(Name = "Variant", Namespace = "")] -public sealed class WidgetVariantConfiguration -{ - /// Identifier of the variant instance. - [DataMember] - [JsonProperty("identifier")] - public Guid Identifier { get; set; } - - /// Widget variant name. - [DataMember] - [JsonProperty("name")] - public string Name { get; set; } - - /// Widget variant properties. - [DataMember] - [JsonProperty("properties")] - // public IWidgetProperties Properties { get; set; } - public JObject Properties { get; set; } - - /// Widget variant personalization condition type. - /// Only personalization condition type parameters are serialized to JSON. - [DataMember] - [JsonProperty("conditionTypeParameters")] - public JObject PersonalizationConditionType { get; set; } -} - -#endregion - diff --git a/Migration.Toolkit.Core.KX13/Services/CmsClass/PageSelectorItem.cs b/Migration.Toolkit.Core.KX13/Services/CmsClass/PageSelectorItem.cs deleted file mode 100644 index 7b6941b0..00000000 --- a/Migration.Toolkit.Core.KX13/Services/CmsClass/PageSelectorItem.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Migration.Toolkit.Core.KX13.Services.CmsClass; - -using Newtonsoft.Json; - -/// Represents an item for a page selector. -public class PageSelectorItem -{ - /// Node Guid of a page. - [JsonProperty("nodeGuid")] - public Guid NodeGuid { get; set; } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX13/Services/CmsClass/PageTemplateConfiguration.cs b/Migration.Toolkit.Core.KX13/Services/CmsClass/PageTemplateConfiguration.cs deleted file mode 100644 index 501d10c7..00000000 --- a/Migration.Toolkit.Core.KX13/Services/CmsClass/PageTemplateConfiguration.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Migration.Toolkit.Core.KX13.Services.CmsClass; - -using System.Runtime.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -/// -/// Page template configuration for the instance. -/// -[DataContract(Name = "PageTemplate", Namespace = "")] -public class PageTemplateConfiguration -{ - /// Identifier of the page template. - [DataMember] - [JsonProperty("identifier")] - public string Identifier { get; set; } - - /// - /// Identifier of the page template configuration based on which the page was created. - /// - [DataMember] - [JsonProperty("configurationIdentifier")] - public Guid ConfigurationIdentifier { get; set; } - - /// Page template properties. - [DataMember] - [JsonProperty("properties")] - public JObject Properties { get; set; } -} \ No newline at end of file From d69d071c4f87458fc9e4b187c28b680693f23f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Krch?= Date: Sun, 14 Jul 2024 22:44:06 +0200 Subject: [PATCH 2/2] #184 deprecation of XbKConnectionString - md file update --- Migration.Toolkit.CLI/README.md | 32 ++++++++++++-------------- Migration.Toolkit.CLI/appsettings.json | 1 - 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Migration.Toolkit.CLI/README.md b/Migration.Toolkit.CLI/README.md index 334da488..89e8770f 100644 --- a/Migration.Toolkit.CLI/README.md +++ b/Migration.Toolkit.CLI/README.md @@ -312,24 +312,23 @@ Before you run the migration, configure options in the `Migration.Toolkit.CLI/ap Add the options under the `Settings` section in the configuration file. -| Configuration | Description | -|----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| -| KxConnectionString | The connection string to the source Kentico Xperience 13 database. | -| KxCmsDirPath | The absolute file system path of the **CMS** folder in the source Kentico Xperience 13 administration project. Required to migrate media library files. | -| XbKConnectionString | The connection string to the target Xperience by Kentico database. | -| XbKDirPath | The absolute file system path of the root of the target Xperience by Kentico project. Required to migrate media library and page attachment files. | -| XbKApiSettings | Configuration options set for the API when creating migrated objects in the target application.

The `ConnectionStrings.CMSConnectionString`option is required - set the connection string to the target Xperience by Kentico database (the same value as `XbKConnectionString`). | -| MigrationProtocolPath | The absolute file system path of the location where the [migration protocol file](./MIGRATION_PROTOCOL_REFERENCE.md) is generated.

For example: `"C:\\Logs\\Migration.Toolkit.Protocol.log"` | -| MigrateOnlyMediaFileInfo | If set to `true`, only the database representations of media files are migrated, without the files in the media folder in the project's file system. For example, enable this option if your media library files are mapped to a shared directory or Cloud storage.

If `false`, media files are migrated based on the `KxCmsDirPath` location. | +| Configuration | Description | +|---------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| +| KxConnectionString | The connection string to the source Kentico Xperience 13 database. | +| KxCmsDirPath | The absolute file system path of the **CMS** folder in the source Kentico Xperience 13 administration project. Required to migrate media library files. | +| XbKDirPath | The absolute file system path of the root of the target Xperience by Kentico project. Required to migrate media library and page attachment files. | +| XbKApiSettings | Configuration options set for the API when creating migrated objects in the target application.

The `ConnectionStrings.CMSConnectionString`option is required - set the connection string to the target Xperience by Kentico database (the same value as `XbKConnectionString`). | +| MigrationProtocolPath | The absolute file system path of the location where the [migration protocol file](./MIGRATION_PROTOCOL_REFERENCE.md) is generated.

For example: `"C:\\Logs\\Migration.Toolkit.Protocol.log"` | +| MigrateOnlyMediaFileInfo | If set to `true`, only the database representations of media files are migrated, without the files in the media folder in the project's file system. For example, enable this option if your media library files are mapped to a shared directory or Cloud storage.

If `false`, media files are migrated based on the `KxCmsDirPath` location. | | MemberIncludeUserSystemFields | Determines which system fields from the *CMS_User* and *CMS_UserSettings* tables are migrated to *CMS_Member* in Xperience by Kentico. Fields that do not exist in *CMS_Member* are automatically created.

The sample `appsettings.json` file included with the toolkit by default includes all user fields that can be migrated from Kentico Xperience 13. Exclude specific fields from the migration by removing them from this configuration option. | -| UseOmActivityNodeRelationAutofix | Determines how the migration handles references from Contact management activities to non-existing pages.

Possible options:
`DiscardData` - faulty references are removed,
`AttemptFix` - references are updated to the IDs of corresponding pages created by the migration,
`Error` - an error is reported and the reference can be translated or otherwise handled manually | -| UseOmActivitySiteRelationAutofix | Determines how the migration handles site references from Contact management activities.

Possible options: `DiscardData`,`AttemptFix`,`Error` | -| EntityConfigurations | Contains options that allow you to fine-tune the migration of specific object types. | -| EntityConfigurations.*<object table name>*.ExcludeCodeNames | Excludes objects with the specified code names from the migration. | +| UseOmActivityNodeRelationAutofix | Determines how the migration handles references from Contact management activities to non-existing pages.

Possible options:
`DiscardData` - faulty references are removed,
`AttemptFix` - references are updated to the IDs of corresponding pages created by the migration,
`Error` - an error is reported and the reference can be translated or otherwise handled manually | +| UseOmActivitySiteRelationAutofix | Determines how the migration handles site references from Contact management activities.

Possible options: `DiscardData`,`AttemptFix`,`Error` | +| EntityConfigurations | Contains options that allow you to fine-tune the migration of specific object types. | +| EntityConfigurations.*<object table name>*.ExcludeCodeNames | Excludes objects with the specified code names from the migration. | | CreateReusableFieldSchemaForClasses | Specifies which page types are also converted to [reusable field schemas](#convert-page-types-to-reusable-field-schemas). | -| OptInFeatures.QuerySourceInstanceApi.Enabled | If `true`, [source instance API discovery](#source-instance-api-discovery) is enabled to allow advanced migration of Page Builder content for pages and page templates. | -| OptInFeatures.QuerySourceInstanceApi.Connections | To use [source instance API discovery](#source-instance-api-discovery), you need to add a connection JSON object containing the following values:
`SourceInstanceUri` - the base URI where the source instance's live site application is running.
`Secret` - the secret that you set in the *ToolkitApiController.cs* file on the source instance. | -| OptInFeatures.CustomMigration.FieldMigrations | Enables conversion of media selection text fields to media library files. See [Convert text fields with media links to media libraries](#convert-text-fields-with-media-links-to-media-libraries) for more information.| +| OptInFeatures.QuerySourceInstanceApi.Enabled | If `true`, [source instance API discovery](#source-instance-api-discovery) is enabled to allow advanced migration of Page Builder content for pages and page templates. | +| OptInFeatures.QuerySourceInstanceApi.Connections | To use [source instance API discovery](#source-instance-api-discovery), you need to add a connection JSON object containing the following values:
`SourceInstanceUri` - the base URI where the source instance's live site application is running.
`Secret` - the secret that you set in the *ToolkitApiController.cs* file on the source instance. | +| OptInFeatures.CustomMigration.FieldMigrations | Enables conversion of media selection text fields to media library files. See [Convert text fields with media links to media libraries](#convert-text-fields-with-media-links-to-media-libraries) for more information.| ### Example @@ -351,7 +350,6 @@ Add the options under the `Settings` section in the configuration file. "Settings": { "KxConnectionString": "Data Source=myserver;Initial Catalog=Xperience13;Integrated Security=True;Persist Security Info=False;Connect Timeout=120;Encrypt=False;Current Language=English;", "KxCmsDirPath": "C:\\inetpub\\wwwroot\\Xperience13\\CMS", - "XbKConnectionString": "Data Source=myserver;Initial Catalog=XperienceByKentico;Integrated Security=True;Persist Security Info=False;Connect Timeout=120;Encrypt=False;Current Language=English;", "XbKDirPath": "C:\\inetpub\\wwwroot\\XP_Target", "XbKApiSettings": { "ConnectionStrings": { diff --git a/Migration.Toolkit.CLI/appsettings.json b/Migration.Toolkit.CLI/appsettings.json index 44faee4a..cad02943 100644 --- a/Migration.Toolkit.CLI/appsettings.json +++ b/Migration.Toolkit.CLI/appsettings.json @@ -18,7 +18,6 @@ "Settings": { "KxConnectionString": "[TODO]", "KxCmsDirPath": "[TODO]", - "XbKConnectionString": "[TODO]", "XbKDirPath": "[TODO]", "MigrateOnlyMediaFileInfo": false, "XbKApiSettings": {