diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index 0bc9715c..f0c6e881 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -12,6 +12,7 @@ using DtoImporterService; using FileManager; using LibationFileManager; using Newtonsoft.Json.Linq; +using NPOI.OpenXmlFormats.Spreadsheet; using Serilog; using static DtoImporterService.PerfLogger; @@ -261,26 +262,43 @@ namespace ApplicationServices logTime($"pre scanAccountAsync {account.AccountName}"); - var dtoItems = await apiExtended.GetLibraryValidatedAsync(libraryOptions, Configuration.Instance.ImportEpisodes); - - if (archiver is not null) + try { - var fileName = $"{DateTime.Now:u} {account.MaskedLogEntry}.json"; - var items = await Task.Run(() => JArray.FromObject(dtoItems.Select(i => i.SourceJson))); + var dtoItems = await apiExtended.GetLibraryValidatedAsync(libraryOptions, Configuration.Instance.ImportEpisodes); - var scanFile = new JObject - { - { "Account", account.MaskedLogEntry }, - { "ScannedDateTime", DateTime.Now.ToString("u") }, - { "Items", items} - }; + logTime($"post scanAccountAsync {account.AccountName} qty: {dtoItems.Count}"); + + await logDtoItemsAsync(dtoItems); - await archiver.AddFileAsync(fileName, scanFile); + return dtoItems.Select(d => new ImportItem { DtoItem = d, AccountId = account.AccountId, LocaleName = account.Locale?.Name }).ToList(); + } + catch(ImportValidationException ex) + { + await logDtoItemsAsync(ex.Items, ex.InnerExceptions.ToArray()); + throw; + } + + async Task logDtoItemsAsync(IEnumerable dtoItems, IEnumerable exceptions = null) + { + if (archiver is not null) + { + var fileName = $"{DateTime.Now:u} {account.MaskedLogEntry}.json"; + var items = await Task.Run(() => JArray.FromObject(dtoItems.Select(i => i.SourceJson))); + + var scanFile = new JObject + { + { "Account", account.MaskedLogEntry }, + { "ScannedDateTime", DateTime.Now.ToString("u") }, + }; + + if (exceptions?.Any() is true) + scanFile.Add("Exceptions", JArray.FromObject(exceptions)); + + scanFile.Add("Items", items); + + await archiver.AddFileAsync(fileName, scanFile); + } } - - logTime($"post scanAccountAsync {account.AccountName} qty: {dtoItems.Count}"); - - return dtoItems.Select(d => new ImportItem { DtoItem = d, AccountId = account.AccountId, LocaleName = account.Locale?.Name }).ToList(); } private static async Task importIntoDbAsync(List importItems) diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs index 2c77a971..9edecd6b 100644 --- a/Source/AudibleUtilities/ApiExtended.cs +++ b/Source/AudibleUtilities/ApiExtended.cs @@ -157,27 +157,13 @@ namespace AudibleUtilities Serilog.Log.Logger.Information("Completed indexing series episodes after {elappsed_ms} ms.", sw.ElapsedMilliseconds); Serilog.Log.Logger.Information($"Completed library scan in {totalTime.TotalMilliseconds:F0} ms."); - var validators = new List(); - validators.AddRange(getValidators()); - foreach (var v in validators) - { - var exceptions = v.Validate(items); - if (exceptions is not null && exceptions.Any()) - throw new AggregateException(exceptions); - } + var allExceptions = IValidator.GetAllValidators().SelectMany(v => v.Validate(items)); + if (allExceptions?.Any() is true) + throw new ImportValidationException(items, allExceptions); + return items; } - private static List getValidators() - { - var type = typeof(IValidator); - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(p => type.IsAssignableFrom(p) && !p.IsInterface); - - return types.Select(t => Activator.CreateInstance(t) as IValidator).ToList(); - } - #region episodes and podcasts /// diff --git a/Source/AudibleUtilities/AudibleApiValidators.cs b/Source/AudibleUtilities/AudibleApiValidators.cs index cae6e812..6ae9269a 100644 --- a/Source/AudibleUtilities/AudibleApiValidators.cs +++ b/Source/AudibleUtilities/AudibleApiValidators.cs @@ -8,7 +8,18 @@ namespace AudibleUtilities public interface IValidator { IEnumerable Validate(IEnumerable items); + + public static IValidator[] GetAllValidators() + => new IValidator[] + { + new LibraryValidator(), + new BookValidator(), + new CategoryValidator(), + new ContributorValidator(), + new SeriesValidator(), + }; } + public class LibraryValidator : IValidator { public IEnumerable Validate(IEnumerable items) diff --git a/Source/AudibleUtilities/ImportValidationException.cs b/Source/AudibleUtilities/ImportValidationException.cs new file mode 100644 index 00000000..66db8574 --- /dev/null +++ b/Source/AudibleUtilities/ImportValidationException.cs @@ -0,0 +1,15 @@ +using AudibleApi.Common; +using System; +using System.Collections.Generic; + +namespace AudibleUtilities +{ + public class ImportValidationException : AggregateException + { + public List Items { get; } + public ImportValidationException(List items, IEnumerable exceptions) : base(exceptions) + { + Items = items; + } + } +}