using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MimeKit; using Serilog; using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Interfaces; using Wino.Services.Extensions; namespace Wino.Services; public class ContactService : BaseDatabaseService, IContactService { public ContactService(IDatabaseService databaseService) : base(databaseService) { } public async Task CreateNewContactAsync(string address, string displayName) { var contact = new AccountContact() { Address = address, Name = displayName }; await Connection.InsertAsync(contact, typeof(AccountContact)).ConfigureAwait(false); return contact; } public Task> GetAddressInformationAsync(string queryText) { if (queryText == null || queryText.Length < 2) return Task.FromResult>(null); const string query = "SELECT * FROM AccountContact WHERE Address LIKE ? OR Name LIKE ?"; var pattern = $"%{queryText}%"; return Connection.QueryAsync(query, pattern, pattern); } public Task GetAddressInformationByAddressAsync(string address) => Connection.Table().FirstOrDefaultAsync(a => a.Address == address); public async Task SaveAddressInformationAsync(MimeMessage message) { var recipients = message .GetRecipients(true) .Where(a => !string.IsNullOrEmpty(a.Name) && !string.IsNullOrEmpty(a.Address)); var addressInformations = recipients.Select(a => new AccountContact() { Name = a.Name, Address = a.Address }); foreach (var info in addressInformations) { var currentContact = await GetAddressInformationByAddressAsync(info.Address).ConfigureAwait(false); try { if (currentContact == null) { await Connection.InsertAsync(info, typeof(AccountContact)).ConfigureAwait(false); } else if (!currentContact.IsRootContact && !currentContact.IsOverridden) // Don't update root contacts or overridden contacts. { await Connection.InsertOrReplaceAsync(info, typeof(AccountContact)).ConfigureAwait(false); } } catch (Exception ex) { Log.Error("Failed to add contact information to the database.", ex); } } } public Task> GetAllContactsAsync() { return Connection.Table().ToListAsync(); } public Task> SearchContactsAsync(string searchQuery) { if (string.IsNullOrWhiteSpace(searchQuery)) return GetAllContactsAsync(); const string query = "SELECT * FROM AccountContact WHERE Address LIKE ? OR Name LIKE ?"; var pattern = $"%{searchQuery.Trim()}%"; return Connection.QueryAsync(query, pattern, pattern); } public async Task UpdateContactAsync(AccountContact contact) { // Mark the contact as overridden when manually updated contact.IsOverridden = true; await Connection.UpdateAsync(contact, typeof(AccountContact)).ConfigureAwait(false); return contact; } public async Task DeleteContactAsync(string address) { var contact = await GetAddressInformationByAddressAsync(address).ConfigureAwait(false); if (contact != null && !contact.IsRootContact) { await Connection.DeleteAsync(contact.Address).ConfigureAwait(false); } } public async Task DeleteContactsAsync(IEnumerable addresses) { foreach (var address in addresses) { await DeleteContactAsync(address).ConfigureAwait(false); } } }