Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

#238 ability to extend Migration Tool #257

Merged
merged 7 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ appsettings.local.json
.idea/
.vs/
*.sln.DotSettings.user
Migration.Toolkit.CLI/appsettings.local.json_
Migration.Tool.CLI/appsettings.local.json_
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"editor.defaultFormatter": "ms-dotnettools.csharp"
},

"dotnet.defaultSolution": "Migration.Toolkit.sln",
"dotnet.defaultSolution": "Migration.Tool.sln",

"typescript.validate.enable": false,
"eslint.workingDirectories": [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Collections.Frozen;
using CMS.DataEngine;
using Microsoft.Extensions.Logging;
using Migration.Toolkit.Common.Helpers;
using Migration.Tool.Common.Helpers;

namespace Migration.Toolkit.Source.Auxiliary;
namespace Migration.Tool.Source.Auxiliary;

public interface ISourceGuidContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System.Xml.Linq;

using Migration.Toolkit.Common;
using Migration.Toolkit.Common.Enumerations;
using Migration.Tool.Common;
using Migration.Tool.Common.Enumerations;
// ReSharper disable InconsistentNaming // generated class

namespace Migration.Toolkit.Source.Auxiliary;
namespace Migration.Tool.Source.Auxiliary;

internal class NodeXmlAdapter
{
Expand Down
107 changes: 107 additions & 0 deletions KVA/Migration.Tool.Source/Behaviors/CommandConstraintBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using MediatR;

using Microsoft.Extensions.Logging;

using Migration.Tool.Common.Abstractions;
using Migration.Tool.Common.MigrationProtocol;
using Migration.Tool.Source.Model;

namespace Migration.Tool.Source.Behaviors;

public class CommandConstraintBehavior<TRequest, TResponse>(
ILogger<CommandConstraintBehavior<TRequest, TResponse>> logger,
IMigrationProtocol protocol,
ModelFacade modelFacade)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
where TResponse : CommandResult
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
try
{
bool criticalCheckPassed = PerformChecks(request);
if (!criticalCheckPassed)
{
return (TResponse)(CommandResult)new CommandCheckFailedResult(criticalCheckPassed);
}
}
catch (Exception ex)
{
protocol.CommandError<TRequest, TResponse>(ex, request);
logger.LogCritical(ex, "Error occured while checking command constraints");
return (TResponse)(CommandResult)new CommandCheckFailedResult(false);
}

return await next();
}

private bool PerformChecks(TRequest request)
{
bool criticalCheckPassed = true;

var sourceSites = modelFacade.SelectAll<ICmsSite>()
.ToList();

foreach (var site in sourceSites)
{
criticalCheckPassed &= CheckSite(sourceSites, site.SiteID);
}


if (request is ICultureReliantCommand cultureReliantCommand)
{
var cultures = modelFacade.SelectAll<ICmsCulture>().ToList();
var siteCultures = modelFacade.SelectAll<ICmsSiteCulture>().ToList();
criticalCheckPassed &= CheckCulture(cultureReliantCommand, sourceSites, cultures, siteCultures);
}

return criticalCheckPassed;
}

private bool CheckSite(List<ICmsSite> sourceSites, int sourceSiteId)
{
bool criticalCheckPassed = true;
if (sourceSites.All(s => s.SiteID != sourceSiteId))
{
var supportedSites = sourceSites.Select(x => new { x.SiteName, x.SiteID }).ToArray();
string supportedSitesStr = string.Join(", ", supportedSites.Select(x => x.ToString()));
logger.LogCritical("Unable to find site with ID '{SourceSiteId}'. Check --siteId parameter. Supported sites: {SupportedSites}", sourceSiteId,
supportedSitesStr);
protocol.Append(HandbookReferences.CommandConstraintBroken("Site exists")
.WithMessage("Check program argument '--siteId'")
.WithData(new { sourceSiteId, AvailableSites = supportedSites }));
criticalCheckPassed = false;
}

return criticalCheckPassed;
}

private bool CheckCulture(ICultureReliantCommand cultureReliantCommand, List<ICmsSite> sourceSites, List<ICmsCulture> cultures, List<ICmsSiteCulture> cmsSiteCultures)
{
bool criticalCheckPassed = true;
string cultureCode = cultureReliantCommand.CultureCode;

foreach (var site in sourceSites)
{
string?[] siteCultures = cmsSiteCultures
.Where(x => x.SiteID == site.SiteID)
.Select(x => cultures.FirstOrDefault(c => c.CultureID == x.CultureID)?.CultureCode)
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToArray();

if (!siteCultures.Contains(cultureCode.ToLowerInvariant()))
{
string supportedCultures = string.Join(", ", siteCultures);
logger.LogCritical("Unable to find culture '{Culture}' mapping to site '{SiteId}'. Check --culture parameter. Supported cultures for site: {SupportedCultures}", cultureCode,
site.SiteID, supportedCultures);
protocol.Append(HandbookReferences.CommandConstraintBroken("Culture is mapped to site")
.WithMessage("Check program argument '--culture'")
.WithData(new { cultureCode, site.SiteID, SiteCultures = supportedCultures }));
criticalCheckPassed = false;
}
}

return criticalCheckPassed;
}
}
40 changes: 40 additions & 0 deletions KVA/Migration.Tool.Source/Behaviors/RequestHandlingBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Diagnostics;

