Calendar invitations for Mail part of the app.
This commit is contained in:
@@ -12,7 +12,6 @@ using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Messaging.Client.Accounts;
|
||||
using Wino.Messaging.UI;
|
||||
using Wino.Services.Extensions;
|
||||
|
||||
namespace Wino.Services;
|
||||
|
||||
@@ -21,6 +20,7 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
public IAuthenticator ExternalAuthenticationAuthenticator { get; set; }
|
||||
|
||||
private readonly ISignatureService _signatureService;
|
||||
private readonly IAuthenticationProvider _authenticationProvider;
|
||||
private readonly IMimeFileService _mimeFileService;
|
||||
private readonly IPreferencesService _preferencesService;
|
||||
|
||||
@@ -28,10 +28,12 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
|
||||
public AccountService(IDatabaseService databaseService,
|
||||
ISignatureService signatureService,
|
||||
IAuthenticationProvider authenticationProvider,
|
||||
IMimeFileService mimeFileService,
|
||||
IPreferencesService preferencesService) : base(databaseService)
|
||||
{
|
||||
_signatureService = signatureService;
|
||||
_authenticationProvider = authenticationProvider;
|
||||
_mimeFileService = mimeFileService;
|
||||
_preferencesService = preferencesService;
|
||||
}
|
||||
@@ -59,7 +61,7 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
var sql = $"UPDATE MailAccount SET MergedInboxId = ? WHERE Id IN ({placeholders})";
|
||||
var parameters = new List<object> { mergedInboxId };
|
||||
parameters.AddRange(accountIdList.Cast<object>());
|
||||
|
||||
|
||||
await Connection.ExecuteAsync(sql, parameters.ToArray());
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new AccountsMenuRefreshRequested());
|
||||
@@ -193,13 +195,18 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
|
||||
if (account == null) return;
|
||||
|
||||
//var authenticator = _authenticationProvider.GetAuthenticator(account.ProviderType);
|
||||
var authenticator = _authenticationProvider.GetAuthenticator(account.ProviderType);
|
||||
|
||||
//// This will re-generate token.
|
||||
//var token = await authenticator.GenerateTokenInformationAsync(account);
|
||||
// This will re-generate token with interactive authentication
|
||||
// New authentication will include calendar scopes
|
||||
var token = await authenticator.GenerateTokenInformationAsync(account);
|
||||
|
||||
// TODO: Rest?
|
||||
// Guard.IsNotNull(token);
|
||||
Guard.IsNotNull(token);
|
||||
|
||||
// Enable calendar access since new token includes calendar scopes
|
||||
account.IsCalendarAccessGranted = true;
|
||||
|
||||
await UpdateAccountAsync(account);
|
||||
}
|
||||
|
||||
private Task<MailAccountPreferences> GetAccountPreferencesAsync(Guid accountId)
|
||||
|
||||
@@ -111,6 +111,9 @@ public static class MailkitClientExtensions
|
||||
// Use InternalDate (server received date) if available, otherwise fall back to Date header (sent date)
|
||||
var creationDate = messageSummary.InternalDate?.UtcDateTime ?? mime.Date.UtcDateTime;
|
||||
|
||||
// Detect calendar invitation based on MIME content type
|
||||
var itemType = GetMailItemTypeFromMime(mime);
|
||||
|
||||
var copy = new MailCopy()
|
||||
{
|
||||
Id = messageUid,
|
||||
@@ -128,12 +131,49 @@ public static class MailkitClientExtensions
|
||||
References = mime.References?.GetReferences(),
|
||||
InReplyTo = mime.GetInReplyTo(),
|
||||
HasAttachments = mime.Attachments.Any(),
|
||||
FileId = Guid.NewGuid()
|
||||
FileId = Guid.NewGuid(),
|
||||
ItemType = itemType
|
||||
};
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines MailItemType based on MIME message content type.
|
||||
/// Calendar invitations have text/calendar content type with METHOD parameter.
|
||||
/// </summary>
|
||||
private static MailItemType GetMailItemTypeFromMime(MimeMessage mime)
|
||||
{
|
||||
if (mime == null) return MailItemType.Mail;
|
||||
|
||||
// Check if the message contains text/calendar content
|
||||
var calendarPart = mime.BodyParts.OfType<MimePart>()
|
||||
.FirstOrDefault(p => p.ContentType?.MimeType?.Equals("text/calendar", StringComparison.OrdinalIgnoreCase) == true);
|
||||
|
||||
if (calendarPart != null)
|
||||
{
|
||||
// Check the METHOD parameter to determine invitation type
|
||||
var method = calendarPart.ContentType.Parameters
|
||||
.FirstOrDefault(p => p.Name.Equals("method", StringComparison.OrdinalIgnoreCase))?.Value?.ToUpperInvariant();
|
||||
|
||||
if (!string.IsNullOrEmpty(method))
|
||||
{
|
||||
return method switch
|
||||
{
|
||||
"REQUEST" => MailItemType.CalendarInvitation,
|
||||
"CANCEL" => MailItemType.CalendarCancellation,
|
||||
"REPLY" => MailItemType.CalendarResponse,
|
||||
_ => MailItemType.Mail
|
||||
};
|
||||
}
|
||||
|
||||
// If no method specified, assume it's an invitation
|
||||
return MailItemType.CalendarInvitation;
|
||||
}
|
||||
|
||||
return MailItemType.Mail;
|
||||
}
|
||||
|
||||
// TODO: Name and Address parsing should be handled better.
|
||||
// At some point Wino needs better contact management.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user