Account to be included on each import item, not just on the aggr group

This commit is contained in:
Robert McRackan 2020-08-26 10:25:24 -04:00
parent 56732a5365
commit 755a7338e9
15 changed files with 150 additions and 71 deletions

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AudibleApi;
using DataLayer;
@ -10,12 +12,17 @@ namespace ApplicationServices
{
public static class LibraryCommands
{
public static async Task<(int totalCount, int newCount)> ImportLibraryAsync(ILoginCallback callback)
// public static async Task<(int totalCount, int newCount)> ImportAccountsAsync(IEnumerable<Account> accounts, ILoginCallback callback)
// {
////throw new NotImplementedException();
//// foreach (var account in accounts)
//// {
//// }
// }
public static async Task<(int totalCount, int newCount)> ImportAccountAsync(Account account, ILoginCallback callback)
{
try
{
var account = AudibleApiStorage.TEST_GetFirstAccount();
Log.Logger.Information("ImportLibraryAsync. {@DebugInfo}", new
{
account.AccountName,
@ -23,12 +30,14 @@ namespace ApplicationServices
LocaleName = account.Locale.Name,
});
var items = await AudibleApiActions.GetAllLibraryItemsAsync(account, callback);
var dtoItems = await AudibleApiActions.GetAllLibraryItemsAsync(account, callback);
var items = dtoItems.Select(d => new ImportItem { DtoItem = d, Account = account }).ToList();
var totalCount = items.Count;
Log.Logger.Information($"GetAllLibraryItems: Total count {totalCount}");
using var context = DbContexts.GetContext();
var libraryImporter = new LibraryImporter(context, account);
var libraryImporter = new LibraryImporter(context);
var newCount = await Task.Run(() => libraryImporter.Import(items));
context.SaveChanges();
Log.Logger.Information($"Import: New count {newCount}");

View File

@ -9,25 +9,25 @@ namespace DtoImporterService
{
public class BookImporter : ItemsImporterBase
{
public BookImporter(LibationContext context, Account account) : base(context, account) { }
public BookImporter(LibationContext context) : base(context) { }
public override IEnumerable<Exception> Validate(IEnumerable<Item> items) => new BookValidator().Validate(items);
public override IEnumerable<Exception> Validate(IEnumerable<ImportItem> importItems) => new BookValidator().Validate(importItems.Select(i => i.DtoItem));
protected override int DoImport(IEnumerable<Item> items)
protected override int DoImport(IEnumerable<ImportItem> importItems)
{
// pre-req.s
new ContributorImporter(DbContext, Account).Import(items);
new SeriesImporter(DbContext, Account).Import(items);
new CategoryImporter(DbContext, Account).Import(items);
new ContributorImporter(DbContext).Import(importItems);
new SeriesImporter(DbContext).Import(importItems);
new CategoryImporter(DbContext).Import(importItems);
// get distinct
var productIds = items.Select(i => i.ProductId).ToList();
var productIds = importItems.Select(i => i.DtoItem.ProductId).ToList();
// load db existing => .Local
loadLocal_books(productIds);
// upsert
var qtyNew = upsertBooks(items);
var qtyNew = upsertBooks(importItems);
return qtyNew;
}
@ -44,13 +44,13 @@ namespace DtoImporterService
DbContext.Books.GetBooks(b => remainingProductIds.Contains(b.AudibleProductId)).ToList();
}
private int upsertBooks(IEnumerable<Item> items)
private int upsertBooks(IEnumerable<ImportItem> importItems)
{
var qtyNew = 0;
foreach (var item in items)
foreach (var item in importItems)
{
var book = DbContext.Books.Local.SingleOrDefault(p => p.AudibleProductId == item.ProductId);
var book = DbContext.Books.Local.SingleOrDefault(p => p.AudibleProductId == item.DtoItem.ProductId);
if (book is null)
{
book = createNewBook(item);
@ -63,8 +63,10 @@ namespace DtoImporterService
return qtyNew;
}
private Book createNewBook(Item item)
private Book createNewBook(ImportItem importItem)
{
var item = importItem.DtoItem;
// absence of authors is very rare, but possible
if (!item.Authors?.Any() ?? true)
item.Authors = new[] { new Person { Name = "", Asin = null } };
@ -106,7 +108,7 @@ namespace DtoImporterService
authors,
narrators,
category,
Account.Locale.Name)
importItem.Account.Locale.Name)
).Entity;
var publisherName = item.Publisher;
@ -124,14 +126,16 @@ namespace DtoImporterService
return book;
}
private void updateBook(Item item, Book book)
private void updateBook(ImportItem importItem, Book book)
{
var item = importItem.DtoItem;
// set/update book-specific info which may have changed
book.PictureId = item.PictureId;
book.UpdateProductRating(item.Product_OverallStars, item.Product_PerformanceStars, item.Product_StoryStars);
// needed during v3 => v4 migration
book.UpdateLocale(Account.Locale.Name);
book.UpdateLocale(importItem.Account.Locale.Name);
// important to update user-specific info. this will have changed if user has rated/reviewed the book since last library import
book.UserDefinedItem.UpdateRating(item.MyUserRating_Overall, item.MyUserRating_Performance, item.MyUserRating_Story);

View File

@ -9,20 +9,26 @@ namespace DtoImporterService
{
public class CategoryImporter : ItemsImporterBase
{
public CategoryImporter(LibationContext context, Account account) : base(context, account) { }
public CategoryImporter(LibationContext context) : base(context) { }
public override IEnumerable<Exception> Validate(IEnumerable<Item> items) => new CategoryValidator().Validate(items);
public override IEnumerable<Exception> Validate(IEnumerable<ImportItem> importItems) => new CategoryValidator().Validate(importItems.Select(i => i.DtoItem));
protected override int DoImport(IEnumerable<Item> items)
protected override int DoImport(IEnumerable<ImportItem> importItems)
{
// get distinct
var categoryIds = items.GetCategoriesDistinct().Select(c => c.CategoryId).ToList();
var categoryIds = importItems
.Select(i => i.DtoItem)
.GetCategoriesDistinct()
.Select(c => c.CategoryId).ToList();
// load db existing => .Local
loadLocal_categories(categoryIds);
// upsert
var categoryPairs = items.GetCategoryPairsDistinct().ToList();
var categoryPairs = importItems
.Select(i => i.DtoItem)
.GetCategoryPairsDistinct()
.ToList();
var qtyNew = upsertCategories(categoryPairs);
return qtyNew;
}

View File

@ -9,16 +9,25 @@ namespace DtoImporterService
{
public class ContributorImporter : ItemsImporterBase
{
public ContributorImporter(LibationContext context, Account account) : base(context, account) { }
public ContributorImporter(LibationContext context) : base(context) { }
public override IEnumerable<Exception> Validate(IEnumerable<Item> items) => new ContributorValidator().Validate(items);
public override IEnumerable<Exception> Validate(IEnumerable<ImportItem> importItems) => new ContributorValidator().Validate(importItems.Select(i => i.DtoItem));
protected override int DoImport(IEnumerable<Item> items)
protected override int DoImport(IEnumerable<ImportItem> importItems)
{
// get distinct
var authors = items.GetAuthorsDistinct().ToList();
var narrators = items.GetNarratorsDistinct().ToList();
var publishers = items.GetPublishersDistinct().ToList();
var authors = importItems
.Select(i => i.DtoItem)
.GetAuthorsDistinct()
.ToList();
var narrators = importItems
.Select(i => i.DtoItem)
.GetNarratorsDistinct()
.ToList();
var publishers = importItems
.Select(i => i.DtoItem)
.GetPublishersDistinct()
.ToList();
// load db existing => .Local
var allNames = publishers

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AudibleApiDTOs;
using DataLayer;
using Dinah.Core;
using InternalUtilities;
@ -11,15 +10,11 @@ namespace DtoImporterService
public abstract class ImporterBase<T>
{
protected LibationContext DbContext { get; }
protected Account Account { get; }
protected ImporterBase(LibationContext context, Account account)
protected ImporterBase(LibationContext context)
{
ArgumentValidator.EnsureNotNull(context, nameof(context));
ArgumentValidator.EnsureNotNull(account, nameof(account));
DbContext = context;
Account = account;
}
/// <summary>LONG RUNNING. call with await Task.Run</summary>
@ -55,8 +50,8 @@ namespace DtoImporterService
public abstract IEnumerable<Exception> Validate(T param);
}
public abstract class ItemsImporterBase : ImporterBase<IEnumerable<Item>>
public abstract class ItemsImporterBase : ImporterBase<IEnumerable<ImportItem>>
{
protected ItemsImporterBase(LibationContext context, Account account) : base(context, account) { }
protected ItemsImporterBase(LibationContext context) : base(context) { }
}
}

View File

@ -9,19 +9,19 @@ namespace DtoImporterService
{
public class LibraryImporter : ItemsImporterBase
{
public LibraryImporter(LibationContext context, Account account) : base(context, account) { }
public LibraryImporter(LibationContext context) : base(context) { }
public override IEnumerable<Exception> Validate(IEnumerable<Item> items) => new LibraryValidator().Validate(items);
public override IEnumerable<Exception> Validate(IEnumerable<ImportItem> importItems) => new LibraryValidator().Validate(importItems.Select(i => i.DtoItem));
protected override int DoImport(IEnumerable<Item> items)
protected override int DoImport(IEnumerable<ImportItem> importItems)
{
new BookImporter(DbContext, Account).Import(items);
new BookImporter(DbContext).Import(importItems);
var qtyNew = upsertLibraryBooks(items);
var qtyNew = upsertLibraryBooks(importItems);
return qtyNew;
}
private int upsertLibraryBooks(IEnumerable<Item> items)
private int upsertLibraryBooks(IEnumerable<ImportItem> importItems)
{
// technically, we should be able to have duplicate books from separate accounts.
// this would violate the current pk and would be difficult to deal with elsewhere:
@ -35,21 +35,25 @@ namespace DtoImporterService
// CURRENT SOLUTION: don't re-insert
var currentLibraryProductIds = DbContext.Library.Select(l => l.Book.AudibleProductId).ToList();
var newItems = items.Where(dto => !currentLibraryProductIds.Contains(dto.ProductId)).ToList();
var newItems = importItems.Where(dto => !currentLibraryProductIds.Contains(dto.DtoItem.ProductId)).ToList();
foreach (var newItem in newItems)
{
var libraryBook = new LibraryBook(
DbContext.Books.Local.Single(b => b.AudibleProductId == newItem.ProductId),
newItem.DateAdded,
Account.AccountId);
DbContext.Books.Local.Single(b => b.AudibleProductId == newItem.DtoItem.ProductId),
newItem.DtoItem.DateAdded,
newItem.Account.AccountId);
DbContext.Library.Add(libraryBook);
}
// needed for v3 => v4 upgrade
var toUpdate = DbContext.Library.Where(l => l.Account == null);
foreach (var u in toUpdate)
u.UpdateAccount(Account.AccountId);
{
var item = importItems.FirstOrDefault(ii => ii.DtoItem.ProductId == u.Book.AudibleProductId);
if (item != null)
u.UpdateAccount(item.Account.AccountId);
}
var qtyNew = newItems.Count;
return qtyNew;

View File

@ -9,14 +9,17 @@ namespace DtoImporterService
{
public class SeriesImporter : ItemsImporterBase
{
public SeriesImporter(LibationContext context, Account account) : base(context, account) { }
public SeriesImporter(LibationContext context) : base(context) { }
public override IEnumerable<Exception> Validate(IEnumerable<Item> items) => new SeriesValidator().Validate(items);
public override IEnumerable<Exception> Validate(IEnumerable<ImportItem> importItems) => new SeriesValidator().Validate(importItems.Select(i => i.DtoItem));
protected override int DoImport(IEnumerable<Item> items)
protected override int DoImport(IEnumerable<ImportItem> importItems)
{
// get distinct
var series = items.GetSeriesDistinct().ToList();
var series = importItems
.Select(i => i.DtoItem)
.GetSeriesDistinct()
.ToList();
// load db existing => .Local
loadLocal_series(series);

View File

@ -0,0 +1,18 @@
using System;
using AudibleApiDTOs;
namespace InternalUtilities
{
public class ImportItem
{
public Item DtoItem { get; set; }
public Account Account { get; set; }
public ImportItem() { }
public ImportItem(Item dtoItem, Account account)
{
DtoItem = dtoItem;
Account = account;
}
}
}

View File

@ -13,7 +13,7 @@
<!-- <PublishSingleFile>true</PublishSingleFile> -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<Version>3.1.12.280</Version>
<Version>3.1.12.288</Version>
</PropertyGroup>
<ItemGroup>

View File

@ -111,6 +111,7 @@ namespace LibationWinForms.Dialogs
persister.CommitTransation();
this.DialogResult = DialogResult.OK;
this.Close();
}
catch (Exception ex)

View File

@ -16,11 +16,11 @@ namespace LibationWinForms.Dialogs
this.Shown += IndexLibraryDialog_Shown;
}
private async void IndexLibraryDialog_Shown(object sender, System.EventArgs e)
private async void IndexLibraryDialog_Shown(object sender, EventArgs e)
{
try
{
(TotalBooksProcessed, NewBooksAdded) = await LibraryCommands.ImportLibraryAsync(new WinformResponder());
(TotalBooksProcessed, NewBooksAdded) = await LibraryCommands.ImportAccountAsync(InternalUtilities.AudibleApiStorage.TEST_GetFirstAccount(), new WinformResponder());
}
catch
{

View File

@ -51,13 +51,13 @@
this.accountsClb.FormattingEnabled = true;
this.accountsClb.Location = new System.Drawing.Point(12, 25);
this.accountsClb.Name = "accountsClb";
this.accountsClb.Size = new System.Drawing.Size(265, 94);
this.accountsClb.Size = new System.Drawing.Size(560, 94);
this.accountsClb.TabIndex = 1;
//
// importBtn
//
this.importBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.importBtn.Location = new System.Drawing.Point(101, 125);
this.importBtn.Location = new System.Drawing.Point(396, 125);
this.importBtn.Name = "importBtn";
this.importBtn.Size = new System.Drawing.Size(75, 23);
this.importBtn.TabIndex = 2;
@ -69,7 +69,7 @@
//
this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelBtn.Location = new System.Drawing.Point(202, 125);
this.cancelBtn.Location = new System.Drawing.Point(497, 125);
this.cancelBtn.Name = "cancelBtn";
this.cancelBtn.Size = new System.Drawing.Size(75, 23);
this.cancelBtn.TabIndex = 3;
@ -83,13 +83,14 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelBtn;
this.ClientSize = new System.Drawing.Size(289, 160);
this.ClientSize = new System.Drawing.Size(584, 160);
this.Controls.Add(this.cancelBtn);
this.Controls.Add(this.importBtn);
this.Controls.Add(this.accountsClb);
this.Controls.Add(this.accountsLbl);
this.Name = "ScanAccountsDialog";
this.Text = "Which accounts?";
this.Load += new System.EventHandler(this.ScanAccountsDialog_Load);
this.ResumeLayout(false);
this.PerformLayout();

View File

@ -1,28 +1,46 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using InternalUtilities;
namespace LibationWinForms.Dialogs
{
public partial class ScanAccountsDialog : Form
{
public List<Account> CheckedAccounts { get; } = new List<Account>();
public ScanAccountsDialog()
{
InitializeComponent();
}
class listItem
{
public Account Account { get; set; }
public string Text { get; set; }
public override string ToString() => Text;
}
private void ScanAccountsDialog_Load(object sender, EventArgs e)
{
var accounts = AudibleApiStorage.GetPersistentAccountsSettings().Accounts;
foreach (var account in accounts)
{
var item = new listItem { Account=account,Text = $"{account.AccountName} ({account.AccountId} - {account.Locale.Name})" };
this.accountsClb.Items.Add(item, account.LibraryScan);
}
}
private void importBtn_Click(object sender, EventArgs e)
{
foreach (listItem item in accountsClb.CheckedItems)
CheckedAccounts.Add(item.Account);
// this.Close();
this.DialogResult = DialogResult.OK;
this.Close();
}
private void cancelBtn_Click(object sender, EventArgs e) => this.Close();

View File

@ -258,6 +258,17 @@ private void scanLibraryOfAllAccountsToolStripMenuItem_Click(object sender, Even
private void scanLibraryOfSomeAccountsToolStripMenuItem_Click(object sender, EventArgs e)
{
using var scanAccountsDialog = new ScanAccountsDialog();
if (scanAccountsDialog.ShowDialog() != DialogResult.OK)
return;
if (!scanAccountsDialog.CheckedAccounts.Any())
return;
var checkedAccounts = scanAccountsDialog.CheckedAccounts;
}
#endregion

View File

@ -51,13 +51,13 @@
this.accountsClb.FormattingEnabled = true;
this.accountsClb.Location = new System.Drawing.Point(12, 25);
this.accountsClb.Name = "accountsClb";
this.accountsClb.Size = new System.Drawing.Size(265, 94);
this.accountsClb.Size = new System.Drawing.Size(560, 94);
this.accountsClb.TabIndex = 1;
//
// importBtn
//
this.importBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.importBtn.Location = new System.Drawing.Point(101, 125);
this.importBtn.Location = new System.Drawing.Point(396, 125);
this.importBtn.Name = "importBtn";
this.importBtn.Size = new System.Drawing.Size(75, 23);
this.importBtn.TabIndex = 2;
@ -68,7 +68,7 @@
//
this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelBtn.Location = new System.Drawing.Point(202, 125);
this.cancelBtn.Location = new System.Drawing.Point(497, 125);
this.cancelBtn.Name = "cancelBtn";
this.cancelBtn.Size = new System.Drawing.Size(75, 23);
this.cancelBtn.TabIndex = 3;
@ -81,7 +81,7 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelBtn;
this.ClientSize = new System.Drawing.Size(289, 160);
this.ClientSize = new System.Drawing.Size(584, 160);
this.Controls.Add(this.cancelBtn);
this.Controls.Add(this.importBtn);
this.Controls.Add(this.accountsClb);