using MediatR;

using Microsoft.Extensions.Logging;

using Migration.Tool.Common.Abstractions;
using Migration.Tool.Common.MigrationProtocol;

namespace Migration.Tool.Source.Behaviors;

public class RequestHandlingBehavior<TRequest, TResponse>(
ILogger<RequestHandlingBehavior<TRequest, TResponse>> logger,
IMigrationProtocol protocol) : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
where TResponse : CommandResult
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
var sw = Stopwatch.StartNew();
logger.LogInformation("Handling {CommandName}", typeof(TRequest).Name);
try
{
protocol.CommandRequest<TRequest, TResponse>(request);
var response = await next();
protocol.CommandFinished(request, response);
return response;
}
catch (Exception ex)
{
protocol.CommandError<TRequest, TResponse>(ex, request);
logger.LogError(ex, "Error occured");
throw;
}
finally
{
logger.LogInformation("Handled {CommandName} in elapsed: {Elapsed}", typeof(TRequest).Name, sw.Elapsed);
}
}
}
42 changes: 42 additions & 0 deletions KVA/Migration.Tool.Source/Behaviors/XbKApiContextBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using CMS.Base;
using CMS.Membership;

using MediatR;

using Microsoft.Extensions.Logging;

using Migration.Tool.Common.Abstractions;
using Migration.Tool.Common.MigrationProtocol;
using Migration.Tool.KXP.Api;

namespace Migration.Tool.Source.Behaviors;

public class XbKApiContextBehavior<TRequest, TResponse>(
ILogger<XbKApiContextBehavior<TRequest, TResponse>> logger,
IMigrationProtocol protocol,
KxpApiInitializer initializer)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
where TResponse : CommandResult
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
initializer.EnsureApiIsInitialized();

var defaultAdmin = UserInfoProvider.ProviderObject.Get(UserInfoProvider.DEFAULT_ADMIN_USERNAME);
if (defaultAdmin == null)
{
protocol.Append(HandbookReferences
.MissingRequiredDependency<UserInfo>()
.WithMessage($"Target XbK doesn't contain default administrator account ('{UserInfoProvider.DEFAULT_ADMIN_USERNAME}'). Default administrator account is required for migration.")
);
throw new InvalidOperationException($"Target XbK doesn't contain default administrator account ('{UserInfoProvider.DEFAULT_ADMIN_USERNAME}')");
}

using (new CMSActionContext(defaultAdmin) { User = defaultAdmin, UseGlobalAdminContext = true })
{
logger.LogInformation("Using CMSActionContext of user '{UserName}'", UserInfoProvider.DEFAULT_ADMIN_USERNAME);
return await next();
}
}
}
Loading