93 lines
4.3 KiB
C#
93 lines
4.3 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using MongoDB.Driver;
|
|
using QuestionsApi.Models;
|
|
using System.Text.Json;
|
|
|
|
namespace QuestionsApi.Services;
|
|
|
|
public static class CcsPromotionCommand
|
|
{
|
|
public static async Task<int> RunAsync(string[] args, TextWriter output)
|
|
{
|
|
var apply = args.Contains("--apply", StringComparer.OrdinalIgnoreCase);
|
|
var sourceIndex = Array.FindIndex(args, value => value.Equals("--source", StringComparison.OrdinalIgnoreCase));
|
|
var source = sourceIndex >= 0 && sourceIndex + 1 < args.Length
|
|
? args[sourceIndex + 1]
|
|
: Path.Combine(AppContext.BaseDirectory, "content", "ccs");
|
|
var files = File.Exists(source)
|
|
? new[] { source }
|
|
: Directory.Exists(source)
|
|
? Directory.EnumerateFiles(source, "*.json", SearchOption.AllDirectories).ToArray()
|
|
: [];
|
|
if (files.Length == 0)
|
|
{
|
|
await output.WriteLineAsync($"CCS content not found: {source}");
|
|
return 2;
|
|
}
|
|
|
|
var json = new JsonSerializerOptions(JsonSerializerDefaults.Web) { PropertyNameCaseInsensitive = true };
|
|
var request = new CcsImportRequest();
|
|
foreach (var file in files)
|
|
{
|
|
var parsed = JsonSerializer.Deserialize<CcsImportRequest>(await File.ReadAllTextAsync(file), json)
|
|
?? throw new InvalidDataException($"Could not parse CCS content: {file}");
|
|
request.Orders.AddRange(parsed.Orders);
|
|
request.Cases.AddRange(parsed.Cases);
|
|
}
|
|
var duplicateOrders = request.Orders.GroupBy(value => value.Code, StringComparer.OrdinalIgnoreCase)
|
|
.Where(value => value.Count() > 1).Select(value => value.Key).ToList();
|
|
if (duplicateOrders.Count > 0)
|
|
throw new InvalidDataException($"Duplicate CCS order codes: {string.Join(", ", duplicateOrders)}");
|
|
|
|
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true)
|
|
.AddEnvironmentVariables().Build();
|
|
var mongo = new MongoDatabaseProvider(configuration);
|
|
var orders = mongo.Database.GetCollection<CcsOrderDefinition>("CcsOrderCatalog");
|
|
var cases = mongo.Database.GetCollection<CcsCaseRevision>("CcsCaseRevisions");
|
|
var existingCodes = (await orders.Find(Builders<CcsOrderDefinition>.Filter.Empty)
|
|
.Project(value => value.Code).ToListAsync()).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
var errors = CcsCaseValidator.ValidateImport(request, existingCodes);
|
|
if (errors.Count > 0)
|
|
{
|
|
foreach (var error in errors) await output.WriteLineAsync(error);
|
|
return 1;
|
|
}
|
|
await output.WriteLineAsync($"Validated {request.Cases.Count} CCS case(s) and {request.Orders.Count} order(s).");
|
|
if (!apply)
|
|
{
|
|
await output.WriteLineAsync("Dry run only. Pass --apply to publish.");
|
|
return 0;
|
|
}
|
|
|
|
foreach (var order in request.Orders)
|
|
{
|
|
order.Code = order.Code.Trim().ToLowerInvariant();
|
|
order.UpdatedUtc = DateTime.UtcNow;
|
|
await orders.ReplaceOneAsync(value => value.Code == order.Code, order, new ReplaceOptions { IsUpsert = true });
|
|
}
|
|
var created = 0;
|
|
var unchanged = 0;
|
|
foreach (var incoming in request.Cases)
|
|
{
|
|
var current = await cases.Find(value => value.ExternalId == incoming.ExternalId && value.IsCurrent)
|
|
.SortByDescending(value => value.Version).FirstOrDefaultAsync();
|
|
if (current is not null && CcsStore.CaseContentDocument(current).Equals(CcsStore.CaseContentDocument(incoming)))
|
|
{
|
|
unchanged++;
|
|
continue;
|
|
}
|
|
if (current is not null)
|
|
await cases.UpdateOneAsync(value => value.Id == current.Id,
|
|
Builders<CcsCaseRevision>.Update.Set(value => value.IsCurrent, false));
|
|
incoming.Id = null;
|
|
incoming.Version = (current?.Version ?? 0) + 1;
|
|
incoming.IsCurrent = true;
|
|
incoming.CreatedUtc = DateTime.UtcNow;
|
|
await cases.InsertOneAsync(incoming);
|
|
created++;
|
|
}
|
|
await output.WriteLineAsync($"Promotion complete: {created} created, {unchanged} unchanged.");
|
|
return 0;
|
|
}
|
|
}
|