diff --git a/KVA/Migration.Toolkit.Source/Contexts/PrimaryKeyMappingContext.cs b/KVA/Migration.Toolkit.Source/Contexts/PrimaryKeyMappingContext.cs index 7149f318..ca62769b 100644 --- a/KVA/Migration.Toolkit.Source/Contexts/PrimaryKeyMappingContext.cs +++ b/KVA/Migration.Toolkit.Source/Contexts/PrimaryKeyMappingContext.cs @@ -5,7 +5,6 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Migration.Toolkit.Common; -using Migration.Toolkit.Common.Services; using Migration.Toolkit.Source.Services; public class PrimaryKeyMappingContext( @@ -23,7 +22,7 @@ public class PrimaryKeyMappingContext( var mappings = toolkitConfiguration.EntityConfigurations?.GetEntityConfiguration().ExplicitPrimaryKeyMapping; if (mappings?.TryGetValue(memberName, out var memberMappings) ?? false) { - return memberMappings.TryGetValue($"{sourceId}", out var mappedId) ? mappedId : null; + return memberMappings.GetValueOrDefault($"{sourceId}"); } return null; diff --git a/KVA/Migration.Toolkit.Source/Handlers/MigrateAttachmentsCommandHandler.cs b/KVA/Migration.Toolkit.Source/Handlers/MigrateAttachmentsCommandHandler.cs index c8fbb865..b7def7d0 100644 --- a/KVA/Migration.Toolkit.Source/Handlers/MigrateAttachmentsCommandHandler.cs +++ b/KVA/Migration.Toolkit.Source/Handlers/MigrateAttachmentsCommandHandler.cs @@ -14,17 +14,17 @@ AttachmentMigrator attachmentMigrator { public async Task Handle(MigrateAttachmentsCommand request, CancellationToken cancellationToken) { - var kx13CmsAttachments = modelFacade.SelectAll(); + var ksCmsAttachments = modelFacade.SelectAll(); - foreach (var kx13CmsAttachment in kx13CmsAttachments) + foreach (var ksCmsAttachment in ksCmsAttachments) { - if (kx13CmsAttachment.AttachmentIsUnsorted != true || kx13CmsAttachment.AttachmentGroupGUID != null) + if (ksCmsAttachment.AttachmentIsUnsorted != true || ksCmsAttachment.AttachmentGroupGUID != null) { // those must be migrated with pages continue; } - var (_, canContinue, _, _) = attachmentMigrator.MigrateAttachment(kx13CmsAttachment); + var (_, canContinue, _, _) = attachmentMigrator.MigrateAttachment(ksCmsAttachment); if (!canContinue) break; } diff --git a/Migration.Toolkit.Core.K11/Handlers/MigrateMediaLibrariesCommandHandler.cs b/KVA/Migration.Toolkit.Source/Handlers/MigrateMediaLibrariesCommandHandler.cs similarity index 60% rename from Migration.Toolkit.Core.K11/Handlers/MigrateMediaLibrariesCommandHandler.cs rename to KVA/Migration.Toolkit.Source/Handlers/MigrateMediaLibrariesCommandHandler.cs index 4c9755de..370c9f8c 100644 --- a/Migration.Toolkit.Core.K11/Handlers/MigrateMediaLibrariesCommandHandler.cs +++ b/KVA/Migration.Toolkit.Source/Handlers/MigrateMediaLibrariesCommandHandler.cs @@ -1,30 +1,32 @@ -namespace Migration.Toolkit.Core.K11.Handlers; +namespace Migration.Toolkit.Source.Handlers; using CMS.Base; using CMS.MediaLibrary; using MediatR; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Migration.Toolkit.Common; using Migration.Toolkit.Common.Abstractions; using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.K11.Contexts; -using Migration.Toolkit.Core.K11.Mappers; -using Migration.Toolkit.K11; -using Migration.Toolkit.K11.Models; using Migration.Toolkit.KXP.Api; using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Context; - -public class MigrateMediaLibrariesCommandHandler(ILogger logger, - IDbContextFactory kxpContextFactory, - IDbContextFactory k11ContextFactory, - IEntityMapper mediaLibraryInfoMapper, - KxpMediaFileFacade mediaFileFacade, - IEntityMapper mediaFileInfoMapper, - ToolkitConfiguration toolkitConfiguration, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol) +using Migration.Toolkit.KXP.Models; +using Migration.Toolkit.Source.Contexts; +using Migration.Toolkit.Source.Mappers; +using Migration.Toolkit.Source.Model; + +public class MigrateMediaLibrariesCommandHandler( + ILogger logger, + IDbContextFactory kxpContextFactory, + ModelFacade modelFacade, + KxpMediaFileFacade mediaFileFacade, + IEntityMapper mediaFileInfoMapper, + IEntityMapper mediaLibraryInfoMapper, + ToolkitConfiguration toolkitConfiguration, + PrimaryKeyMappingContext primaryKeyMappingContext, + IProtocol protocol) : IRequestHandler, IDisposable { private const string DIR_MEDIA = "media"; @@ -33,66 +35,39 @@ public class MigrateMediaLibrariesCommandHandler(ILogger Handle(MigrateMediaLibrariesCommand request, CancellationToken cancellationToken) { - await using var k11Context = await k11ContextFactory.CreateDbContextAsync(cancellationToken); - - var skippedMediaLibraries = new HashSet(); - var unsuitableMediaLibraries = k11Context.MediaLibraries - .Include(ml => ml.LibrarySite) - .GroupBy(l => l.LibraryName); + var ksMediaLibraries = modelFacade.SelectAll(" ORDER BY LibraryID"); - foreach (var mlg in unsuitableMediaLibraries) + var migratedMediaLibraries = new List<(IMediaLibrary sourceLibrary, ICmsSite sourceSite, MediaLibraryInfo targetLibrary)>(); + foreach (var ksMediaLibrary in ksMediaLibraries) { - if (mlg.Count() <= 1) continue; - - logger.LogError(""" - Media libraries with LibraryGuid ({LibraryGuids}) have same LibraryName '{LibraryName}', due to removal of sites and media library globalization it is required to set unique LibraryName and LibraryFolder - """, string.Join(",", mlg.Select(l => l.LibraryGuid)), mlg.Key); + protocol.FetchedSource(ksMediaLibrary); - foreach (var ml in mlg) + if (ksMediaLibrary.LibraryGUID is not { } mediaLibraryGuid) { - if (ml.LibraryGuid is { } libraryGuid) - { - skippedMediaLibraries.Add(libraryGuid); - } - - protocol.Append(HandbookReferences.NotCurrentlySupportedSkip() - .WithMessage($"Media library '{ml.LibraryName}' with LibraryGuid '{ml.LibraryGuid}' doesn't satisfy unique LibraryName and LibraryFolder condition for migration") - .WithIdentityPrint(ml) - .WithData(new { ml.LibraryGuid, ml.LibraryName, ml.LibrarySiteId, ml.LibraryFolder}) + protocol.Append(HandbookReferences + .InvalidSourceData() + .WithId(nameof(MediaLibrary.LibraryId), ksMediaLibrary.LibraryID) + .WithMessage("Media library has missing MediaLibraryGUID") ); - } - } - - var k11MediaLibraries = k11Context.MediaLibraries - .Include(ml => ml.LibrarySite) - .OrderBy(t => t.LibraryId) - ; - - var migratedMediaLibraries = new List<(MediaLibrary sourceLibrary, MediaLibraryInfo targetLibrary)>(); - foreach (var k11MediaLibrary in k11MediaLibraries) - { - if (k11MediaLibrary.LibraryGuid is {} libraryGuid && skippedMediaLibraries.Contains(libraryGuid)) - { continue; } - protocol.FetchedSource(k11MediaLibrary); + var mediaLibraryInfo = mediaFileFacade.GetMediaLibraryInfo(mediaLibraryGuid); + + protocol.FetchedTarget(mediaLibraryInfo); - if (k11MediaLibrary.LibraryGuid is not { } mediaLibraryGuid) + if (modelFacade.SelectById(ksMediaLibrary.LibrarySiteID) is not { } ksSite) { protocol.Append(HandbookReferences .InvalidSourceData() - .WithId(nameof(MediaLibrary.LibraryId), k11MediaLibrary.LibraryId) - .WithMessage("Media library has missing MediaLibraryGUID") + .WithId(nameof(MediaLibrary.LibraryId), ksMediaLibrary.LibraryID) + .WithMessage("Media library has missing site assigned") ); + logger.LogError("Missing site, SiteID=={SiteId}", ksMediaLibrary.LibrarySiteID); continue; } - var mediaLibraryInfo = mediaFileFacade.GetMediaLibraryInfo(mediaLibraryGuid); - - protocol.FetchedTarget(mediaLibraryInfo); - - var mapped = mediaLibraryInfoMapper.Map(k11MediaLibrary, mediaLibraryInfo); + var mapped = mediaLibraryInfoMapper.Map(new (ksMediaLibrary, ksSite), mediaLibraryInfo); protocol.MappedTarget(mapped); if (mapped is { Success : true } result) @@ -104,7 +79,7 @@ Media libraries with LibraryGuid ({LibraryGuids}) have same LibraryName '{Librar { mediaFileFacade.SetMediaLibrary(mfi); - protocol.Success(k11MediaLibrary, mfi, mapped); + protocol.Success(ksMediaLibrary, mfi, mapped); logger.LogEntitySetAction(newInstance, mfi); } catch (Exception ex) @@ -123,15 +98,15 @@ Media libraries with LibraryGuid ({LibraryGuids}) have same LibraryName '{Librar primaryKeyMappingContext.SetMapping( r => r.LibraryId, - k11MediaLibrary.LibraryId, + ksMediaLibrary.LibraryID, mfi.LibraryID ); - migratedMediaLibraries.Add((k11MediaLibrary, mfi)); + migratedMediaLibraries.Add((ksMediaLibrary, ksSite, mfi)); } } - await RequireMigratedMediaFiles(migratedMediaLibraries, k11Context, cancellationToken); + await RequireMigratedMediaFiles(migratedMediaLibraries, cancellationToken); return new GenericCommandResult(); } @@ -155,49 +130,46 @@ private LoadMediaFileResult LoadMediaFileBinary(string? sourceMediaLibraryPath, return new LoadMediaFileResult(false, null); } - private async Task RequireMigratedMediaFiles( - List<(MediaLibrary sourceLibrary, MediaLibraryInfo targetLibrary)> migratedMediaLibraries, - K11Context k11Context, CancellationToken cancellationToken) + private async Task RequireMigratedMediaFiles(List<(IMediaLibrary sourceLibrary, ICmsSite sourceSite, MediaLibraryInfo targetLibrary)> migratedMediaLibraries, CancellationToken cancellationToken) { var kxoDbContext = await kxpContextFactory.CreateDbContextAsync(cancellationToken); try { - foreach (var (sourceMediaLibrary, targetMediaLibrary) in migratedMediaLibraries) + foreach (var (ksMediaLibrary, ksSite, targetMediaLibrary) in migratedMediaLibraries) { string? sourceMediaLibraryPath = null; var loadMediaFileData = false; if (!toolkitConfiguration.MigrateOnlyMediaFileInfo.GetValueOrDefault(true) && !string.IsNullOrWhiteSpace(toolkitConfiguration.KxCmsDirPath)) { - sourceMediaLibraryPath = Path.Combine(toolkitConfiguration.KxCmsDirPath, sourceMediaLibrary.LibrarySite.SiteName, DIR_MEDIA, sourceMediaLibrary.LibraryFolder); + sourceMediaLibraryPath = Path.Combine(toolkitConfiguration.KxCmsDirPath, ksSite.SiteName, DIR_MEDIA, ksMediaLibrary.LibraryFolder); loadMediaFileData = true; } - var k11MediaFiles = k11Context.MediaFiles - .Where(x => x.FileLibraryId == sourceMediaLibrary.LibraryId); + var ksMediaFiles = modelFacade.SelectWhere("FileLibraryID = @FileLibraryId", new SqlParameter("FileLibraryId", ksMediaLibrary.LibraryID)); - foreach (var k11MediaFile in k11MediaFiles) + foreach (var ksMediaFile in ksMediaFiles) { - protocol.FetchedSource(k11MediaFile); + protocol.FetchedSource(ksMediaFile); bool found = false; IUploadedFile? uploadedFile = null; if (loadMediaFileData) { - (found, uploadedFile) = LoadMediaFileBinary(sourceMediaLibraryPath, k11MediaFile.FilePath, k11MediaFile.FileMimeType); + (found, uploadedFile) = LoadMediaFileBinary(sourceMediaLibraryPath, ksMediaFile.FilePath, ksMediaFile.FileMimeType); if (!found) { // TODO tk: 2022-07-07 report missing file (currently reported in mapper) } } - var librarySubfolder = Path.GetDirectoryName(k11MediaFile.FilePath); + var librarySubfolder = Path.GetDirectoryName(ksMediaFile.FilePath); - var kxoMediaFile = mediaFileFacade.GetMediaFile(k11MediaFile.FileGuid); + var kxoMediaFile = mediaFileFacade.GetMediaFile(ksMediaFile.FileGUID); protocol.FetchedTarget(kxoMediaFile); - var source = new MediaFileInfoMapperSource(k11MediaFile, targetMediaLibrary.LibraryID, found ? uploadedFile : null, + var source = new MediaFileInfoMapperSource(ksMediaFile, targetMediaLibrary.LibraryID, found ? uploadedFile : null, librarySubfolder, toolkitConfiguration.MigrateOnlyMediaFileInfo.GetValueOrDefault(false)); var mapped = mediaFileInfoMapper.Map(source, kxoMediaFile); protocol.MappedTarget(mapped); @@ -217,10 +189,10 @@ private async Task RequireMigratedMediaFiles( mediaFileFacade.SetMediaFile(mf, newInstance); await _kxpContext.SaveChangesAsync(cancellationToken); - protocol.Success(k11MediaFile, mf, mapped); + protocol.Success(ksMediaFile, mf, mapped); logger.LogEntitySetAction(newInstance, mf); } - catch (Exception ex) // TODO tk: 2022-05-18 handle exceptions + catch (Exception ex) { await kxoDbContext.DisposeAsync(); // reset context errors kxoDbContext = await kxpContextFactory.CreateDbContextAsync(cancellationToken); @@ -236,7 +208,7 @@ private async Task RequireMigratedMediaFiles( primaryKeyMappingContext.SetMapping( r => r.FileId, - k11MediaFile.FileId, + ksMediaFile.FileID, mf.FileID ); } diff --git a/KVA/Migration.Toolkit.Source/Helpers/AdminUserHelper.cs b/KVA/Migration.Toolkit.Source/Helpers/AdminUserHelper.cs new file mode 100644 index 00000000..71f8b054 --- /dev/null +++ b/KVA/Migration.Toolkit.Source/Helpers/AdminUserHelper.cs @@ -0,0 +1,45 @@ +namespace Migration.Toolkit.Source.Helpers; + +using CMS.Base; +using Microsoft.Extensions.DependencyInjection; +using Migration.Toolkit.Common; +using Migration.Toolkit.KXP.Api.Auxiliary; +using Migration.Toolkit.Source.Model; + +public class AdminUserHelper +{ + /// + /// maps source user id to target admin user + /// + /// source user id + /// in case user was migrated to member, replacement admin user shall be returned + /// called when no admin user exists in target instance, but is expected to exist + /// Target admin user ID + public static int? MapTargetAdminUser(int? sourceUserId, int memberFallbackTargetUserId, Action? onAdminNotFound = null) + { + if (sourceUserId is null) return null; + + var modelFacade = KsCoreDiExtensions.ServiceProvider.GetRequiredService(); + if (modelFacade.SelectById(sourceUserId) is { } modifiedByUser) + { + if (UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(modifiedByUser.UserPrivilegeLevel)) + { + var primaryKeyMappingContext = KsCoreDiExtensions.ServiceProvider.GetRequiredService(); + switch (primaryKeyMappingContext.MapSourceId(u => u.UserID, sourceUserId)) + { + case { Success: true, MappedId: { } targetUserId }: + return targetUserId; + default: + { + onAdminNotFound?.Invoke(); + return null; + } + } + } + return CMSActionContext.CurrentUser.UserID; + } + + // user not found, setting fallback + return CMSActionContext.CurrentUser.UserID; + } +} \ No newline at end of file diff --git a/KVA/Migration.Toolkit.Source/KsCoreDiExtensions.cs b/KVA/Migration.Toolkit.Source/KsCoreDiExtensions.cs index a1ba04de..9297e44c 100644 --- a/KVA/Migration.Toolkit.Source/KsCoreDiExtensions.cs +++ b/KVA/Migration.Toolkit.Source/KsCoreDiExtensions.cs @@ -27,6 +27,12 @@ namespace Migration.Toolkit.Source; public static class KsCoreDiExtensions { + public static IServiceProvider ServiceProvider { get; private set; } = null!; + public static void InitServiceProvider(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + public static IServiceCollection UseKsToolkitCore(this IServiceCollection services) { var printService = new PrintService(); @@ -58,6 +64,7 @@ public static IServiceCollection UseKsToolkitCore(this IServiceCollection servic services.AddTransient(); services.AddScoped(); + services.AddScoped(s => s.GetRequiredService()); services.AddScoped(); // commands @@ -79,6 +86,10 @@ public static IServiceCollection UseKsToolkitCore(this IServiceCollection servic services.AddTransient, AlternativeFormMapper>(); services.AddTransient, MemberInfoMapper>(); services.AddTransient, PageTemplateConfigurationMapper>(); + services.AddTransient, MediaLibraryInfoMapper>(); + services.AddTransient, MediaFileInfoMapper>(); + + services.AddUniversalMigrationToolkit(); diff --git a/Migration.Toolkit.Core.K11/Mappers/MediaFileInfoMapper.cs b/KVA/Migration.Toolkit.Source/Mappers/MediaFileInfoMapper.cs similarity index 60% rename from Migration.Toolkit.Core.K11/Mappers/MediaFileInfoMapper.cs rename to KVA/Migration.Toolkit.Source/Mappers/MediaFileInfoMapper.cs index ef7bcfd0..2b3414a6 100644 --- a/Migration.Toolkit.Core.K11/Mappers/MediaFileInfoMapper.cs +++ b/KVA/Migration.Toolkit.Source/Mappers/MediaFileInfoMapper.cs @@ -1,32 +1,33 @@ -namespace Migration.Toolkit.Core.K11.Mappers; +namespace Migration.Toolkit.Source.Mappers; using System.Data; using CMS.Base; using CMS.MediaLibrary; +using CMS.Membership; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; using Migration.Toolkit.Common; using Migration.Toolkit.Common.Abstractions; using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.K11.Contexts; -using Migration.Toolkit.Core.K11.Helpers; -using Migration.Toolkit.K11.Models; using Migration.Toolkit.KXP.Api; +using Migration.Toolkit.KXP.Api.Auxiliary; +using Migration.Toolkit.Source.Contexts; +using Migration.Toolkit.Source.Helpers; +using Migration.Toolkit.Source.Model; -public record MediaFileInfoMapperSource(MediaFile MediaFile, int TargetLibraryId, IUploadedFile? File, string? LibrarySubFolder, +public record MediaFileInfoMapperSource(IMediaFile MediaFile, int TargetLibraryId, IUploadedFile? File, string? LibrarySubFolder, bool MigrateOnlyMediaFileInfo); -public class MediaFileInfoMapper(ILogger logger, - PrimaryKeyMappingContext primaryKeyMappingContext, - KxpClassFacade classFacade, - IProtocol protocol, - ToolkitConfiguration toolkitConfiguration, - KeyMappingContext keyMappingContext) +public class MediaFileInfoMapper( + ILogger logger, + PrimaryKeyMappingContext primaryKeyMappingContext, + KxpClassFacade classFacade, + IProtocol protocol, + ToolkitConfiguration toolkitConfiguration, + ModelFacade modelFacade +) : EntityMapperBase(logger, primaryKeyMappingContext, protocol) { - private readonly IProtocol _protocol = protocol; - - protected override MediaFileInfo? CreateNewInstance(MediaFileInfoMapperSource source, MappingHelper mappingHelper, AddFailure addFailure) { if (source.File != null) { @@ -50,7 +51,7 @@ protected override MediaFileInfo MapInternal(MediaFileInfoMapperSource args, Med target.FileSize = mediaFile.FileSize; target.FileImageWidth = mediaFile.FileImageWidth ?? 0; target.FileImageHeight = mediaFile.FileImageHeight ?? 0; - target.FileGUID = mediaFile.FileGuid; + target.FileGUID = mediaFile.FileGUID; target.FileCreatedWhen = mediaFile.FileCreatedWhen; target.FileModifiedWhen = mediaFile.FileModifiedWhen; KenticoHelper.CopyCustomData(target.FileCustomData, mediaFile.FileCustomData); @@ -59,39 +60,27 @@ protected override MediaFileInfo MapInternal(MediaFileInfoMapperSource args, Med target.FileLibraryID = targetLibraryId; - var targetCreatedMemberId = keyMappingContext.MapSourceKey( - s => s.UserId, - s => s.UserGuid, - mediaFile.FileCreatedByUserId, - t => t.MemberId, - t => t.MemberGuid + var createdByUserId = AdminUserHelper.MapTargetAdminUser( + mediaFile.FileCreatedByUserID, + CMSActionContext.CurrentUser.UserID, + () => addFailure(HandbookReferences + .MissingRequiredDependency(nameof(mediaFile.FileCreatedByUserID), mediaFile.FileCreatedByUserID) + .NeedsManualAction() + .AsFailure() + ) ); - if (targetCreatedMemberId.Success) - { - // user was migrated to MEMBER => setting user would break foreign key - target.SetValue(nameof(target.FileCreatedByUserID), CMSActionContext.CurrentUser.UserID); - } - else if (mappingHelper.TranslateIdAllowNulls(c => c.UserId, mediaFile.FileCreatedByUserId, out var createdByUserId)) - { - target.SetValue(nameof(target.FileCreatedByUserID), createdByUserId); - } - - var targetModifiedMemberId = keyMappingContext.MapSourceKey( - s => s.UserId, - s => s.UserGuid, - mediaFile.FileModifiedByUserId, - t => t.MemberId, - t => t.MemberGuid + target.SetValue(nameof(target.FileCreatedByUserID), createdByUserId); + + var modifiedByUserId = AdminUserHelper.MapTargetAdminUser( + mediaFile.FileModifiedByUserID, + CMSActionContext.CurrentUser.UserID, + () => addFailure(HandbookReferences + .MissingRequiredDependency(nameof(mediaFile.FileModifiedByUserID), mediaFile.FileModifiedByUserID) + .NeedsManualAction() + .AsFailure() + ) ); - if (targetModifiedMemberId.Success) - { - // user was migrated to MEMBER => setting user would break foreign key - target.SetValue(nameof(target.FileModifiedByUserID), CMSActionContext.CurrentUser.UserID); - } - else if (mappingHelper.TranslateIdAllowNulls(c => c.UserId, mediaFile.FileModifiedByUserId, out var modifiedByUserId)) - { - target.SetValue(nameof(target.FileModifiedByUserID), modifiedByUserId); - } + target.SetValue(nameof(target.FileModifiedByUserID), modifiedByUserId); if (string.IsNullOrWhiteSpace(target.FilePath)) { @@ -101,13 +90,13 @@ protected override MediaFileInfo MapInternal(MediaFileInfoMapperSource args, Med if (file == null && !migrateOnlyMediaFileInfo) { addFailure(HandbookReferences.MediaFileIsMissingOnSourceFilesystem - .WithId(nameof(mediaFile.FileId), mediaFile.FileId) + .WithId(nameof(mediaFile.FileID), mediaFile.FileID) .WithData(new { mediaFile.FilePath, - mediaFile.FileGuid, - mediaFile.FileLibraryId, - mediaFile.FileSiteId + mediaFile.FileGUID, + mediaFile.FileLibraryID, + mediaFile.FileSiteID }) .AsFailure() ); @@ -116,7 +105,7 @@ protected override MediaFileInfo MapInternal(MediaFileInfoMapperSource args, Med return target; } - private void MigrateCustomizedFields(MediaFileInfo target, MediaFile mediaFile) + private void MigrateCustomizedFields(MediaFileInfo target, IMediaFile sourceMediaFile) { var customizedFields = classFacade.GetCustomizedFieldInfos(MediaFileInfo.TYPEINFO.ObjectClassName).ToList(); if (customizedFields.Count <= 0) return; @@ -132,7 +121,7 @@ private void MigrateCustomizedFields(MediaFileInfo target, MediaFile mediaFile) cmd.CommandText = query; cmd.CommandType = CommandType.Text; cmd.CommandTimeout = 3; - cmd.Parameters.AddWithValue("id", mediaFile.FileId); + cmd.Parameters.AddWithValue("id", sourceMediaFile.FileID); conn.Open(); diff --git a/KVA/Migration.Toolkit.Source/Mappers/MediaLibraryInfoMapper.cs b/KVA/Migration.Toolkit.Source/Mappers/MediaLibraryInfoMapper.cs new file mode 100644 index 00000000..dafbc98f --- /dev/null +++ b/KVA/Migration.Toolkit.Source/Mappers/MediaLibraryInfoMapper.cs @@ -0,0 +1,40 @@ +namespace Migration.Toolkit.Source.Mappers; + +using CMS.MediaLibrary; +using Microsoft.Extensions.Logging; +using Migration.Toolkit.Common.Abstractions; +using Migration.Toolkit.Common.MigrationProtocol; +using Migration.Toolkit.Source.Contexts; +using Migration.Toolkit.Source.Model; + +public record MediaLibraryInfoMapperSource(IMediaLibrary MediaLibrary, ICmsSite Site); + +public class MediaLibraryInfoMapper(ILogger logger, PrimaryKeyMappingContext primaryKeyMappingContext, IProtocol protocol) + : EntityMapperBase(logger, primaryKeyMappingContext, protocol) +{ + protected override MediaLibraryInfo? CreateNewInstance(MediaLibraryInfoMapperSource source, MappingHelper mappingHelper, AddFailure addFailure) => + MediaLibraryInfo.New(); + + protected override MediaLibraryInfo MapInternal(MediaLibraryInfoMapperSource s, MediaLibraryInfo target, bool newInstance, MappingHelper mappingHelper, AddFailure addFailure) + { + var (ksLibrary, ksSite) = s; + + // Sets the library properties + target.LibraryDisplayName = ksLibrary.LibraryDisplayName; + target.LibraryName = ksLibrary.LibraryName; + target.LibraryDescription = ksLibrary.LibraryDescription; + target.LibraryFolder = ksLibrary.LibraryFolder; + target.LibraryGUID = mappingHelper.Require(ksLibrary.LibraryGUID, nameof(ksLibrary.LibraryGUID)); + target.LibraryDisplayName = ksLibrary.LibraryDisplayName; + target.LibraryDescription = ksLibrary.LibraryDescription; + + if (!target.LibraryFolder.StartsWith($"{ksSite.SiteName}_", StringComparison.InvariantCultureIgnoreCase)) + { + target.LibraryFolder = $"{ksSite.SiteName}_{ksLibrary.LibraryFolder}"; + } + + target.LibraryLastModified = mappingHelper.Require(ksLibrary.LibraryLastModified, nameof(ksLibrary.LibraryLastModified)); + + return target; + } +} \ No newline at end of file diff --git a/KVA/Migration.Toolkit.Source/Model/CmsUser.cs b/KVA/Migration.Toolkit.Source/Model/CmsUser.cs index 7e222335..2d79d24e 100644 --- a/KVA/Migration.Toolkit.Source/Model/CmsUser.cs +++ b/KVA/Migration.Toolkit.Source/Model/CmsUser.cs @@ -32,7 +32,7 @@ public interface ICmsUser: ISourceModel int UserPrivilegeLevel { get; } string? UserSecurityStamp { get; } byte[]? UserMFSecret { get; } - long? UserMFTimestep { get; } + long? UserMFTimestep { get; } static string ISourceModel.GetPrimaryKeyName(SemanticVersion version) { @@ -70,57 +70,57 @@ static ICmsUser ISourceModel.FromReader(IDataReader reader, SemanticVe public partial record CmsUserK11(int UserID, string UserName, string? FirstName, string? MiddleName, string? LastName, string? FullName, string? Email, string UserPassword, string? PreferredCultureCode, string? PreferredUICultureCode, bool UserEnabled, bool? UserIsExternal, string? UserPasswordFormat, DateTime? UserCreated, DateTime? LastLogon, string? UserStartingAliasPath, Guid UserGUID, DateTime UserLastModified, string? UserLastLogonInfo, bool? UserIsHidden, string? UserVisibility, bool? UserIsDomain, bool? UserHasAllowedCultures, bool? UserMFRequired, int UserPrivilegeLevel, string? UserSecurityStamp, byte[]? UserMFSecret, long? UserMFTimestep): ICmsUser, ISourceModel { public static bool IsAvailable(SemanticVersion version) => true; - public static string GetPrimaryKeyName(SemanticVersion version) => "UserID"; + public static string GetPrimaryKeyName(SemanticVersion version) => "UserID"; public static string TableName => "CMS_User"; public static string GuidColumnName => "UserGUID"; static CmsUserK11 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) { return new CmsUserK11( - reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") + reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") ); } public static CmsUserK11 FromReader(IDataReader reader, SemanticVersion version) { return new CmsUserK11( - reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") + reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") ); } }; public partial record CmsUserK12(int UserID, string UserName, string? FirstName, string? MiddleName, string? LastName, string? FullName, string? Email, string UserPassword, string? PreferredCultureCode, string? PreferredUICultureCode, bool UserEnabled, bool? UserIsExternal, string? UserPasswordFormat, DateTime? UserCreated, DateTime? LastLogon, string? UserStartingAliasPath, Guid UserGUID, DateTime UserLastModified, string? UserLastLogonInfo, bool? UserIsHidden, string? UserVisibility, bool? UserIsDomain, bool? UserHasAllowedCultures, bool? UserMFRequired, int UserPrivilegeLevel, string? UserSecurityStamp, byte[]? UserMFSecret, long? UserMFTimestep): ICmsUser, ISourceModel { public static bool IsAvailable(SemanticVersion version) => true; - public static string GetPrimaryKeyName(SemanticVersion version) => "UserID"; + public static string GetPrimaryKeyName(SemanticVersion version) => "UserID"; public static string TableName => "CMS_User"; public static string GuidColumnName => "UserGUID"; static CmsUserK12 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) { return new CmsUserK12( - reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") + reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") ); } public static CmsUserK12 FromReader(IDataReader reader, SemanticVersion version) { return new CmsUserK12( - reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") + reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserVisibility"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") ); } }; -public partial record CmsUserK13(int UserID, string UserName, string? FirstName, string? MiddleName, string? LastName, string? FullName, string? Email, string UserPassword, string? PreferredCultureCode, string? PreferredUICultureCode, bool UserEnabled, bool? UserIsExternal, string? UserPasswordFormat, DateTime? UserCreated, DateTime? LastLogon, string? UserStartingAliasPath, Guid UserGUID, DateTime UserLastModified, string? UserLastLogonInfo, bool? UserIsHidden, bool? UserIsDomain, bool? UserHasAllowedCultures, bool? UserMFRequired, int UserPrivilegeLevel, string? UserSecurityStamp, byte[]? UserMFSecret, long? UserMFTimestep, string? CustomizedField1): ICmsUser, ISourceModel +public partial record CmsUserK13(int UserID, string UserName, string? FirstName, string? MiddleName, string? LastName, string? FullName, string? Email, string UserPassword, string? PreferredCultureCode, string? PreferredUICultureCode, bool UserEnabled, bool? UserIsExternal, string? UserPasswordFormat, DateTime? UserCreated, DateTime? LastLogon, string? UserStartingAliasPath, Guid UserGUID, DateTime UserLastModified, string? UserLastLogonInfo, bool? UserIsHidden, bool? UserIsDomain, bool? UserHasAllowedCultures, bool? UserMFRequired, int UserPrivilegeLevel, string? UserSecurityStamp, byte[]? UserMFSecret, long? UserMFTimestep): ICmsUser, ISourceModel { public static bool IsAvailable(SemanticVersion version) => true; - public static string GetPrimaryKeyName(SemanticVersion version) => "UserID"; + public static string GetPrimaryKeyName(SemanticVersion version) => "UserID"; public static string TableName => "CMS_User"; public static string GuidColumnName => "UserGUID"; static CmsUserK13 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) { return new CmsUserK13( - reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep"), reader.Unbox("CustomizedField1") + reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") ); } public static CmsUserK13 FromReader(IDataReader reader, SemanticVersion version) { return new CmsUserK13( - reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep"), reader.Unbox("CustomizedField1") + reader.Unbox("UserID"), reader.Unbox("UserName"), reader.Unbox("FirstName"), reader.Unbox("MiddleName"), reader.Unbox("LastName"), reader.Unbox("FullName"), reader.Unbox("Email"), reader.Unbox("UserPassword"), reader.Unbox("PreferredCultureCode"), reader.Unbox("PreferredUICultureCode"), reader.Unbox("UserEnabled"), reader.Unbox("UserIsExternal"), reader.Unbox("UserPasswordFormat"), reader.Unbox("UserCreated"), reader.Unbox("LastLogon"), reader.Unbox("UserStartingAliasPath"), reader.Unbox("UserGUID"), reader.Unbox("UserLastModified"), reader.Unbox("UserLastLogonInfo"), reader.Unbox("UserIsHidden"), reader.Unbox("UserIsDomain"), reader.Unbox("UserHasAllowedCultures"), reader.Unbox("UserMFRequired"), reader.Unbox("UserPrivilegeLevel"), reader.Unbox("UserSecurityStamp"), reader.Unbox("UserMFSecret"), reader.Unbox("UserMFTimestep") ); } }; diff --git a/KVA/Migration.Toolkit.Source/Model/MediaFile.cs b/KVA/Migration.Toolkit.Source/Model/MediaFile.cs new file mode 100644 index 00000000..949311d6 --- /dev/null +++ b/KVA/Migration.Toolkit.Source/Model/MediaFile.cs @@ -0,0 +1,118 @@ +namespace Migration.Toolkit.Source.Model; +// ReSharper disable InconsistentNaming + +using System.Data; +using Migration.Toolkit.Common; + +public interface IMediaFile: ISourceModel +{ + int FileID { get; } + string FileName { get; } + string FileTitle { get; } + string FileDescription { get; } + string FileExtension { get; } + string FileMimeType { get; } + string FilePath { get; } + long FileSize { get; } + int? FileImageWidth { get; } + int? FileImageHeight { get; } + Guid FileGUID { get; } + int FileLibraryID { get; } + int FileSiteID { get; } + int? FileCreatedByUserID { get; } + DateTime FileCreatedWhen { get; } + int? FileModifiedByUserID { get; } + DateTime FileModifiedWhen { get; } + string? FileCustomData { get; } + + static string ISourceModel.GetPrimaryKeyName(SemanticVersion version) + { + return version switch + { + { Major: 11 } => MediaFileK11.GetPrimaryKeyName(version), + { Major: 12 } => MediaFileK12.GetPrimaryKeyName(version), + { Major: 13 } => MediaFileK13.GetPrimaryKeyName(version), + _ => throw new InvalidCastException($"Invalid version {version}") + }; + } + static bool ISourceModel.IsAvailable(SemanticVersion version) + { + return version switch + { + { Major: 11 } => MediaFileK11.IsAvailable(version), + { Major: 12 } => MediaFileK12.IsAvailable(version), + { Major: 13 } => MediaFileK13.IsAvailable(version), + _ => throw new InvalidCastException($"Invalid version {version}") + }; + } + static string ISourceModel.TableName => "Media_File"; + static string ISourceModel.GuidColumnName => "FileGUID"; //assumtion, class Guid column doesn't change between versions + static IMediaFile ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return version switch + { + { Major: 11 } => MediaFileK11.FromReader(reader, version), + { Major: 12 } => MediaFileK12.FromReader(reader, version), + { Major: 13 } => MediaFileK13.FromReader(reader, version), + _ => throw new InvalidCastException($"Invalid version {version}") + }; + } +} +public partial record MediaFileK11(int FileID, string FileName, string FileTitle, string FileDescription, string FileExtension, string FileMimeType, string FilePath, long FileSize, int? FileImageWidth, int? FileImageHeight, Guid FileGUID, int FileLibraryID, int FileSiteID, int? FileCreatedByUserID, DateTime FileCreatedWhen, int? FileModifiedByUserID, DateTime FileModifiedWhen, string? FileCustomData): IMediaFile, ISourceModel +{ + public static bool IsAvailable(SemanticVersion version) => true; + public static string GetPrimaryKeyName(SemanticVersion version) => "FileID"; + public static string TableName => "Media_File"; + public static string GuidColumnName => "FileGUID"; + static MediaFileK11 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaFileK11( + reader.Unbox("FileID"), reader.Unbox("FileName"), reader.Unbox("FileTitle"), reader.Unbox("FileDescription"), reader.Unbox("FileExtension"), reader.Unbox("FileMimeType"), reader.Unbox("FilePath"), reader.Unbox("FileSize"), reader.Unbox("FileImageWidth"), reader.Unbox("FileImageHeight"), reader.Unbox("FileGUID"), reader.Unbox("FileLibraryID"), reader.Unbox("FileSiteID"), reader.Unbox("FileCreatedByUserID"), reader.Unbox("FileCreatedWhen"), reader.Unbox("FileModifiedByUserID"), reader.Unbox("FileModifiedWhen"), reader.Unbox("FileCustomData") + ); + } + public static MediaFileK11 FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaFileK11( + reader.Unbox("FileID"), reader.Unbox("FileName"), reader.Unbox("FileTitle"), reader.Unbox("FileDescription"), reader.Unbox("FileExtension"), reader.Unbox("FileMimeType"), reader.Unbox("FilePath"), reader.Unbox("FileSize"), reader.Unbox("FileImageWidth"), reader.Unbox("FileImageHeight"), reader.Unbox("FileGUID"), reader.Unbox("FileLibraryID"), reader.Unbox("FileSiteID"), reader.Unbox("FileCreatedByUserID"), reader.Unbox("FileCreatedWhen"), reader.Unbox("FileModifiedByUserID"), reader.Unbox("FileModifiedWhen"), reader.Unbox("FileCustomData") + ); + } +}; +public partial record MediaFileK12(int FileID, string FileName, string FileTitle, string FileDescription, string FileExtension, string FileMimeType, string FilePath, long FileSize, int? FileImageWidth, int? FileImageHeight, Guid FileGUID, int FileLibraryID, int FileSiteID, int? FileCreatedByUserID, DateTime FileCreatedWhen, int? FileModifiedByUserID, DateTime FileModifiedWhen, string? FileCustomData): IMediaFile, ISourceModel +{ + public static bool IsAvailable(SemanticVersion version) => true; + public static string GetPrimaryKeyName(SemanticVersion version) => "FileID"; + public static string TableName => "Media_File"; + public static string GuidColumnName => "FileGUID"; + static MediaFileK12 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaFileK12( + reader.Unbox("FileID"), reader.Unbox("FileName"), reader.Unbox("FileTitle"), reader.Unbox("FileDescription"), reader.Unbox("FileExtension"), reader.Unbox("FileMimeType"), reader.Unbox("FilePath"), reader.Unbox("FileSize"), reader.Unbox("FileImageWidth"), reader.Unbox("FileImageHeight"), reader.Unbox("FileGUID"), reader.Unbox("FileLibraryID"), reader.Unbox("FileSiteID"), reader.Unbox("FileCreatedByUserID"), reader.Unbox("FileCreatedWhen"), reader.Unbox("FileModifiedByUserID"), reader.Unbox("FileModifiedWhen"), reader.Unbox("FileCustomData") + ); + } + public static MediaFileK12 FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaFileK12( + reader.Unbox("FileID"), reader.Unbox("FileName"), reader.Unbox("FileTitle"), reader.Unbox("FileDescription"), reader.Unbox("FileExtension"), reader.Unbox("FileMimeType"), reader.Unbox("FilePath"), reader.Unbox("FileSize"), reader.Unbox("FileImageWidth"), reader.Unbox("FileImageHeight"), reader.Unbox("FileGUID"), reader.Unbox("FileLibraryID"), reader.Unbox("FileSiteID"), reader.Unbox("FileCreatedByUserID"), reader.Unbox("FileCreatedWhen"), reader.Unbox("FileModifiedByUserID"), reader.Unbox("FileModifiedWhen"), reader.Unbox("FileCustomData") + ); + } +}; +public partial record MediaFileK13(int FileID, string FileName, string FileTitle, string FileDescription, string FileExtension, string FileMimeType, string FilePath, long FileSize, int? FileImageWidth, int? FileImageHeight, Guid FileGUID, int FileLibraryID, int FileSiteID, int? FileCreatedByUserID, DateTime FileCreatedWhen, int? FileModifiedByUserID, DateTime FileModifiedWhen, string? FileCustomData): IMediaFile, ISourceModel +{ + public static bool IsAvailable(SemanticVersion version) => true; + public static string GetPrimaryKeyName(SemanticVersion version) => "FileID"; + public static string TableName => "Media_File"; + public static string GuidColumnName => "FileGUID"; + static MediaFileK13 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaFileK13( + reader.Unbox("FileID"), reader.Unbox("FileName"), reader.Unbox("FileTitle"), reader.Unbox("FileDescription"), reader.Unbox("FileExtension"), reader.Unbox("FileMimeType"), reader.Unbox("FilePath"), reader.Unbox("FileSize"), reader.Unbox("FileImageWidth"), reader.Unbox("FileImageHeight"), reader.Unbox("FileGUID"), reader.Unbox("FileLibraryID"), reader.Unbox("FileSiteID"), reader.Unbox("FileCreatedByUserID"), reader.Unbox("FileCreatedWhen"), reader.Unbox("FileModifiedByUserID"), reader.Unbox("FileModifiedWhen"), reader.Unbox("FileCustomData") + ); + } + public static MediaFileK13 FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaFileK13( + reader.Unbox("FileID"), reader.Unbox("FileName"), reader.Unbox("FileTitle"), reader.Unbox("FileDescription"), reader.Unbox("FileExtension"), reader.Unbox("FileMimeType"), reader.Unbox("FilePath"), reader.Unbox("FileSize"), reader.Unbox("FileImageWidth"), reader.Unbox("FileImageHeight"), reader.Unbox("FileGUID"), reader.Unbox("FileLibraryID"), reader.Unbox("FileSiteID"), reader.Unbox("FileCreatedByUserID"), reader.Unbox("FileCreatedWhen"), reader.Unbox("FileModifiedByUserID"), reader.Unbox("FileModifiedWhen"), reader.Unbox("FileCustomData") + ); + } +}; + diff --git a/KVA/Migration.Toolkit.Source/Model/MediaLibrary.cs b/KVA/Migration.Toolkit.Source/Model/MediaLibrary.cs new file mode 100644 index 00000000..5f1a56ca --- /dev/null +++ b/KVA/Migration.Toolkit.Source/Model/MediaLibrary.cs @@ -0,0 +1,111 @@ +namespace Migration.Toolkit.Source.Model; +// ReSharper disable InconsistentNaming + +using System.Data; +using Migration.Toolkit.Common; + +public interface IMediaLibrary: ISourceModel +{ + int LibraryID { get; } + string LibraryName { get; } + string LibraryDisplayName { get; } + string? LibraryDescription { get; } + string LibraryFolder { get; } + int? LibraryAccess { get; } + int LibrarySiteID { get; } + Guid? LibraryGUID { get; } + DateTime? LibraryLastModified { get; } + string? LibraryTeaserPath { get; } + Guid? LibraryTeaserGUID { get; } + + static string ISourceModel.GetPrimaryKeyName(SemanticVersion version) + { + return version switch + { + { Major: 11 } => MediaLibraryK11.GetPrimaryKeyName(version), + { Major: 12 } => MediaLibraryK12.GetPrimaryKeyName(version), + { Major: 13 } => MediaLibraryK13.GetPrimaryKeyName(version), + _ => throw new InvalidCastException($"Invalid version {version}") + }; + } + static bool ISourceModel.IsAvailable(SemanticVersion version) + { + return version switch + { + { Major: 11 } => MediaLibraryK11.IsAvailable(version), + { Major: 12 } => MediaLibraryK12.IsAvailable(version), + { Major: 13 } => MediaLibraryK13.IsAvailable(version), + _ => throw new InvalidCastException($"Invalid version {version}") + }; + } + static string ISourceModel.TableName => "Media_Library"; + static string ISourceModel.GuidColumnName => "LibraryGUID"; //assumtion, class Guid column doesn't change between versions + static IMediaLibrary ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return version switch + { + { Major: 11 } => MediaLibraryK11.FromReader(reader, version), + { Major: 12 } => MediaLibraryK12.FromReader(reader, version), + { Major: 13 } => MediaLibraryK13.FromReader(reader, version), + _ => throw new InvalidCastException($"Invalid version {version}") + }; + } +} +public partial record MediaLibraryK11(int LibraryID, string LibraryName, string LibraryDisplayName, string? LibraryDescription, string LibraryFolder, int? LibraryAccess, int? LibraryGroupID, int LibrarySiteID, Guid? LibraryGUID, DateTime? LibraryLastModified, string? LibraryTeaserPath, Guid? LibraryTeaserGUID): IMediaLibrary, ISourceModel +{ + public static bool IsAvailable(SemanticVersion version) => true; + public static string GetPrimaryKeyName(SemanticVersion version) => "LibraryID"; + public static string TableName => "Media_Library"; + public static string GuidColumnName => "LibraryTeaserGUID"; + static MediaLibraryK11 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaLibraryK11( + reader.Unbox("LibraryID"), reader.Unbox("LibraryName"), reader.Unbox("LibraryDisplayName"), reader.Unbox("LibraryDescription"), reader.Unbox("LibraryFolder"), reader.Unbox("LibraryAccess"), reader.Unbox("LibraryGroupID"), reader.Unbox("LibrarySiteID"), reader.Unbox("LibraryGUID"), reader.Unbox("LibraryLastModified"), reader.Unbox("LibraryTeaserPath"), reader.Unbox("LibraryTeaserGUID") + ); + } + public static MediaLibraryK11 FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaLibraryK11( + reader.Unbox("LibraryID"), reader.Unbox("LibraryName"), reader.Unbox("LibraryDisplayName"), reader.Unbox("LibraryDescription"), reader.Unbox("LibraryFolder"), reader.Unbox("LibraryAccess"), reader.Unbox("LibraryGroupID"), reader.Unbox("LibrarySiteID"), reader.Unbox("LibraryGUID"), reader.Unbox("LibraryLastModified"), reader.Unbox("LibraryTeaserPath"), reader.Unbox("LibraryTeaserGUID") + ); + } +}; +public partial record MediaLibraryK12(int LibraryID, string LibraryName, string LibraryDisplayName, string? LibraryDescription, string LibraryFolder, int? LibraryAccess, int? LibraryGroupID, int LibrarySiteID, Guid? LibraryGUID, DateTime? LibraryLastModified, string? LibraryTeaserPath, Guid? LibraryTeaserGUID): IMediaLibrary, ISourceModel +{ + public static bool IsAvailable(SemanticVersion version) => true; + public static string GetPrimaryKeyName(SemanticVersion version) => "LibraryID"; + public static string TableName => "Media_Library"; + public static string GuidColumnName => "LibraryTeaserGUID"; + static MediaLibraryK12 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaLibraryK12( + reader.Unbox("LibraryID"), reader.Unbox("LibraryName"), reader.Unbox("LibraryDisplayName"), reader.Unbox("LibraryDescription"), reader.Unbox("LibraryFolder"), reader.Unbox("LibraryAccess"), reader.Unbox("LibraryGroupID"), reader.Unbox("LibrarySiteID"), reader.Unbox("LibraryGUID"), reader.Unbox("LibraryLastModified"), reader.Unbox("LibraryTeaserPath"), reader.Unbox("LibraryTeaserGUID") + ); + } + public static MediaLibraryK12 FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaLibraryK12( + reader.Unbox("LibraryID"), reader.Unbox("LibraryName"), reader.Unbox("LibraryDisplayName"), reader.Unbox("LibraryDescription"), reader.Unbox("LibraryFolder"), reader.Unbox("LibraryAccess"), reader.Unbox("LibraryGroupID"), reader.Unbox("LibrarySiteID"), reader.Unbox("LibraryGUID"), reader.Unbox("LibraryLastModified"), reader.Unbox("LibraryTeaserPath"), reader.Unbox("LibraryTeaserGUID") + ); + } +}; +public partial record MediaLibraryK13(int LibraryID, string LibraryName, string LibraryDisplayName, string? LibraryDescription, string LibraryFolder, int? LibraryAccess, int LibrarySiteID, Guid? LibraryGUID, DateTime? LibraryLastModified, string? LibraryTeaserPath, Guid? LibraryTeaserGUID, bool? LibraryUseDirectPathForContent): IMediaLibrary, ISourceModel +{ + public static bool IsAvailable(SemanticVersion version) => true; + public static string GetPrimaryKeyName(SemanticVersion version) => "LibraryID"; + public static string TableName => "Media_Library"; + public static string GuidColumnName => "LibraryTeaserGUID"; + static MediaLibraryK13 ISourceModel.FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaLibraryK13( + reader.Unbox("LibraryID"), reader.Unbox("LibraryName"), reader.Unbox("LibraryDisplayName"), reader.Unbox("LibraryDescription"), reader.Unbox("LibraryFolder"), reader.Unbox("LibraryAccess"), reader.Unbox("LibrarySiteID"), reader.Unbox("LibraryGUID"), reader.Unbox("LibraryLastModified"), reader.Unbox("LibraryTeaserPath"), reader.Unbox("LibraryTeaserGUID"), reader.Unbox("LibraryUseDirectPathForContent") + ); + } + public static MediaLibraryK13 FromReader(IDataReader reader, SemanticVersion version) + { + return new MediaLibraryK13( + reader.Unbox("LibraryID"), reader.Unbox("LibraryName"), reader.Unbox("LibraryDisplayName"), reader.Unbox("LibraryDescription"), reader.Unbox("LibraryFolder"), reader.Unbox("LibraryAccess"), reader.Unbox("LibrarySiteID"), reader.Unbox("LibraryGUID"), reader.Unbox("LibraryLastModified"), reader.Unbox("LibraryTeaserPath"), reader.Unbox("LibraryTeaserGUID"), reader.Unbox("LibraryUseDirectPathForContent") + ); + } +}; + diff --git a/KVA/Migration.Toolkit.Source/ModelFacade.cs b/KVA/Migration.Toolkit.Source/ModelFacade.cs index df674485..23d1be13 100644 --- a/KVA/Migration.Toolkit.Source/ModelFacade.cs +++ b/KVA/Migration.Toolkit.Source/ModelFacade.cs @@ -24,13 +24,17 @@ public async IAsyncEnumerable SelectAllAsync([EnumeratorCancellation] Canc } } - public IEnumerable SelectAll() where T : ISourceModel + public IEnumerable SelectAll(string? orderBy = null) where T : ISourceModel { _version ??= SelectVersion(); using var conn = GetConnection(); conn.Open(); var cmd = conn.CreateCommand(); cmd.CommandText = $"SELECT * FROM {T.TableName}"; + if (!string.IsNullOrWhiteSpace(orderBy)) + { + cmd.CommandText += orderBy; + } using var reader = cmd.ExecuteReader(); while (reader.Read()) { diff --git a/KVA/Migration.Toolkit.Source/Services/PrimaryKeyLocatorService.cs b/KVA/Migration.Toolkit.Source/Services/PrimaryKeyLocatorService.cs index 58e09482..e7d8569a 100644 --- a/KVA/Migration.Toolkit.Source/Services/PrimaryKeyLocatorService.cs +++ b/KVA/Migration.Toolkit.Source/Services/PrimaryKeyLocatorService.cs @@ -4,7 +4,6 @@ namespace Migration.Toolkit.Source.Services; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Migration.Toolkit.Common; -using Migration.Toolkit.Common.Services; using Migration.Toolkit.KXP.Context; using Migration.Toolkit.Source.Model; @@ -14,16 +13,9 @@ public class PrimaryKeyLocatorService( ModelFacade modelFacade ) : IPrimaryKeyLocatorService { - private class KeyEqualityComparerWithLambda : IEqualityComparer + private class KeyEqualityComparerWithLambda(Func equalityComparer) : IEqualityComparer { - private readonly Func _equalityComparer; - - public KeyEqualityComparerWithLambda(Func equalityComparer) - { - _equalityComparer = equalityComparer; - } - - public bool Equals(T? x, T? y) => _equalityComparer.Invoke(x, y); + public bool Equals(T? x, T? y) => equalityComparer.Invoke(x, y); public int GetHashCode(T obj) => obj?.GetHashCode() ?? 0; } diff --git a/Migration.Toolkit.CLI/Program.cs b/Migration.Toolkit.CLI/Program.cs index 49b5fc72..20ea1eae 100644 --- a/Migration.Toolkit.CLI/Program.cs +++ b/Migration.Toolkit.CLI/Program.cs @@ -158,6 +158,7 @@ services.UseToolkitCommon(); await using var serviceProvider = services.BuildServiceProvider(); +KsCoreDiExtensions.InitServiceProvider(serviceProvider); using var scope = serviceProvider.CreateScope(); var loader = scope.ServiceProvider.GetRequiredService(); diff --git a/Migration.Toolkit.Common/Abstractions/EntityMapperBase.cs b/Migration.Toolkit.Common/Abstractions/EntityMapperBase.cs index f3f94a93..d8fad3dc 100644 --- a/Migration.Toolkit.Common/Abstractions/EntityMapperBase.cs +++ b/Migration.Toolkit.Common/Abstractions/EntityMapperBase.cs @@ -53,17 +53,8 @@ public virtual IModelMappingResult Map(TSourceEntity? source, TTa protected delegate void AddFailure(MapperResultFailure failure); - protected class MappingHelper + protected class MappingHelper(IPrimaryKeyMappingContext primaryKeyMappingContext, Action> addFailure) { - private readonly IPrimaryKeyMappingContext _primaryKeyMappingContext; - private readonly Action> _addFailure; - - public MappingHelper(IPrimaryKeyMappingContext primaryKeyMappingContext, Action> addFailure) - { - _primaryKeyMappingContext = primaryKeyMappingContext; - _addFailure = addFailure; - } - public Guid Require(Guid? value, string valueName) { if (value is { } v && v != Guid.Empty) @@ -76,7 +67,7 @@ public Guid Require(Guid? value, string valueName) .AsFailure() ; - _addFailure(failure); + addFailure(failure); return Guid.Empty; } @@ -92,7 +83,7 @@ public int Require(int? value, string valueName) .AsFailure() ; - _addFailure(failure); + addFailure(failure); return -1; } @@ -108,7 +99,7 @@ public bool Require(bool? value, string valueName) .AsFailure() ; - _addFailure(failure); + addFailure(failure); return false; } @@ -124,7 +115,7 @@ public DateTime Require(DateTime? value, string valueName) .AsFailure() ; - _addFailure(failure); + addFailure(failure); return DateTime.MinValue; } @@ -136,7 +127,7 @@ public bool TranslateIdAllowNulls(Expression> return true; } - translatedId = _primaryKeyMappingContext.MapFromSourceOrNull(keyNameSelector, sourceId); + translatedId = primaryKeyMappingContext.MapFromSourceOrNull(keyNameSelector, sourceId); if (!translatedId.HasValue) { var memberName = keyNameSelector.GetMemberName(); @@ -146,7 +137,7 @@ public bool TranslateIdAllowNulls(Expression> .AsFailure() ; - _addFailure(failure); + addFailure(failure); return false; } @@ -155,7 +146,7 @@ public bool TranslateIdAllowNulls(Expression> public bool TryTranslateId(Expression> keyNameSelector, int? sourceId, out int? translatedId) { - translatedId = _primaryKeyMappingContext.MapFromSourceOrNull(keyNameSelector, sourceId); + translatedId = primaryKeyMappingContext.MapFromSourceOrNull(keyNameSelector, sourceId); if (sourceId.HasValue && !translatedId.HasValue) { return false; @@ -166,7 +157,7 @@ public bool TryTranslateId(Expression> keyNam public bool TranslateRequiredId(Expression> keyNameSelector, int? sourceId, out int translatedId) { - if (_primaryKeyMappingContext.TryRequireMapFromSource(keyNameSelector, sourceId, out translatedId)) + if (primaryKeyMappingContext.TryRequireMapFromSource(keyNameSelector, sourceId, out translatedId)) { return true; } @@ -177,7 +168,7 @@ public bool TranslateRequiredId(Expression> k .NeedsManualAction() .AsFailure() ; - _addFailure(failure); + addFailure(failure); return false; } } diff --git a/Migration.Toolkit.Core.K11/Handlers/MigrateMembersCommandHandler.cs b/Migration.Toolkit.Core.K11/Handlers/MigrateMembersCommandHandler.cs index c6289ce1..7cf71052 100644 --- a/Migration.Toolkit.Core.K11/Handlers/MigrateMembersCommandHandler.cs +++ b/Migration.Toolkit.Core.K11/Handlers/MigrateMembersCommandHandler.cs @@ -13,6 +13,7 @@ using Migration.Toolkit.Core.K11.Mappers; using Migration.Toolkit.K11; using Migration.Toolkit.K11.Models; +using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Api.Enums; public class MigrateMembersCommandHandler(ILogger logger, @@ -24,15 +25,13 @@ public class MigrateMembersCommandHandler(ILogger { private const string USER_PUBLIC = "public"; - private static int[] MigratedAdminUserPrivilegeLevels => [(int)UserPrivilegeLevelEnum.None]; - public async Task Handle(MigrateMembersCommand request, CancellationToken cancellationToken) { await using var k11Context = await k11ContextFactory.CreateDbContextAsync(cancellationToken); var k11CmsUsers = k11Context.CmsUsers .Include(u => u.CmsUserSettingUserSettingsUserNavigation) - .Where(u => MigratedAdminUserPrivilegeLevels.Contains(u.UserPrivilegeLevel)) + .Where(u => UserHelper.PrivilegeLevelsMigratedAsMemberUser.Contains(u.UserPrivilegeLevel)) ; foreach (var k11User in k11CmsUsers) diff --git a/Migration.Toolkit.Core.K11/Handlers/MigrateUsersCommandHandler.cs b/Migration.Toolkit.Core.K11/Handlers/MigrateUsersCommandHandler.cs index 2a59a8bf..2279cc20 100644 --- a/Migration.Toolkit.Core.K11/Handlers/MigrateUsersCommandHandler.cs +++ b/Migration.Toolkit.Core.K11/Handlers/MigrateUsersCommandHandler.cs @@ -11,6 +11,7 @@ using Migration.Toolkit.Core.K11.Contexts; using Migration.Toolkit.K11; using Migration.Toolkit.K11.Models; +using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Api.Enums; public class MigrateUsersCommandHandler(ILogger logger, @@ -24,14 +25,12 @@ public class MigrateUsersCommandHandler(ILogger logg { private const string USER_PUBLIC = "public"; - private static int[] MigratedAdminUserPrivilegeLevels => new[] { (int)UserPrivilegeLevelEnum.Editor, (int)UserPrivilegeLevelEnum.Admin, (int)UserPrivilegeLevelEnum.GlobalAdmin }; - public async Task Handle(MigrateUsersCommand request, CancellationToken cancellationToken) { await using var k11Context = await k11ContextFactory.CreateDbContextAsync(cancellationToken); var k11CmsUsers = k11Context.CmsUsers - .Where(u => MigratedAdminUserPrivilegeLevels.Contains(u.UserPrivilegeLevel)) + .Where(u => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(u.UserPrivilegeLevel)) ; foreach (var k11User in k11CmsUsers) @@ -66,7 +65,7 @@ public async Task Handle(MigrateUsersCommand request, Cancellatio var mapped = userInfoMapper.Map(k11User, xbkUserInfo); protocol.MappedTarget(mapped); - await SaveUserUsingKenticoApi(cancellationToken, mapped, k11User); + SaveUserUsingKenticoApi(mapped, k11User); } await MigrateUserCmsRoles(k11Context, cancellationToken); @@ -74,7 +73,7 @@ public async Task Handle(MigrateUsersCommand request, Cancellatio return new GenericCommandResult(); } - private async Task SaveUserUsingKenticoApi(CancellationToken cancellationToken, IModelMappingResult mapped, CmsUser k11User) + private bool SaveUserUsingKenticoApi(IModelMappingResult mapped, CmsUser k11User) { if (mapped is { Success : true } result) { @@ -120,7 +119,7 @@ private async Task MigrateUserCmsRoles(K11Context k11Context, CancellationToken { var groupedRoles = k11Context.CmsRoles .Where(r => - r.CmsUserRoles.Any(ur => MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel)) + r.CmsUserRoles.Any(ur => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel)) ) .GroupBy(x => x.RoleName) .AsNoTracking(); @@ -150,7 +149,7 @@ Roles with RoleGuid ({RoleGuids}) have same RoleName '{RoleName}', due to remova var k11CmsRoles = k11Context.CmsRoles .Where(r => - r.CmsUserRoles.Any(ur => MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel)) + r.CmsUserRoles.Any(ur => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel)) ) .AsNoTracking() .AsAsyncEnumerable(); @@ -206,7 +205,7 @@ private async Task MigrateUserRole(int k11RoleId) var k11UserRoles = k11Context.CmsUserRoles .Where(ur => ur.RoleId == k11RoleId && - MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel) + UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel) ) .AsNoTracking() .AsAsyncEnumerable(); diff --git a/Migration.Toolkit.Core.K11/K11CoreDiExtensions.cs b/Migration.Toolkit.Core.K11/K11CoreDiExtensions.cs index 6d65a53b..4ab16ee4 100644 --- a/Migration.Toolkit.Core.K11/K11CoreDiExtensions.cs +++ b/Migration.Toolkit.Core.K11/K11CoreDiExtensions.cs @@ -72,11 +72,9 @@ public static IServiceCollection UseK11ToolkitCore(this IServiceCollection servi services.AddTransient, UserInfoMapper>(); services.AddTransient, MemberInfoMapper>(); services.AddTransient, UserRoleInfoMapper>(); - services.AddTransient, MediaLibraryInfoMapper>(); services.AddTransient, OmContactMapper>(); services.AddTransient, OmContactGroupMapper>(); services.AddTransient, OmContactStatusMapper>(); - services.AddTransient, MediaFileInfoMapper>(); services.AddTransient, CountryInfoMapper>(); services.AddTransient, StateInfoMapper>(); diff --git a/Migration.Toolkit.Core.K11/Mappers/MediaLibraryInfoMapper.cs b/Migration.Toolkit.Core.K11/Mappers/MediaLibraryInfoMapper.cs deleted file mode 100644 index 49f07d30..00000000 --- a/Migration.Toolkit.Core.K11/Mappers/MediaLibraryInfoMapper.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Migration.Toolkit.Core.K11.Mappers; - -using CMS.MediaLibrary; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.K11.Contexts; -using Migration.Toolkit.K11.Models; - -public class MediaLibraryInfoMapper(ILogger logger, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol) - : EntityMapperBase(logger, primaryKeyMappingContext, protocol) -{ - protected override MediaLibraryInfo? CreateNewInstance(MediaLibrary source, MappingHelper mappingHelper, AddFailure addFailure) => - MediaLibraryInfo.New(); - - protected override MediaLibraryInfo MapInternal(MediaLibrary source, MediaLibraryInfo target, bool newInstance, MappingHelper mappingHelper, AddFailure addFailure) - { - // Sets the library properties - target.LibraryDisplayName = source.LibraryDisplayName; - target.LibraryName = source.LibraryName; - target.LibraryDescription = source.LibraryDescription; - target.LibraryFolder = source.LibraryFolder; - target.LibraryGUID = mappingHelper.Require(source.LibraryGuid, nameof(source.LibraryGuid)); - target.LibraryDisplayName = source.LibraryDisplayName; - target.LibraryDescription = source.LibraryDescription; - - if (!target.LibraryFolder.StartsWith($"{source.LibrarySite.SiteName}_", StringComparison.InvariantCultureIgnoreCase)) - { - target.LibraryFolder = $"{source.LibrarySite.SiteName}_{source.LibraryFolder}"; - } - - target.LibraryLastModified = mappingHelper.Require(source.LibraryLastModified, nameof(source.LibraryLastModified)); - - return target; - } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX12/Handlers/MigrateMediaLibrariesCommandHandler.cs b/Migration.Toolkit.Core.KX12/Handlers/MigrateMediaLibrariesCommandHandler.cs deleted file mode 100644 index 4d501541..00000000 --- a/Migration.Toolkit.Core.KX12/Handlers/MigrateMediaLibrariesCommandHandler.cs +++ /dev/null @@ -1,247 +0,0 @@ -namespace Migration.Toolkit.Core.KX12.Handlers; - -using CMS.Base; -using CMS.MediaLibrary; -using MediatR; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.KX12.Contexts; -using Migration.Toolkit.Core.KX12.Mappers; -using Migration.Toolkit.KX12.Context; -using Migration.Toolkit.KX12.Models; -using Migration.Toolkit.KXP.Api; -using Migration.Toolkit.KXP.Api.Auxiliary; -using Migration.Toolkit.KXP.Context; - -public class MigrateMediaLibrariesCommandHandler : IRequestHandler, IDisposable -{ - private const string DIR_MEDIA = "media"; - private readonly ILogger _logger; - private readonly IDbContextFactory _kxpContextFactory; - private readonly IDbContextFactory _kx12ContextFactory; - private readonly IEntityMapper _mediaLibraryInfoMapper; - private readonly KxpMediaFileFacade _mediaFileFacade; - private readonly IEntityMapper _mediaFileInfoMapper; - private readonly ToolkitConfiguration _toolkitConfiguration; - private readonly PrimaryKeyMappingContext _primaryKeyMappingContext; - private readonly IProtocol _protocol; - - private KxpContext _kxpContext; - - public MigrateMediaLibrariesCommandHandler( - ILogger logger, - IDbContextFactory kxpContextFactory, - IDbContextFactory kx12ContextFactory, - IEntityMapper mediaLibraryInfoMapper, - KxpMediaFileFacade mediaFileFacade, - IEntityMapper mediaFileInfoMapper, - ToolkitConfiguration toolkitConfiguration, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol - ) - { - _logger = logger; - _kxpContextFactory = kxpContextFactory; - _kx12ContextFactory = kx12ContextFactory; - _mediaLibraryInfoMapper = mediaLibraryInfoMapper; - _mediaFileFacade = mediaFileFacade; - _mediaFileInfoMapper = mediaFileInfoMapper; - _toolkitConfiguration = toolkitConfiguration; - _primaryKeyMappingContext = primaryKeyMappingContext; - _protocol = protocol; - _kxpContext = kxpContextFactory.CreateDbContext(); - } - - public async Task Handle(MigrateMediaLibrariesCommand request, CancellationToken cancellationToken) - { - await using var kx12Context = await _kx12ContextFactory.CreateDbContextAsync(cancellationToken); - - var k12MediaLibraries = kx12Context.MediaLibraries - .Include(ml => ml.LibrarySite) - .OrderBy(t => t.LibraryId) - ; - - var migratedMediaLibraries = new List<(MediaLibrary sourceLibrary, MediaLibraryInfo targetLibrary)>(); - foreach (var k12MediaLibrary in k12MediaLibraries) - { - _protocol.FetchedSource(k12MediaLibrary); - - if (k12MediaLibrary.LibraryGuid is not { } mediaLibraryGuid) - { - _protocol.Append(HandbookReferences - .InvalidSourceData() - .WithId(nameof(MediaLibrary.LibraryId), k12MediaLibrary.LibraryId) - .WithMessage("Media library has missing MediaLibraryGUID") - ); - continue; - } - - var mediaLibraryInfo = _mediaFileFacade.GetMediaLibraryInfo(mediaLibraryGuid); - - _protocol.FetchedTarget(mediaLibraryInfo); - - var mapped = _mediaLibraryInfoMapper.Map(k12MediaLibrary, mediaLibraryInfo); - _protocol.MappedTarget(mapped); - - if (mapped is { Success : true } result) - { - var (mfi, newInstance) = result; - ArgumentNullException.ThrowIfNull(mfi, nameof(mfi)); - - try - { - _mediaFileFacade.SetMediaLibrary(mfi); - - _protocol.Success(k12MediaLibrary, mfi, mapped); - _logger.LogEntitySetAction(newInstance, mfi); - } - catch (Exception ex) - { - await _kxpContext.DisposeAsync(); // reset context errors - _kxpContext = await _kxpContextFactory.CreateDbContextAsync(cancellationToken); - - _protocol.Append(HandbookReferences - .ErrorCreatingTargetInstance(ex) - .NeedsManualAction() - .WithIdentityPrint(mfi) - ); - _logger.LogEntitySetError(ex, newInstance, mfi); - continue; - } - - _primaryKeyMappingContext.SetMapping( - r => r.LibraryId, - k12MediaLibrary.LibraryId, - mfi.LibraryID - ); - - migratedMediaLibraries.Add((k12MediaLibrary, mfi)); - } - } - - await RequireMigratedMediaFiles(migratedMediaLibraries, kx12Context, cancellationToken); - - return new GenericCommandResult(); - } - - private record LoadMediaFileResult(bool Found, IUploadedFile? File); - private LoadMediaFileResult LoadMediaFileBinary(string? sourceMediaLibraryPath, string relativeFilePath, string contentType) - { - if (sourceMediaLibraryPath == null) - { - return new LoadMediaFileResult(false, null); - } - - var filePath = Path.Combine(sourceMediaLibraryPath, relativeFilePath); - if (File.Exists(filePath)) - { - var data = File.ReadAllBytes(filePath); - var dummyFile = DummyUploadedFile.FromByteArray(data, contentType, data.LongLength, Path.GetFileName(filePath)); - return new LoadMediaFileResult(true, dummyFile); - } - - return new LoadMediaFileResult(false, null); - } - - private async Task RequireMigratedMediaFiles( - List<(MediaLibrary sourceLibrary, MediaLibraryInfo targetLibrary)> migratedMediaLibraries, - KX12Context KX12Context, CancellationToken cancellationToken) - { - var kxoDbContext = await _kxpContextFactory.CreateDbContextAsync(cancellationToken); - try - { - foreach (var (sourceMediaLibrary, targetMediaLibrary) in migratedMediaLibraries) - { - string? sourceMediaLibraryPath = null; - var loadMediaFileData = false; - if (!_toolkitConfiguration.MigrateOnlyMediaFileInfo.GetValueOrDefault(true) && - !string.IsNullOrWhiteSpace(_toolkitConfiguration.KxCmsDirPath)) - { - sourceMediaLibraryPath = Path.Combine(_toolkitConfiguration.KxCmsDirPath, sourceMediaLibrary.LibrarySite.SiteName, DIR_MEDIA, sourceMediaLibrary.LibraryFolder); - loadMediaFileData = true; - } - - var k12MediaFiles = KX12Context.MediaFiles - .Where(x => x.FileLibraryId == sourceMediaLibrary.LibraryId); - - foreach (var k12MediaFile in k12MediaFiles) - { - _protocol.FetchedSource(k12MediaFile); - - bool found = false; - IUploadedFile? uploadedFile = null; - if (loadMediaFileData) - { - (found, uploadedFile) = LoadMediaFileBinary(sourceMediaLibraryPath, k12MediaFile.FilePath, k12MediaFile.FileMimeType); - if (!found) - { - // TODO tk: 2022-07-07 report missing file (currently reported in mapper) - } - } - - var librarySubfolder = Path.GetDirectoryName(k12MediaFile.FilePath); - - var kxoMediaFile = _mediaFileFacade.GetMediaFile(k12MediaFile.FileGuid); - - _protocol.FetchedTarget(kxoMediaFile); - - var source = new MediaFileInfoMapperSource(k12MediaFile, targetMediaLibrary.LibraryID, found ? uploadedFile : null, - librarySubfolder, _toolkitConfiguration.MigrateOnlyMediaFileInfo.GetValueOrDefault(false)); - var mapped = _mediaFileInfoMapper.Map(source, kxoMediaFile); - _protocol.MappedTarget(mapped); - - if (mapped is { Success : true } result) - { - var (mf, newInstance) = result; - ArgumentNullException.ThrowIfNull(mf, nameof(mf)); - - try - { - if (newInstance) - { - _mediaFileFacade.EnsureMediaFilePathExistsInLibrary(mf, targetMediaLibrary.LibraryID); - } - - _mediaFileFacade.SetMediaFile(mf, newInstance); - await _kxpContext.SaveChangesAsync(cancellationToken); - - _protocol.Success(k12MediaFile, mf, mapped); - _logger.LogEntitySetAction(newInstance, mf); - } - catch (Exception ex) // TODO tk: 2022-05-18 handle exceptions - { - await kxoDbContext.DisposeAsync(); // reset context errors - kxoDbContext = await _kxpContextFactory.CreateDbContextAsync(cancellationToken); - - _protocol.Append(HandbookReferences - .ErrorCreatingTargetInstance(ex) - .NeedsManualAction() - .WithIdentityPrint(mf) - ); - _logger.LogEntitySetError(ex, newInstance, mf); - continue; - } - - _primaryKeyMappingContext.SetMapping( - r => r.FileId, - k12MediaFile.FileId, - mf.FileID - ); - } - } - } - } - finally - { - await kxoDbContext.DisposeAsync(); - } - } - - public void Dispose() - { - _kxpContext.Dispose(); - } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX12/Handlers/MigrateMembersCommandHandler.cs b/Migration.Toolkit.Core.KX12/Handlers/MigrateMembersCommandHandler.cs index 570cb3e4..0eceefd4 100644 --- a/Migration.Toolkit.Core.KX12/Handlers/MigrateMembersCommandHandler.cs +++ b/Migration.Toolkit.Core.KX12/Handlers/MigrateMembersCommandHandler.cs @@ -12,6 +12,7 @@ using Migration.Toolkit.Core.KX12.Contexts; using Migration.Toolkit.Core.KX12.Mappers; using Migration.Toolkit.KX12.Context; +using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Api.Enums; public class MigrateMembersCommandHandler( @@ -24,15 +25,13 @@ public class MigrateMembersCommandHandler( { private const string USER_PUBLIC = "public"; - private static int[] MigratedAdminUserPrivilegeLevels => new[] { (int)UserPrivilegeLevelEnum.None }; - public async Task Handle(MigrateMembersCommand request, CancellationToken cancellationToken) { await using var kx12Context = await kx12ContextFactory.CreateDbContextAsync(cancellationToken); var k12CmsUsers = kx12Context.CmsUsers .Include(u => u.CmsUserSettingUserSettingsUserNavigation) - .Where(u => MigratedAdminUserPrivilegeLevels.Contains(u.UserPrivilegeLevel)) + .Where(u => UserHelper.PrivilegeLevelsMigratedAsMemberUser.Contains(u.UserPrivilegeLevel)) ; foreach (var k12User in k12CmsUsers) diff --git a/Migration.Toolkit.Core.KX12/Handlers/MigrateUsersCommandHandler.cs b/Migration.Toolkit.Core.KX12/Handlers/MigrateUsersCommandHandler.cs index e6a784ec..15b8746d 100644 --- a/Migration.Toolkit.Core.KX12/Handlers/MigrateUsersCommandHandler.cs +++ b/Migration.Toolkit.Core.KX12/Handlers/MigrateUsersCommandHandler.cs @@ -10,6 +10,7 @@ using Migration.Toolkit.Common.MigrationProtocol; using Migration.Toolkit.Core.KX12.Contexts; using Migration.Toolkit.KX12.Context; +using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Api.Enums; public class MigrateUsersCommandHandler( @@ -24,14 +25,12 @@ public class MigrateUsersCommandHandler( { private const string USER_PUBLIC = "public"; - private static int[] MigratedAdminUserPrivilegeLevels => [(int)UserPrivilegeLevelEnum.Editor, (int)UserPrivilegeLevelEnum.Admin, (int)UserPrivilegeLevelEnum.GlobalAdmin]; - public async Task Handle(MigrateUsersCommand request, CancellationToken cancellationToken) { await using var kx12Context = await kx12ContextFactory.CreateDbContextAsync(cancellationToken); var k12CmsUsers = kx12Context.CmsUsers - .Where(u => MigratedAdminUserPrivilegeLevels.Contains(u.UserPrivilegeLevel)) + .Where(u => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(u.UserPrivilegeLevel)) ; foreach (var k12User in k12CmsUsers) @@ -117,7 +116,7 @@ private async Task MigrateUserCmsRoles(KX12Context kx12Context, CancellationToke { var k12CmsRoles = kx12Context.CmsRoles .Where(r => - r.CmsUserRoles.Any(ur => MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel)) + r.CmsUserRoles.Any(ur => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel)) ) .AsNoTracking() .AsAsyncEnumerable(); @@ -171,7 +170,7 @@ private async Task MigrateUserRole(int k12RoleId) var k12UserRoles = kx12Context.CmsUserRoles .Where(ur => ur.RoleId == k12RoleId && - MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel) + UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel) ) .AsNoTracking() .AsAsyncEnumerable(); diff --git a/Migration.Toolkit.Core.KX12/KX12CoreDiExtensions.cs b/Migration.Toolkit.Core.KX12/KX12CoreDiExtensions.cs index 933a9c21..0b3f4be9 100644 --- a/Migration.Toolkit.Core.KX12/KX12CoreDiExtensions.cs +++ b/Migration.Toolkit.Core.KX12/KX12CoreDiExtensions.cs @@ -72,11 +72,9 @@ public static IServiceCollection UseKx12ToolkitCore(this IServiceCollection serv services.AddTransient, UserInfoMapper>(); services.AddTransient, MemberInfoMapper>(); services.AddTransient, UserRoleInfoMapper>(); - services.AddTransient, MediaLibraryInfoMapper>(); services.AddTransient, OmContactMapper>(); services.AddTransient, OmContactGroupMapper>(); services.AddTransient, OmContactStatusMapper>(); - services.AddTransient, MediaFileInfoMapper>(); services.AddTransient, CountryInfoMapper>(); services.AddTransient, StateInfoMapper>(); diff --git a/Migration.Toolkit.Core.KX12/Mappers/MediaFileInfoMapper.cs b/Migration.Toolkit.Core.KX12/Mappers/MediaFileInfoMapper.cs deleted file mode 100644 index e6050e3f..00000000 --- a/Migration.Toolkit.Core.KX12/Mappers/MediaFileInfoMapper.cs +++ /dev/null @@ -1,173 +0,0 @@ -namespace Migration.Toolkit.Core.KX12.Mappers; - -using System.Data; -using CMS.Base; -using CMS.MediaLibrary; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.KX12.Contexts; -using Migration.Toolkit.Core.KX12.Helpers; -using Migration.Toolkit.KX12.Models; -using Migration.Toolkit.KXP.Api; - -public record MediaFileInfoMapperSource(MediaFile MediaFile, int TargetLibraryId, IUploadedFile? File, string? LibrarySubFolder, - bool MigrateOnlyMediaFileInfo); - -public class MediaFileInfoMapper: EntityMapperBase -{ - private readonly ILogger _logger; - private readonly KxpClassFacade _classFacade; - private readonly IProtocol _protocol; - private readonly ToolkitConfiguration _toolkitConfiguration; - private readonly KeyMappingContext _keyMappingContext; - - public MediaFileInfoMapper( - ILogger logger, - PrimaryKeyMappingContext primaryKeyMappingContext, - KxpClassFacade classFacade, - IProtocol protocol, - ToolkitConfiguration toolkitConfiguration, - KeyMappingContext keyMappingContext - ): base(logger, primaryKeyMappingContext, protocol) - { - _logger = logger; - _classFacade = classFacade; - _protocol = protocol; - _toolkitConfiguration = toolkitConfiguration; - _keyMappingContext = keyMappingContext; - } - - - protected override MediaFileInfo? CreateNewInstance(MediaFileInfoMapperSource source, MappingHelper mappingHelper, AddFailure addFailure) { - if (source.File != null) - { - var mf = new MediaFileInfo(source.File, source.TargetLibraryId, source.LibrarySubFolder ?? "", 0, 0, 0); - mf.SaveFileToDisk(true); - return mf; - } - - return new MediaFileInfo(); - } - - protected override MediaFileInfo MapInternal(MediaFileInfoMapperSource args, MediaFileInfo target, bool newInstance, MappingHelper mappingHelper, AddFailure addFailure) - { - var (mediaFile, targetLibraryId, file, _, migrateOnlyMediaFileInfo) = args; - - target.FileName = mediaFile.FileName; - target.FileTitle = mediaFile.FileTitle; - target.FileDescription = mediaFile.FileDescription; - target.FileExtension = mediaFile.FileExtension; - target.FileMimeType = mediaFile.FileMimeType; - target.FileSize = mediaFile.FileSize; - target.FileImageWidth = mediaFile.FileImageWidth ?? 0; - target.FileImageHeight = mediaFile.FileImageHeight ?? 0; - target.FileGUID = mediaFile.FileGuid; - target.FileCreatedWhen = mediaFile.FileCreatedWhen; - target.FileModifiedWhen = mediaFile.FileModifiedWhen; - KenticoHelper.CopyCustomData(target.FileCustomData, mediaFile.FileCustomData); - - MigrateCustomizedFields(target, mediaFile); - - target.FileLibraryID = targetLibraryId; - - var targetCreatedMemberId = _keyMappingContext.MapSourceKey( - s => s.UserId, - s => s.UserGuid, - mediaFile.FileCreatedByUserId, - t => t.MemberId, - t => t.MemberGuid - ); - if (targetCreatedMemberId.Success) - { - // user was migrated to MEMBER => setting user would break foreign key - target.SetValue(nameof(target.FileCreatedByUserID), CMSActionContext.CurrentUser.UserID); - } - else if (mappingHelper.TranslateIdAllowNulls(c => c.UserId, mediaFile.FileCreatedByUserId, out var createdByUserId)) - { - target.SetValue(nameof(target.FileCreatedByUserID), createdByUserId); - } - - var targetModifiedMemberId = _keyMappingContext.MapSourceKey( - s => s.UserId, - s => s.UserGuid, - mediaFile.FileModifiedByUserId, - t => t.MemberId, - t => t.MemberGuid - ); - if (targetModifiedMemberId.Success) - { - // user was migrated to MEMBER => setting user would break foreign key - target.SetValue(nameof(target.FileModifiedByUserID), CMSActionContext.CurrentUser.UserID); - } - else if (mappingHelper.TranslateIdAllowNulls(c => c.UserId, mediaFile.FileModifiedByUserId, out var modifiedByUserId)) - { - target.SetValue(nameof(target.FileModifiedByUserID), modifiedByUserId); - } - - if (string.IsNullOrWhiteSpace(target.FilePath)) - { - target.FilePath = mediaFile.FilePath; - } - - if (file == null && !migrateOnlyMediaFileInfo) - { - addFailure(HandbookReferences.MediaFileIsMissingOnSourceFilesystem - .WithId(nameof(mediaFile.FileId), mediaFile.FileId) - .WithData(new - { - mediaFile.FilePath, - mediaFile.FileGuid, - mediaFile.FileLibraryId, - mediaFile.FileSiteId - }) - .AsFailure() - ); - } - - return target; - } - - private void MigrateCustomizedFields(MediaFileInfo target, MediaFile mediaFile) - { - var customizedFields = _classFacade.GetCustomizedFieldInfos(MediaFileInfo.TYPEINFO.ObjectClassName).ToList(); - if (customizedFields.Count <= 0) return; - - try - { - var query = - $"SELECT {string.Join(", ", customizedFields.Select(x => x.FieldName))} FROM {MediaFileInfo.TYPEINFO.ClassStructureInfo.TableName} WHERE {MediaFileInfo.TYPEINFO.ClassStructureInfo.IDColumn} = @id"; - - using var conn = new SqlConnection(_toolkitConfiguration.KxConnectionString); - using var cmd = conn.CreateCommand(); - - cmd.CommandText = query; - cmd.CommandType = CommandType.Text; - cmd.CommandTimeout = 3; - cmd.Parameters.AddWithValue("id", mediaFile.FileId); - - conn.Open(); - - using var reader = cmd.ExecuteReader(); - if (reader.Read()) - { - foreach (var customizedFieldInfo in customizedFields) - { - _logger.LogDebug("Map customized field '{FieldName}'", customizedFieldInfo.FieldName); - target.SetValue(customizedFieldInfo.FieldName, reader.GetValue(customizedFieldInfo.FieldName)); - } - } - else - { - // failed! - _logger.LogError("Failed to load MediaFileInfo custom data from source database"); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to load MediaFileInfo custom data from source database"); - } - } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX12/Mappers/MediaLibraryInfoMapper.cs b/Migration.Toolkit.Core.KX12/Mappers/MediaLibraryInfoMapper.cs deleted file mode 100644 index 13e1a916..00000000 --- a/Migration.Toolkit.Core.KX12/Mappers/MediaLibraryInfoMapper.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Migration.Toolkit.Core.KX12.Mappers; - -using CMS.MediaLibrary; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.KX12.Contexts; - -public class MediaLibraryInfoMapper : EntityMapperBase -{ - public MediaLibraryInfoMapper( - ILogger logger, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol - ) : base(logger, primaryKeyMappingContext, protocol) - { - } - - protected override MediaLibraryInfo? CreateNewInstance(KX12M.MediaLibrary source, MappingHelper mappingHelper, AddFailure addFailure) => - MediaLibraryInfo.New(); - - protected override MediaLibraryInfo MapInternal(KX12M.MediaLibrary source, MediaLibraryInfo target, bool newInstance, MappingHelper mappingHelper, AddFailure addFailure) - { - // Sets the library properties - target.LibraryDisplayName = source.LibraryDisplayName; - target.LibraryName = source.LibraryName; - target.LibraryDescription = source.LibraryDescription; - target.LibraryFolder = source.LibraryFolder; - target.LibraryGUID = mappingHelper.Require(source.LibraryGuid, nameof(source.LibraryGuid)); - target.LibraryDisplayName = source.LibraryDisplayName; - target.LibraryDescription = source.LibraryDescription; - - if (!target.LibraryFolder.StartsWith($"{source.LibrarySite.SiteName}_", StringComparison.InvariantCultureIgnoreCase)) - { - target.LibraryFolder = $"{source.LibrarySite.SiteName}_{source.LibraryFolder}"; - } - - target.LibraryLastModified = mappingHelper.Require(source.LibraryLastModified, nameof(source.LibraryLastModified)); - - return target; - } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX13/DependencyInjectionExtensions.cs b/Migration.Toolkit.Core.KX13/DependencyInjectionExtensions.cs index bc3d4f49..e95f1a4e 100644 --- a/Migration.Toolkit.Core.KX13/DependencyInjectionExtensions.cs +++ b/Migration.Toolkit.Core.KX13/DependencyInjectionExtensions.cs @@ -72,11 +72,9 @@ public static IServiceCollection UseKx13ToolkitCore(this IServiceCollection serv services.AddTransient, UserInfoMapper>(); services.AddTransient, MemberInfoMapper>(); services.AddTransient, UserRoleInfoMapper>(); - services.AddTransient, MediaLibraryInfoMapper>(); services.AddTransient, OmContactMapper>(); services.AddTransient, OmContactGroupMapper>(); services.AddTransient, OmContactStatusMapper>(); - services.AddTransient, MediaFileInfoMapper>(); services.AddTransient, CountryInfoMapper>(); services.AddTransient, StateInfoMapper>(); diff --git a/Migration.Toolkit.Core.KX13/Handlers/MigrateMediaLibrariesCommandHandler.cs b/Migration.Toolkit.Core.KX13/Handlers/MigrateMediaLibrariesCommandHandler.cs deleted file mode 100644 index 84296e39..00000000 --- a/Migration.Toolkit.Core.KX13/Handlers/MigrateMediaLibrariesCommandHandler.cs +++ /dev/null @@ -1,247 +0,0 @@ -namespace Migration.Toolkit.Core.KX13.Handlers; - -using CMS.Base; -using CMS.MediaLibrary; -using MediatR; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.KX13.Contexts; -using Migration.Toolkit.Core.KX13.Mappers; -using Migration.Toolkit.KX13.Context; -using Migration.Toolkit.KX13.Models; -using Migration.Toolkit.KXP.Api; -using Migration.Toolkit.KXP.Api.Auxiliary; -using Migration.Toolkit.KXP.Context; - -public class MigrateMediaLibrariesCommandHandler : IRequestHandler, IDisposable -{ - private const string DIR_MEDIA = "media"; - private readonly ILogger _logger; - private readonly IDbContextFactory _kxpContextFactory; - private readonly IDbContextFactory _kx13ContextFactory; - private readonly IEntityMapper _mediaLibraryInfoMapper; - private readonly KxpMediaFileFacade _mediaFileFacade; - private readonly IEntityMapper _mediaFileInfoMapper; - private readonly ToolkitConfiguration _toolkitConfiguration; - private readonly PrimaryKeyMappingContext _primaryKeyMappingContext; - private readonly IProtocol _protocol; - - private KxpContext _kxpContext; - - public MigrateMediaLibrariesCommandHandler( - ILogger logger, - IDbContextFactory kxpContextFactory, - IDbContextFactory kx13ContextFactory, - IEntityMapper mediaLibraryInfoMapper, - KxpMediaFileFacade mediaFileFacade, - IEntityMapper mediaFileInfoMapper, - ToolkitConfiguration toolkitConfiguration, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol - ) - { - _logger = logger; - _kxpContextFactory = kxpContextFactory; - _kx13ContextFactory = kx13ContextFactory; - _mediaLibraryInfoMapper = mediaLibraryInfoMapper; - _mediaFileFacade = mediaFileFacade; - _mediaFileInfoMapper = mediaFileInfoMapper; - _toolkitConfiguration = toolkitConfiguration; - _primaryKeyMappingContext = primaryKeyMappingContext; - _protocol = protocol; - _kxpContext = kxpContextFactory.CreateDbContext(); - } - - public async Task Handle(MigrateMediaLibrariesCommand request, CancellationToken cancellationToken) - { - await using var kx13Context = await _kx13ContextFactory.CreateDbContextAsync(cancellationToken); - - var kx13MediaLibraries = kx13Context.MediaLibraries - .Include(ml => ml.LibrarySite) - .OrderBy(t => t.LibraryId) - ; - - var migratedMediaLibraries = new List<(MediaLibrary sourceLibrary, MediaLibraryInfo targetLibrary)>(); - foreach (var kx13MediaLibrary in kx13MediaLibraries) - { - _protocol.FetchedSource(kx13MediaLibrary); - - if (kx13MediaLibrary.LibraryGuid is not { } mediaLibraryGuid) - { - _protocol.Append(HandbookReferences - .InvalidSourceData() - .WithId(nameof(MediaLibrary.LibraryId), kx13MediaLibrary.LibraryId) - .WithMessage("Media library has missing MediaLibraryGUID") - ); - continue; - } - - var mediaLibraryInfo = _mediaFileFacade.GetMediaLibraryInfo(mediaLibraryGuid); - - _protocol.FetchedTarget(mediaLibraryInfo); - - var mapped = _mediaLibraryInfoMapper.Map(kx13MediaLibrary, mediaLibraryInfo); - _protocol.MappedTarget(mapped); - - if (mapped is { Success : true } result) - { - var (mfi, newInstance) = result; - ArgumentNullException.ThrowIfNull(mfi, nameof(mfi)); - - try - { - _mediaFileFacade.SetMediaLibrary(mfi); - - _protocol.Success(kx13MediaLibrary, mfi, mapped); - _logger.LogEntitySetAction(newInstance, mfi); - } - catch (Exception ex) - { - await _kxpContext.DisposeAsync(); // reset context errors - _kxpContext = await _kxpContextFactory.CreateDbContextAsync(cancellationToken); - - _protocol.Append(HandbookReferences - .ErrorCreatingTargetInstance(ex) - .NeedsManualAction() - .WithIdentityPrint(mfi) - ); - _logger.LogEntitySetError(ex, newInstance, mfi); - continue; - } - - _primaryKeyMappingContext.SetMapping( - r => r.LibraryId, - kx13MediaLibrary.LibraryId, - mfi.LibraryID - ); - - migratedMediaLibraries.Add((kx13MediaLibrary, mfi)); - } - } - - await RequireMigratedMediaFiles(migratedMediaLibraries, kx13Context, cancellationToken); - - return new GenericCommandResult(); - } - - private record LoadMediaFileResult(bool Found, IUploadedFile? File); - private LoadMediaFileResult LoadMediaFileBinary(string? sourceMediaLibraryPath, string relativeFilePath, string contentType) - { - if (sourceMediaLibraryPath == null) - { - return new LoadMediaFileResult(false, null); - } - - var filePath = Path.Combine(sourceMediaLibraryPath, relativeFilePath); - if (File.Exists(filePath)) - { - var data = File.ReadAllBytes(filePath); - var dummyFile = DummyUploadedFile.FromByteArray(data, contentType, data.LongLength, Path.GetFileName(filePath)); - return new LoadMediaFileResult(true, dummyFile); - } - - return new LoadMediaFileResult(false, null); - } - - private async Task RequireMigratedMediaFiles( - List<(MediaLibrary sourceLibrary, MediaLibraryInfo targetLibrary)> migratedMediaLibraries, - KX13Context kx13Context, CancellationToken cancellationToken) - { - var kxoDbContext = await _kxpContextFactory.CreateDbContextAsync(cancellationToken); - try - { - foreach (var (sourceMediaLibrary, targetMediaLibrary) in migratedMediaLibraries) - { - string? sourceMediaLibraryPath = null; - var loadMediaFileData = false; - if (!_toolkitConfiguration.MigrateOnlyMediaFileInfo.GetValueOrDefault(true) && - !string.IsNullOrWhiteSpace(_toolkitConfiguration.KxCmsDirPath)) - { - sourceMediaLibraryPath = Path.Combine(_toolkitConfiguration.KxCmsDirPath, sourceMediaLibrary.LibrarySite.SiteName, DIR_MEDIA, sourceMediaLibrary.LibraryFolder); - loadMediaFileData = true; - } - - var kx13MediaFiles = kx13Context.MediaFiles - .Where(x => x.FileLibraryId == sourceMediaLibrary.LibraryId); - - foreach (var kx13MediaFile in kx13MediaFiles) - { - _protocol.FetchedSource(kx13MediaFile); - - bool found = false; - IUploadedFile? uploadedFile = null; - if (loadMediaFileData) - { - (found, uploadedFile) = LoadMediaFileBinary(sourceMediaLibraryPath, kx13MediaFile.FilePath, kx13MediaFile.FileMimeType); - if (!found) - { - // TODO tk: 2022-07-07 report missing file (currently reported in mapper) - } - } - - var librarySubfolder = Path.GetDirectoryName(kx13MediaFile.FilePath); - - var kxoMediaFile = _mediaFileFacade.GetMediaFile(kx13MediaFile.FileGuid); - - _protocol.FetchedTarget(kxoMediaFile); - - var source = new MediaFileInfoMapperSource(kx13MediaFile, targetMediaLibrary.LibraryID, found ? uploadedFile : null, - librarySubfolder, _toolkitConfiguration.MigrateOnlyMediaFileInfo.GetValueOrDefault(false)); - var mapped = _mediaFileInfoMapper.Map(source, kxoMediaFile); - _protocol.MappedTarget(mapped); - - if (mapped is { Success : true } result) - { - var (mf, newInstance) = result; - ArgumentNullException.ThrowIfNull(mf, nameof(mf)); - - try - { - if (newInstance) - { - _mediaFileFacade.EnsureMediaFilePathExistsInLibrary(mf, targetMediaLibrary.LibraryID); - } - - _mediaFileFacade.SetMediaFile(mf, newInstance); - await _kxpContext.SaveChangesAsync(cancellationToken); - - _protocol.Success(kx13MediaFile, mf, mapped); - _logger.LogEntitySetAction(newInstance, mf); - } - catch (Exception ex) // TODO tk: 2022-05-18 handle exceptions - { - await kxoDbContext.DisposeAsync(); // reset context errors - kxoDbContext = await _kxpContextFactory.CreateDbContextAsync(cancellationToken); - - _protocol.Append(HandbookReferences - .ErrorCreatingTargetInstance(ex) - .NeedsManualAction() - .WithIdentityPrint(mf) - ); - _logger.LogEntitySetError(ex, newInstance, mf); - continue; - } - - _primaryKeyMappingContext.SetMapping( - r => r.FileId, - kx13MediaFile.FileId, - mf.FileID - ); - } - } - } - } - finally - { - await kxoDbContext.DisposeAsync(); - } - } - - public void Dispose() - { - _kxpContext.Dispose(); - } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX13/Handlers/MigrateMembersCommandHandler.cs b/Migration.Toolkit.Core.KX13/Handlers/MigrateMembersCommandHandler.cs index 20db298c..f8f1b06b 100644 --- a/Migration.Toolkit.Core.KX13/Handlers/MigrateMembersCommandHandler.cs +++ b/Migration.Toolkit.Core.KX13/Handlers/MigrateMembersCommandHandler.cs @@ -12,6 +12,7 @@ using Migration.Toolkit.Core.KX13.Contexts; using Migration.Toolkit.Core.KX13.Mappers; using Migration.Toolkit.KX13.Context; +using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Api.Enums; public class MigrateMembersCommandHandler( @@ -24,15 +25,13 @@ public class MigrateMembersCommandHandler( { private const string USER_PUBLIC = "public"; - private static int[] MigratedAdminUserPrivilegeLevels => [(int)UserPrivilegeLevelEnum.None]; - public async Task Handle(MigrateMembersCommand request, CancellationToken cancellationToken) { await using var kx13Context = await kx13ContextFactory.CreateDbContextAsync(cancellationToken); var kx13CmsUsers = kx13Context.CmsUsers .Include(u => u.CmsUserSettingUserSettingsUserNavigation) - .Where(u => MigratedAdminUserPrivilegeLevels.Contains(u.UserPrivilegeLevel)) + .Where(u => UserHelper.PrivilegeLevelsMigratedAsMemberUser.Contains(u.UserPrivilegeLevel)) ; foreach (var kx13User in kx13CmsUsers) diff --git a/Migration.Toolkit.Core.KX13/Handlers/MigrateUsersCommandHandler.cs b/Migration.Toolkit.Core.KX13/Handlers/MigrateUsersCommandHandler.cs index c7356afd..21767a79 100644 --- a/Migration.Toolkit.Core.KX13/Handlers/MigrateUsersCommandHandler.cs +++ b/Migration.Toolkit.Core.KX13/Handlers/MigrateUsersCommandHandler.cs @@ -10,80 +10,60 @@ using Migration.Toolkit.Common.MigrationProtocol; using Migration.Toolkit.Core.KX13.Contexts; using Migration.Toolkit.KX13.Context; +using Migration.Toolkit.KXP.Api.Auxiliary; using Migration.Toolkit.KXP.Api.Enums; -public class MigrateUsersCommandHandler : IRequestHandler, IDisposable +public class MigrateUsersCommandHandler( + ILogger logger, + IDbContextFactory kx13ContextFactory, + IEntityMapper userInfoMapper, + IEntityMapper roleMapper, + IEntityMapper userRoleMapper, + PrimaryKeyMappingContext primaryKeyMappingContext, + IProtocol protocol) + : IRequestHandler, IDisposable { private const string USER_PUBLIC = "public"; - private readonly ILogger _logger; - private readonly IDbContextFactory _kx13ContextFactory; - private readonly IEntityMapper _userInfoMapper; - private readonly IEntityMapper _roleMapper; - private readonly IEntityMapper _userRoleMapper; - private readonly PrimaryKeyMappingContext _primaryKeyMappingContext; - private readonly IProtocol _protocol; - - private static int[] MigratedAdminUserPrivilegeLevels => new[] { (int)UserPrivilegeLevelEnum.Editor, (int)UserPrivilegeLevelEnum.Admin, (int)UserPrivilegeLevelEnum.GlobalAdmin }; - - public MigrateUsersCommandHandler( - ILogger logger, - IDbContextFactory kx13ContextFactory, - IEntityMapper userInfoMapper, - IEntityMapper roleMapper, - IEntityMapper userRoleMapper, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol - ) - { - _logger = logger; - _kx13ContextFactory = kx13ContextFactory; - _userInfoMapper = userInfoMapper; - _roleMapper = roleMapper; - _userRoleMapper = userRoleMapper; - _primaryKeyMappingContext = primaryKeyMappingContext; - _protocol = protocol; - } - public async Task Handle(MigrateUsersCommand request, CancellationToken cancellationToken) { - await using var kx13Context = await _kx13ContextFactory.CreateDbContextAsync(cancellationToken); + await using var kx13Context = await kx13ContextFactory.CreateDbContextAsync(cancellationToken); var kx13CmsUsers = kx13Context.CmsUsers - .Where(u => MigratedAdminUserPrivilegeLevels.Contains(u.UserPrivilegeLevel)) + .Where(u => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(u.UserPrivilegeLevel)) ; foreach (var kx13User in kx13CmsUsers) { - _protocol.FetchedSource(kx13User); - _logger.LogTrace("Migrating user {UserName} with UserGuid {UserGuid}", kx13User.UserName, kx13User.UserGuid); + protocol.FetchedSource(kx13User); + logger.LogTrace("Migrating user {UserName} with UserGuid {UserGuid}", kx13User.UserName, kx13User.UserGuid); var xbkUserInfo = UserInfoProvider.ProviderObject.Get(kx13User.UserGuid); - _protocol.FetchedTarget(xbkUserInfo); + protocol.FetchedTarget(xbkUserInfo); if (kx13User.UserPrivilegeLevel == (int)UserPrivilegeLevelEnum.GlobalAdmin && xbkUserInfo != null) { - _protocol.Append(HandbookReferences.CmsUserAdminUserSkip.WithIdentityPrint(xbkUserInfo)); - _logger.LogInformation("User with guid {UserGuid} is administrator, you need to update administrators manually => skipping", kx13User.UserGuid); - _primaryKeyMappingContext.SetMapping(r => r.UserId, kx13User.UserId, xbkUserInfo.UserID); + protocol.Append(HandbookReferences.CmsUserAdminUserSkip.WithIdentityPrint(xbkUserInfo)); + logger.LogInformation("User with guid {UserGuid} is administrator, you need to update administrators manually => skipping", kx13User.UserGuid); + primaryKeyMappingContext.SetMapping(r => r.UserId, kx13User.UserId, xbkUserInfo.UserID); continue; } if (xbkUserInfo?.UserName == USER_PUBLIC || kx13User.UserName == USER_PUBLIC) { - _protocol.Append(HandbookReferences.CmsUserPublicUserSkip.WithIdentityPrint(xbkUserInfo)); - _logger.LogInformation("User with guid {UserGuid} is public user, special case that can't be migrated => skipping", xbkUserInfo?.UserGUID ?? kx13User.UserGuid); + protocol.Append(HandbookReferences.CmsUserPublicUserSkip.WithIdentityPrint(xbkUserInfo)); + logger.LogInformation("User with guid {UserGuid} is public user, special case that can't be migrated => skipping", xbkUserInfo?.UserGUID ?? kx13User.UserGuid); if (xbkUserInfo != null) { - _primaryKeyMappingContext.SetMapping(r => r.UserId, kx13User.UserId, xbkUserInfo.UserID); + primaryKeyMappingContext.SetMapping(r => r.UserId, kx13User.UserId, xbkUserInfo.UserID); } continue; } - var mapped = _userInfoMapper.Map(kx13User, xbkUserInfo); - _protocol.MappedTarget(mapped); + var mapped = userInfoMapper.Map(kx13User, xbkUserInfo); + protocol.MappedTarget(mapped); await SaveUserUsingKenticoApi(mapped, kx13User); } @@ -104,14 +84,14 @@ private Task SaveUserUsingKenticoApi(IModelMappingResult mapped, KX13M { UserInfoProvider.ProviderObject.Set(userInfo); - _protocol.Success(kx13User, userInfo, mapped); - _logger.LogEntitySetAction(newInstance, userInfo); + protocol.Success(kx13User, userInfo, mapped); + logger.LogEntitySetAction(newInstance, userInfo); } /*Violation in unique index or Violation in unique constraint */ catch (DbUpdateException dbUpdateException) when (dbUpdateException.InnerException is SqlException { Number: 2601 or 2627 } sqlException) { - _logger.LogEntitySetError(sqlException, newInstance, userInfo); - _protocol.Append(HandbookReferences.DbConstraintBroken(sqlException, kx13User) + logger.LogEntitySetError(sqlException, newInstance, userInfo); + protocol.Append(HandbookReferences.DbConstraintBroken(sqlException, kx13User) .WithData(new { kx13User.UserName, kx13User.UserGuid, kx13User.UserId, }) .WithMessage("Failed to migrate user, target database broken.") ); @@ -119,8 +99,8 @@ private Task SaveUserUsingKenticoApi(IModelMappingResult mapped, KX13M } catch (Exception ex) { - _logger.LogEntitySetError(ex, newInstance, userInfo); - _protocol.Append(HandbookReferences + logger.LogEntitySetError(ex, newInstance, userInfo); + protocol.Append(HandbookReferences .ErrorCreatingTargetInstance(ex) .NeedsManualAction() .WithIdentityPrint(userInfo) @@ -128,7 +108,7 @@ private Task SaveUserUsingKenticoApi(IModelMappingResult mapped, KX13M return Task.CompletedTask; } - _primaryKeyMappingContext.SetMapping(r => r.UserId, kx13User.UserId, userInfo.UserID); + primaryKeyMappingContext.SetMapping(r => r.UserId, kx13User.UserId, userInfo.UserID); return Task.CompletedTask; } @@ -139,19 +119,19 @@ private async Task MigrateUserCmsRoles(KX13Context kx13Context, CancellationToke { var kx13CmsRoles = kx13Context.CmsRoles .Where(r => - r.CmsUserRoles.Any(ur => MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel)) + r.CmsUserRoles.Any(ur => UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel)) ) .AsNoTracking() .AsAsyncEnumerable(); await foreach (var kx13CmsRole in kx13CmsRoles.WithCancellation(cancellationToken)) { - _protocol.FetchedSource(kx13CmsRole); + protocol.FetchedSource(kx13CmsRole); var xbkRoleInfo = RoleInfoProvider.ProviderObject.Get(kx13CmsRole.RoleGuid); - _protocol.FetchedTarget(xbkRoleInfo); - var mapped = _roleMapper.Map(kx13CmsRole, xbkRoleInfo); - _protocol.MappedTarget(mapped); + protocol.FetchedTarget(xbkRoleInfo); + var mapped = roleMapper.Map(kx13CmsRole, xbkRoleInfo); + protocol.MappedTarget(mapped); if (mapped is not (var roleInfo, var newInstance) { Success : true }) { @@ -163,10 +143,10 @@ private async Task MigrateUserCmsRoles(KX13Context kx13Context, CancellationToke { RoleInfoProvider.ProviderObject.Set(roleInfo); - _protocol.Success(kx13CmsRole, roleInfo, mapped); - _logger.LogEntitySetAction(newInstance, roleInfo); + protocol.Success(kx13CmsRole, roleInfo, mapped); + logger.LogEntitySetAction(newInstance, roleInfo); - _primaryKeyMappingContext.SetMapping( + primaryKeyMappingContext.SetMapping( r => r.RoleId, kx13CmsRole.RoleId, roleInfo.RoleID @@ -174,8 +154,8 @@ private async Task MigrateUserCmsRoles(KX13Context kx13Context, CancellationToke } catch (Exception ex) { - _logger.LogEntitySetError(ex, newInstance, roleInfo); - _protocol.Append(HandbookReferences + logger.LogEntitySetError(ex, newInstance, roleInfo); + protocol.Append(HandbookReferences .ErrorCreatingTargetInstance(ex) .NeedsManualAction() .WithIdentityPrint(roleInfo) @@ -189,39 +169,39 @@ private async Task MigrateUserCmsRoles(KX13Context kx13Context, CancellationToke private async Task MigrateUserRole(int kx13RoleId) { - var kx13Context = await _kx13ContextFactory.CreateDbContextAsync(); + var kx13Context = await kx13ContextFactory.CreateDbContextAsync(); var kx13UserRoles = kx13Context.CmsUserRoles .Where(ur => ur.RoleId == kx13RoleId && - MigratedAdminUserPrivilegeLevels.Contains(ur.User.UserPrivilegeLevel) + UserHelper.PrivilegeLevelsMigratedAsAdminUser.Contains(ur.User.UserPrivilegeLevel) ) .AsNoTracking() .AsAsyncEnumerable(); await foreach (var kx13UserRole in kx13UserRoles) { - _protocol.FetchedSource(kx13UserRole); - if (!_primaryKeyMappingContext.TryRequireMapFromSource(u => u.RoleId, kx13RoleId, out var xbkRoleId)) + protocol.FetchedSource(kx13UserRole); + if (!primaryKeyMappingContext.TryRequireMapFromSource(u => u.RoleId, kx13RoleId, out var xbkRoleId)) { var handbookRef = HandbookReferences .MissingRequiredDependency(nameof(UserRoleInfo.RoleID), kx13UserRole.RoleId) .NeedsManualAction(); - _protocol.Append(handbookRef); - _logger.LogWarning("Unable to locate role in target instance with source RoleID '{RoleID}'", kx13UserRole.RoleId); + protocol.Append(handbookRef); + logger.LogWarning("Unable to locate role in target instance with source RoleID '{RoleID}'", kx13UserRole.RoleId); continue; } - if (!_primaryKeyMappingContext.TryRequireMapFromSource(u => u.UserId, kx13UserRole.UserId, out var xbkUserId)) + if (!primaryKeyMappingContext.TryRequireMapFromSource(u => u.UserId, kx13UserRole.UserId, out var xbkUserId)) { continue; } var xbkUserRole = UserRoleInfoProvider.ProviderObject.Get(xbkUserId, xbkRoleId); - _protocol.FetchedTarget(xbkUserRole); + protocol.FetchedTarget(xbkUserRole); - var mapped = _userRoleMapper.Map(kx13UserRole, xbkUserRole); - _protocol.MappedTarget(mapped); + var mapped = userRoleMapper.Map(kx13UserRole, xbkUserRole); + protocol.MappedTarget(mapped); if (mapped is { Success : true }) { @@ -232,13 +212,13 @@ private async Task MigrateUserRole(int kx13RoleId) { UserRoleInfoProvider.ProviderObject.Set(userRoleInfo); - _protocol.Success(kx13UserRole, userRoleInfo, mapped); - _logger.LogEntitySetAction(newInstance, userRoleInfo); + protocol.Success(kx13UserRole, userRoleInfo, mapped); + logger.LogEntitySetAction(newInstance, userRoleInfo); } catch (Exception ex) { - _logger.LogEntitySetError(ex, newInstance, userRoleInfo); - _protocol.Append(HandbookReferences.ErrorSavingTargetInstance(ex) + logger.LogEntitySetError(ex, newInstance, userRoleInfo); + protocol.Append(HandbookReferences.ErrorSavingTargetInstance(ex) .WithData(new { kx13UserRole.UserRoleId, kx13UserRole.UserId, kx13UserRole.RoleId, }) .WithMessage("Failed to migrate user role") ); diff --git a/Migration.Toolkit.Core.KX13/Mappers/MediaFileInfoMapper.cs b/Migration.Toolkit.Core.KX13/Mappers/MediaFileInfoMapper.cs deleted file mode 100644 index 739df2c1..00000000 --- a/Migration.Toolkit.Core.KX13/Mappers/MediaFileInfoMapper.cs +++ /dev/null @@ -1,173 +0,0 @@ -namespace Migration.Toolkit.Core.KX13.Mappers; - -using System.Data; -using CMS.Base; -using CMS.MediaLibrary; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.KX13.Contexts; -using Migration.Toolkit.Core.KX13.Helpers; -using Migration.Toolkit.KX13.Models; -using Migration.Toolkit.KXP.Api; - -public record MediaFileInfoMapperSource(MediaFile MediaFile, int TargetLibraryId, IUploadedFile? File, string? LibrarySubFolder, - bool MigrateOnlyMediaFileInfo); - -public class MediaFileInfoMapper: EntityMapperBase -{ - private readonly ILogger _logger; - private readonly KxpClassFacade _classFacade; - private readonly IProtocol _protocol; - private readonly ToolkitConfiguration _toolkitConfiguration; - private readonly KeyMappingContext _keyMappingContext; - - public MediaFileInfoMapper( - ILogger logger, - PrimaryKeyMappingContext primaryKeyMappingContext, - KxpClassFacade classFacade, - IProtocol protocol, - ToolkitConfiguration toolkitConfiguration, - KeyMappingContext keyMappingContext - ): base(logger, primaryKeyMappingContext, protocol) - { - _logger = logger; - _classFacade = classFacade; - _protocol = protocol; - _toolkitConfiguration = toolkitConfiguration; - _keyMappingContext = keyMappingContext; - } - - - protected override MediaFileInfo? CreateNewInstance(MediaFileInfoMapperSource source, MappingHelper mappingHelper, AddFailure addFailure) { - if (source.File != null) - { - var mf = new MediaFileInfo(source.File, source.TargetLibraryId, source.LibrarySubFolder ?? "", 0, 0, 0); - mf.SaveFileToDisk(true); - return mf; - } - - return new MediaFileInfo(); - } - - protected override MediaFileInfo MapInternal(MediaFileInfoMapperSource args, MediaFileInfo target, bool newInstance, MappingHelper mappingHelper, AddFailure addFailure) - { - var (mediaFile, targetLibraryId, file, _, migrateOnlyMediaFileInfo) = args; - - target.FileName = mediaFile.FileName; - target.FileTitle = mediaFile.FileTitle; - target.FileDescription = mediaFile.FileDescription; - target.FileExtension = mediaFile.FileExtension; - target.FileMimeType = mediaFile.FileMimeType; - target.FileSize = mediaFile.FileSize; - target.FileImageWidth = mediaFile.FileImageWidth ?? 0; - target.FileImageHeight = mediaFile.FileImageHeight ?? 0; - target.FileGUID = mediaFile.FileGuid; - target.FileCreatedWhen = mediaFile.FileCreatedWhen; - target.FileModifiedWhen = mediaFile.FileModifiedWhen; - KenticoHelper.CopyCustomData(target.FileCustomData, mediaFile.FileCustomData); - - MigrateCustomizedFields(target, mediaFile); - - target.FileLibraryID = targetLibraryId; - - var targetCreatedMemberId = _keyMappingContext.MapSourceKey( - s => s.UserId, - s => s.UserGuid, - mediaFile.FileCreatedByUserId, - t => t.MemberId, - t => t.MemberGuid - ); - if (targetCreatedMemberId.Success) - { - // user was migrated to MEMBER => setting user would break foreign key - target.SetValue(nameof(target.FileCreatedByUserID), CMSActionContext.CurrentUser.UserID); - } - else if (mappingHelper.TranslateIdAllowNulls(c => c.UserId, mediaFile.FileCreatedByUserId, out var createdByUserId)) - { - target.SetValue(nameof(target.FileCreatedByUserID), createdByUserId); - } - - var targetModifiedMemberId = _keyMappingContext.MapSourceKey( - s => s.UserId, - s => s.UserGuid, - mediaFile.FileModifiedByUserId, - t => t.MemberId, - t => t.MemberGuid - ); - if (targetModifiedMemberId.Success) - { - // user was migrated to MEMBER => setting user would break foreign key - target.SetValue(nameof(target.FileModifiedByUserID), CMSActionContext.CurrentUser.UserID); - } - else if (mappingHelper.TranslateIdAllowNulls(c => c.UserId, mediaFile.FileModifiedByUserId, out var modifiedByUserId)) - { - target.SetValue(nameof(target.FileModifiedByUserID), modifiedByUserId); - } - - if (string.IsNullOrWhiteSpace(target.FilePath)) - { - target.FilePath = mediaFile.FilePath; - } - - if (file == null && !migrateOnlyMediaFileInfo) - { - addFailure(HandbookReferences.MediaFileIsMissingOnSourceFilesystem - .WithId(nameof(mediaFile.FileId), mediaFile.FileId) - .WithData(new - { - mediaFile.FilePath, - mediaFile.FileGuid, - mediaFile.FileLibraryId, - mediaFile.FileSiteId - }) - .AsFailure() - ); - } - - return target; - } - - private void MigrateCustomizedFields(MediaFileInfo target, MediaFile mediaFile) - { - var customizedFields = _classFacade.GetCustomizedFieldInfos(MediaFileInfo.TYPEINFO.ObjectClassName).ToList(); - if (customizedFields.Count <= 0) return; - - try - { - var query = - $"SELECT {string.Join(", ", customizedFields.Select(x => x.FieldName))} FROM {MediaFileInfo.TYPEINFO.ClassStructureInfo.TableName} WHERE {MediaFileInfo.TYPEINFO.ClassStructureInfo.IDColumn} = @id"; - - using var conn = new SqlConnection(_toolkitConfiguration.KxConnectionString); - using var cmd = conn.CreateCommand(); - - cmd.CommandText = query; - cmd.CommandType = CommandType.Text; - cmd.CommandTimeout = 3; - cmd.Parameters.AddWithValue("id", mediaFile.FileId); - - conn.Open(); - - using var reader = cmd.ExecuteReader(); - if (reader.Read()) - { - foreach (var customizedFieldInfo in customizedFields) - { - _logger.LogDebug("Map customized field '{FieldName}'", customizedFieldInfo.FieldName); - target.SetValue(customizedFieldInfo.FieldName, reader.GetValue(customizedFieldInfo.FieldName)); - } - } - else - { - // failed! - _logger.LogError("Failed to load MediaFileInfo custom data from source database"); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to load MediaFileInfo custom data from source database"); - } - } -} \ No newline at end of file diff --git a/Migration.Toolkit.Core.KX13/Mappers/MediaLibraryInfoMapper.cs b/Migration.Toolkit.Core.KX13/Mappers/MediaLibraryInfoMapper.cs deleted file mode 100644 index 4f5d70f9..00000000 --- a/Migration.Toolkit.Core.KX13/Mappers/MediaLibraryInfoMapper.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Migration.Toolkit.Core.KX13.Mappers; - -using CMS.MediaLibrary; -using Microsoft.Extensions.Logging; -using Migration.Toolkit.Common.Abstractions; -using Migration.Toolkit.Common.MigrationProtocol; -using Migration.Toolkit.Core.KX13.Contexts; - -public class MediaLibraryInfoMapper : EntityMapperBase -{ - public MediaLibraryInfoMapper( - ILogger logger, - PrimaryKeyMappingContext primaryKeyMappingContext, - IProtocol protocol - ) : base(logger, primaryKeyMappingContext, protocol) - { - } - - protected override MediaLibraryInfo? CreateNewInstance(Toolkit.KX13.Models.MediaLibrary source, MappingHelper mappingHelper, AddFailure addFailure) => - MediaLibraryInfo.New(); - - protected override MediaLibraryInfo MapInternal(Toolkit.KX13.Models.MediaLibrary source, MediaLibraryInfo target, bool newInstance, MappingHelper mappingHelper, AddFailure addFailure) - { - // Sets the library properties - target.LibraryDisplayName = source.LibraryDisplayName; - target.LibraryName = source.LibraryName; - target.LibraryDescription = source.LibraryDescription; - target.LibraryFolder = source.LibraryFolder; - target.LibraryGUID = mappingHelper.Require(source.LibraryGuid, nameof(source.LibraryGuid)); - target.LibraryDisplayName = source.LibraryDisplayName; - target.LibraryDescription = source.LibraryDescription; - - if (!target.LibraryFolder.StartsWith($"{source.LibrarySite.SiteName}_", StringComparison.InvariantCultureIgnoreCase)) - { - target.LibraryFolder = $"{source.LibrarySite.SiteName}_{source.LibraryFolder}"; - } - - target.LibraryLastModified = mappingHelper.Require(source.LibraryLastModified, nameof(source.LibraryLastModified)); - - return target; - } -} \ No newline at end of file diff --git a/Migration.Toolkit.KXP.Api/Auxiliary/UserHelper.cs b/Migration.Toolkit.KXP.Api/Auxiliary/UserHelper.cs new file mode 100644 index 00000000..ce3b155e --- /dev/null +++ b/Migration.Toolkit.KXP.Api/Auxiliary/UserHelper.cs @@ -0,0 +1,9 @@ +namespace Migration.Toolkit.KXP.Api.Auxiliary; + +using Migration.Toolkit.KXP.Api.Enums; + +public class UserHelper +{ + public static int[] PrivilegeLevelsMigratedAsAdminUser => [(int)UserPrivilegeLevelEnum.Editor, (int)UserPrivilegeLevelEnum.Admin, (int)UserPrivilegeLevelEnum.GlobalAdmin]; + public static int[] PrivilegeLevelsMigratedAsMemberUser => [(int)UserPrivilegeLevelEnum.None]; +} \ No newline at end of file