From 8db34289a7c7e1fd293ed9a2856cfaf1f3d0f41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Thu, 29 Aug 2024 23:43:49 +0200 Subject: [PATCH] Fixing single threads for API threading strategy. --- .../Interfaces/IThreadingStrategy.cs | 3 +- .../Models/MailItem/ThreadMailItem.cs | 10 +++-- .../Threading/APIThreadingStrategy.cs | 39 +++++++++++++++++-- .../Threading/ImapThreadStrategy.cs | 3 +- Wino.Core/Services/MailService.cs | 2 +- 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs b/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs index cd0cec9c..8b5c5d14 100644 --- a/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs +++ b/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.MailItem; namespace Wino.Core.Domain.Interfaces @@ -12,7 +13,7 @@ namespace Wino.Core.Domain.Interfaces /// /// Original mails. /// Original mails with thread mails. - Task> ThreadItemsAsync(List items); + Task> ThreadItemsAsync(List items, IMailItemFolder threadingForFolder); bool ShouldThreadWithItem(IMailItem originalItem, IMailItem targetItem); } } diff --git a/Wino.Core.Domain/Models/MailItem/ThreadMailItem.cs b/Wino.Core.Domain/Models/MailItem/ThreadMailItem.cs index 0c59af3a..1b3a486f 100644 --- a/Wino.Core.Domain/Models/MailItem/ThreadMailItem.cs +++ b/Wino.Core.Domain/Models/MailItem/ThreadMailItem.cs @@ -14,19 +14,19 @@ namespace Wino.Core.Domain.Models.MailItem public IMailItem LatestMailItem => ThreadItems.LastOrDefault(); public IMailItem FirstMailItem => ThreadItems.FirstOrDefault(); - public void AddThreadItem(IMailItem item) + public bool AddThreadItem(IMailItem item) { - if (item == null) return; + if (item == null) return false; if (ThreadItems.Any(a => a.Id == item.Id)) { - return; + return false; } if (item != null && item.IsDraft) { ThreadItems.Insert(0, item); - return; + return true; } var insertItem = ThreadItems.FirstOrDefault(a => !a.IsDraft && a.CreationDate < item.CreationDate); @@ -39,6 +39,8 @@ namespace Wino.Core.Domain.Models.MailItem ThreadItems.Insert(index, item); } + + return true; } public IEnumerable GetContainingIds() => ThreadItems?.Select(a => a.UniqueId) ?? default; diff --git a/Wino.Core/Integration/Threading/APIThreadingStrategy.cs b/Wino.Core/Integration/Threading/APIThreadingStrategy.cs index f1258f9d..4d43ff42 100644 --- a/Wino.Core/Integration/Threading/APIThreadingStrategy.cs +++ b/Wino.Core/Integration/Threading/APIThreadingStrategy.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Services; @@ -27,7 +28,7 @@ namespace Wino.Core.Integration.Threading } /// - public async Task> ThreadItemsAsync(List items) + public async Task> ThreadItemsAsync(List items, IMailItemFolder threadingForFolder) { var assignedAccount = items[0].AssignedAccount; @@ -62,11 +63,43 @@ namespace Wino.Core.Integration.Threading } var thread = new ThreadMailItem(); + foreach (var childThreadItem in threadItem) { - thread.AddThreadItem(childThreadItem); + if (thread.ThreadItems.Any(a => a.Id == childThreadItem.Id)) + { + // Mail already exist in the thread. + // There should be only 1 instance of the mail in the thread. + // Make sure we add the correct one. + + // Add the one with threading folder. + var threadingFolderItem = threadItem.FirstOrDefault(a => a.Id == childThreadItem.Id && a.FolderId == threadingForFolder.Id); + + if (threadingFolderItem == null) continue; + + // Remove the existing one. + thread.ThreadItems.Remove(thread.ThreadItems.First(a => a.Id == childThreadItem.Id)); + + // Add the correct one for listing. + thread.AddThreadItem(threadingFolderItem); + } + else + { + thread.AddThreadItem(childThreadItem); + } + } + + if (thread.ThreadItems.Count > 1) + { + resultList.Add(thread); + } + else + { + // Don't make threads if the thread has only one item. + // Gmail has may have multiple assignments for the same item. + + resultList.Add(thread.ThreadItems.First()); } - resultList.Add(thread); } } diff --git a/Wino.Core/Integration/Threading/ImapThreadStrategy.cs b/Wino.Core/Integration/Threading/ImapThreadStrategy.cs index 97aded37..047c4883 100644 --- a/Wino.Core/Integration/Threading/ImapThreadStrategy.cs +++ b/Wino.Core/Integration/Threading/ImapThreadStrategy.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using SqlKata; using Wino.Core.Domain.Entities; using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Extensions; using Wino.Core.Services; @@ -58,7 +59,7 @@ namespace Wino.Core.Integration.Threading return _databaseService.Connection.FindWithQueryAsync(query.GetRawQuery()); } - public async Task> ThreadItemsAsync(List items) + public async Task> ThreadItemsAsync(List items, IMailItemFolder threadingForFolder) { var threads = new List(); diff --git a/Wino.Core/Services/MailService.cs b/Wino.Core/Services/MailService.cs index 4a970593..4a5e16a7 100644 --- a/Wino.Core/Services/MailService.cs +++ b/Wino.Core/Services/MailService.cs @@ -241,7 +241,7 @@ namespace Wino.Core.Services // Only thread items from Draft and Sent folders must present here. // Otherwise this strategy will fetch the items that are in Deleted folder as well. - var accountThreadedItems = await threadingStrategy.ThreadItemsAsync([.. group]); + var accountThreadedItems = await threadingStrategy.ThreadItemsAsync([.. group], options.Folders.First()); // Populate threaded items with folder and account assignments. // Almost everything already should be in cache from initial population.