Add IMAP local calendar operation tests using in-memory DB (#807)
* Add IMAP local calendar operation handler tests * Fix tests. * Fix calendar item show as not updating. * Create one default calendar for local calendar accounts.
This commit is contained in:
@@ -0,0 +1,113 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using Wino.Core.Domain;
|
||||||
|
using Wino.Core.Domain.Entities.Mail;
|
||||||
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Tests.Helpers;
|
||||||
|
using Wino.Services;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Wino.Core.Tests.Services;
|
||||||
|
|
||||||
|
public class AccountServiceTests : IAsyncLifetime
|
||||||
|
{
|
||||||
|
private InMemoryDatabaseService _databaseService = null!;
|
||||||
|
private AccountService _accountService = null!;
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
_databaseService = new InMemoryDatabaseService();
|
||||||
|
await _databaseService.InitializeAsync();
|
||||||
|
_accountService = CreateService(_databaseService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisposeAsync()
|
||||||
|
{
|
||||||
|
await _databaseService.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateAccountAsync_ImapLocalOnly_CreatesSinglePrimaryDefaultCalendar()
|
||||||
|
{
|
||||||
|
var accountId = Guid.NewGuid();
|
||||||
|
var account = CreateImapAccount(accountId);
|
||||||
|
var server = new CustomServerInformation
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
AccountId = accountId,
|
||||||
|
CalendarSupportMode = ImapCalendarSupportMode.LocalOnly
|
||||||
|
};
|
||||||
|
|
||||||
|
await _accountService.CreateAccountAsync(account, server);
|
||||||
|
|
||||||
|
var calendars = await _databaseService.Connection.Table<Wino.Core.Domain.Entities.Calendar.AccountCalendar>()
|
||||||
|
.Where(a => a.AccountId == accountId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
calendars.Should().HaveCount(1);
|
||||||
|
calendars[0].IsPrimary.Should().BeTrue();
|
||||||
|
calendars[0].Name.Should().Be(Translator.AccountDetailsPage_TabCalendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateAccountAsync_ImapCalDav_DoesNotCreateDefaultLocalCalendar()
|
||||||
|
{
|
||||||
|
var accountId = Guid.NewGuid();
|
||||||
|
var account = CreateImapAccount(accountId);
|
||||||
|
var server = new CustomServerInformation
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
AccountId = accountId,
|
||||||
|
CalendarSupportMode = ImapCalendarSupportMode.CalDav
|
||||||
|
};
|
||||||
|
|
||||||
|
await _accountService.CreateAccountAsync(account, server);
|
||||||
|
|
||||||
|
var calendars = await _databaseService.Connection.Table<Wino.Core.Domain.Entities.Calendar.AccountCalendar>()
|
||||||
|
.Where(a => a.AccountId == accountId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
calendars.Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MailAccount CreateImapAccount(Guid accountId)
|
||||||
|
{
|
||||||
|
return new MailAccount
|
||||||
|
{
|
||||||
|
Id = accountId,
|
||||||
|
Name = "IMAP Test Account",
|
||||||
|
Address = "imap@test.local",
|
||||||
|
SenderName = "IMAP Test",
|
||||||
|
ProviderType = MailProviderType.IMAP4
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AccountService CreateService(InMemoryDatabaseService databaseService)
|
||||||
|
{
|
||||||
|
var signatureService = new Mock<ISignatureService>();
|
||||||
|
signatureService
|
||||||
|
.Setup(a => a.CreateDefaultSignatureAsync(It.IsAny<Guid>()))
|
||||||
|
.ReturnsAsync((Guid accountId) => new AccountSignature
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
MailAccountId = accountId,
|
||||||
|
Name = "Default",
|
||||||
|
HtmlBody = string.Empty
|
||||||
|
});
|
||||||
|
|
||||||
|
var authenticationProvider = new Mock<IAuthenticationProvider>();
|
||||||
|
var mimeFileService = new Mock<IMimeFileService>();
|
||||||
|
|
||||||
|
var preferencesService = new Mock<IPreferencesService>();
|
||||||
|
preferencesService.SetupProperty(a => a.StartupEntityId);
|
||||||
|
|
||||||
|
return new AccountService(
|
||||||
|
databaseService,
|
||||||
|
signatureService.Object,
|
||||||
|
authenticationProvider.Object,
|
||||||
|
mimeFileService.Object,
|
||||||
|
preferencesService.Object);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,7 +119,8 @@ public class ImapSynchronizerCalDavConfigurationTests
|
|||||||
unifiedSynchronizer,
|
unifiedSynchronizer,
|
||||||
Mock.Of<IImapSynchronizerErrorHandlerFactory>(),
|
Mock.Of<IImapSynchronizerErrorHandlerFactory>(),
|
||||||
Mock.Of<ICalDavClient>(),
|
Mock.Of<ICalDavClient>(),
|
||||||
autoDiscoveryService ?? Mock.Of<IAutoDiscoveryService>());
|
autoDiscoveryService ?? Mock.Of<IAutoDiscoveryService>(),
|
||||||
|
Mock.Of<ICalendarService>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CustomServerInformation CreateServerInformation()
|
private static CustomServerInformation CreateServerInformation()
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public class ImapSynchronizerIdleTests
|
|||||||
unifiedSynchronizer,
|
unifiedSynchronizer,
|
||||||
Mock.Of<IImapSynchronizerErrorHandlerFactory>(),
|
Mock.Of<IImapSynchronizerErrorHandlerFactory>(),
|
||||||
Mock.Of<ICalDavClient>(),
|
Mock.Of<ICalDavClient>(),
|
||||||
Mock.Of<IAutoDiscoveryService>());
|
Mock.Of<IAutoDiscoveryService>(),
|
||||||
|
Mock.Of<ICalendarService>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public partial class AccountManagementViewModel : AccountManagementPageViewModel
|
|||||||
|
|
||||||
createdAccount.Address = accountCreationDialogResult.SpecialImapProviderDetails.Address;
|
createdAccount.Address = accountCreationDialogResult.SpecialImapProviderDetails.Address;
|
||||||
createdAccount.SenderName = accountCreationDialogResult.SpecialImapProviderDetails.SenderName;
|
createdAccount.SenderName = accountCreationDialogResult.SpecialImapProviderDetails.SenderName;
|
||||||
createdAccount.IsCalendarAccessGranted = customServerInformation.CalendarSupportMode == ImapCalendarSupportMode.CalDav;
|
createdAccount.IsCalendarAccessGranted = customServerInformation.CalendarSupportMode != ImapCalendarSupportMode.Disabled;
|
||||||
createdAccount.ServerInformation = customServerInformation;
|
createdAccount.ServerInformation = customServerInformation;
|
||||||
|
|
||||||
await ValidateSpecialImapConnectivityAsync(customServerInformation).ConfigureAwait(false);
|
await ValidateSpecialImapConnectivityAsync(customServerInformation).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -713,7 +713,7 @@ public partial class ImapCalDavSettingsPageViewModel : MailBaseViewModel
|
|||||||
{
|
{
|
||||||
DisplayName = DisplayName.Trim(),
|
DisplayName = DisplayName.Trim(),
|
||||||
EmailAddress = EmailAddress.Trim(),
|
EmailAddress = EmailAddress.Trim(),
|
||||||
IsCalendarAccessGranted = serverInformation.CalendarSupportMode == ImapCalendarSupportMode.CalDav,
|
IsCalendarAccessGranted = serverInformation.CalendarSupportMode != ImapCalendarSupportMode.Disabled,
|
||||||
ServerInformation = serverInformation
|
ServerInformation = serverInformation
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -735,7 +735,7 @@ public partial class ImapCalDavSettingsPageViewModel : MailBaseViewModel
|
|||||||
|
|
||||||
account.SenderName = DisplayName.Trim();
|
account.SenderName = DisplayName.Trim();
|
||||||
account.Address = EmailAddress.Trim();
|
account.Address = EmailAddress.Trim();
|
||||||
account.IsCalendarAccessGranted = serverInformation.CalendarSupportMode == ImapCalendarSupportMode.CalDav;
|
account.IsCalendarAccessGranted = serverInformation.CalendarSupportMode != ImapCalendarSupportMode.Disabled;
|
||||||
|
|
||||||
serverInformation.Id = account.ServerInformation?.Id ?? Guid.NewGuid();
|
serverInformation.Id = account.ServerInformation?.Id ?? Guid.NewGuid();
|
||||||
serverInformation.AccountId = account.Id;
|
serverInformation.AccountId = account.Id;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
VerticalContentAlignment="Stretch"
|
VerticalContentAlignment="Stretch"
|
||||||
Canvas.ZIndex="10000"
|
Canvas.ZIndex="10000"
|
||||||
Content="{x:Bind CalendarItem}"
|
Content="{x:Bind CalendarItem, Mode=OneWay}"
|
||||||
ContentTemplateSelector="{StaticResource ShowAsStripeSelector}"
|
ContentTemplateSelector="{StaticResource ShowAsStripeSelector}"
|
||||||
IsTabStop="False" />
|
IsTabStop="False" />
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using System.Threading.Tasks;
|
|||||||
using CommunityToolkit.Diagnostics;
|
using CommunityToolkit.Diagnostics;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using Wino.Core.Domain;
|
||||||
|
using Wino.Core.Domain.Entities.Calendar;
|
||||||
using Wino.Core.Domain.Entities.Mail;
|
using Wino.Core.Domain.Entities.Mail;
|
||||||
using Wino.Core.Domain.Entities.Shared;
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
@@ -17,6 +19,22 @@ namespace Wino.Services;
|
|||||||
|
|
||||||
public class AccountService : BaseDatabaseService, IAccountService
|
public class AccountService : BaseDatabaseService, IAccountService
|
||||||
{
|
{
|
||||||
|
private static readonly string[] DefaultCalendarFlatColors =
|
||||||
|
[
|
||||||
|
"#B91C1C",
|
||||||
|
"#15803D",
|
||||||
|
"#0E7490",
|
||||||
|
"#1D4ED8",
|
||||||
|
"#7C3AED",
|
||||||
|
"#C026D3",
|
||||||
|
"#EC4899",
|
||||||
|
"#F97316",
|
||||||
|
"#EAB308",
|
||||||
|
"#22C55E",
|
||||||
|
"#06B6D4",
|
||||||
|
"#60A5FA"
|
||||||
|
];
|
||||||
|
|
||||||
public IAuthenticator ExternalAuthenticationAuthenticator { get; set; }
|
public IAuthenticator ExternalAuthenticationAuthenticator { get; set; }
|
||||||
|
|
||||||
private readonly ISignatureService _signatureService;
|
private readonly ISignatureService _signatureService;
|
||||||
@@ -528,35 +546,49 @@ public class AccountService : BaseDatabaseService, IAccountService
|
|||||||
|
|
||||||
if (customServerInformation != null)
|
if (customServerInformation != null)
|
||||||
await Connection.InsertAsync(customServerInformation, typeof(CustomServerInformation));
|
await Connection.InsertAsync(customServerInformation, typeof(CustomServerInformation));
|
||||||
|
|
||||||
|
if (account.ProviderType == MailProviderType.IMAP4 &&
|
||||||
|
customServerInformation?.CalendarSupportMode == ImapCalendarSupportMode.LocalOnly)
|
||||||
|
{
|
||||||
|
await EnsureDefaultLocalCalendarForImapAsync(account.Id).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public async Task<string> UpdateSynchronizationIdentifierAsync(Guid accountId, string newIdentifier)
|
private async Task EnsureDefaultLocalCalendarForImapAsync(Guid accountId)
|
||||||
//{
|
{
|
||||||
// var account = await GetAccountAsync(accountId);
|
var existingCalendarCount = await Connection.Table<AccountCalendar>()
|
||||||
|
.Where(a => a.AccountId == accountId)
|
||||||
|
.CountAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// if (account == null)
|
if (existingCalendarCount > 0)
|
||||||
// {
|
return;
|
||||||
// _logger.Error("Could not find account with id {AccountId}", accountId);
|
|
||||||
// return string.Empty;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var currentIdentifier = account.SynchronizationDeltaIdentifier;
|
var localCalendar = new AccountCalendar
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
AccountId = accountId,
|
||||||
|
Name = Translator.AccountDetailsPage_TabCalendar,
|
||||||
|
IsPrimary = true,
|
||||||
|
IsSynchronizationEnabled = true,
|
||||||
|
IsExtended = true,
|
||||||
|
RemoteCalendarId = string.Empty,
|
||||||
|
TimeZone = string.Empty,
|
||||||
|
BackgroundColorHex = GetDefaultCalendarFlatColor(accountId),
|
||||||
|
TextColorHex = "#FFFFFF"
|
||||||
|
};
|
||||||
|
|
||||||
// bool shouldUpdateIdentifier = account.ProviderType == MailProviderType.Gmail ?
|
await Connection.InsertAsync(localCalendar, typeof(AccountCalendar)).ConfigureAwait(false);
|
||||||
// string.IsNullOrEmpty(currentIdentifier) ? true : !string.IsNullOrEmpty(currentIdentifier)
|
}
|
||||||
// && ulong.TryParse(currentIdentifier, out ulong currentIdentifierValue)
|
|
||||||
// && ulong.TryParse(newIdentifier, out ulong newIdentifierValue)
|
|
||||||
// && newIdentifierValue > currentIdentifierValue : true;
|
|
||||||
|
|
||||||
// if (shouldUpdateIdentifier)
|
private static string GetDefaultCalendarFlatColor(Guid accountId)
|
||||||
// {
|
{
|
||||||
// account.SynchronizationDeltaIdentifier = newIdentifier;
|
var bytes = accountId.ToByteArray();
|
||||||
|
var hash = BitConverter.ToUInt32(bytes, 0);
|
||||||
|
var index = (int)(hash % (uint)DefaultCalendarFlatColors.Length);
|
||||||
|
|
||||||
// await UpdateAccountAsync(account);
|
return DefaultCalendarFlatColors[index];
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return account.SynchronizationDeltaIdentifier;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public async Task UpdateAccountOrdersAsync(Dictionary<Guid, int> accountIdOrderPair)
|
public async Task UpdateAccountOrdersAsync(Dictionary<Guid, int> accountIdOrderPair)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user