Handle deleted events.
This commit is contained in:
@@ -12,6 +12,7 @@ public interface ICalendarService
|
|||||||
Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId);
|
Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId);
|
||||||
Task<AccountCalendar> GetAccountCalendarAsync(Guid accountCalendarId);
|
Task<AccountCalendar> GetAccountCalendarAsync(Guid accountCalendarId);
|
||||||
Task DeleteCalendarItemAsync(Guid calendarItemId);
|
Task DeleteCalendarItemAsync(Guid calendarItemId);
|
||||||
|
Task DeleteCalendarItemAsync(string calendarRemoteEventId, Guid calendarId);
|
||||||
|
|
||||||
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public interface IDefaultChangeProcessor
|
|||||||
Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId);
|
Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId);
|
||||||
|
|
||||||
Task DeleteCalendarItemAsync(Guid calendarItemId);
|
Task DeleteCalendarItemAsync(Guid calendarItemId);
|
||||||
|
Task DeleteCalendarItemAsync(string calendarRemoteEventId, Guid calendarId);
|
||||||
|
|
||||||
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
@@ -188,6 +189,9 @@ public class DefaultChangeProcessor(IDatabaseService databaseService,
|
|||||||
public Task DeleteCalendarItemAsync(Guid calendarItemId)
|
public Task DeleteCalendarItemAsync(Guid calendarItemId)
|
||||||
=> CalendarService.DeleteCalendarItemAsync(calendarItemId);
|
=> CalendarService.DeleteCalendarItemAsync(calendarItemId);
|
||||||
|
|
||||||
|
public Task DeleteCalendarItemAsync(string calendarRemoteEventId, Guid calendarId)
|
||||||
|
=> CalendarService.DeleteCalendarItemAsync(calendarRemoteEventId, calendarId);
|
||||||
|
|
||||||
public Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar)
|
public Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar)
|
||||||
=> CalendarService.DeleteAccountCalendarAsync(accountCalendar);
|
=> CalendarService.DeleteAccountCalendarAsync(accountCalendar);
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ namespace Wino.Core.Synchronizers.Mail;
|
|||||||
[JsonSerializable(typeof(OutlookFileAttachment))]
|
[JsonSerializable(typeof(OutlookFileAttachment))]
|
||||||
public partial class OutlookSynchronizerJsonContext : JsonSerializerContext;
|
public partial class OutlookSynchronizerJsonContext : JsonSerializerContext;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Outlook synchronizer implementation with delta token synchronization.
|
/// Outlook synchronizer implementation with delta token synchronization.
|
||||||
///
|
///
|
||||||
@@ -102,6 +100,7 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
|||||||
];
|
];
|
||||||
|
|
||||||
private readonly SemaphoreSlim _handleItemRetrievalSemaphore = new(1);
|
private readonly SemaphoreSlim _handleItemRetrievalSemaphore = new(1);
|
||||||
|
private readonly SemaphoreSlim _handleCalendarEventRetrievalSemaphore = new(1);
|
||||||
|
|
||||||
private readonly ILogger _logger = Log.ForContext<OutlookSynchronizer>();
|
private readonly ILogger _logger = Log.ForContext<OutlookSynchronizer>();
|
||||||
private readonly IOutlookChangeProcessor _outlookChangeProcessor;
|
private readonly IOutlookChangeProcessor _outlookChangeProcessor;
|
||||||
@@ -1633,8 +1632,8 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
|||||||
_logger.Information("No calendar sync identifier for calendar {Name}. Performing initial sync.", calendar.Name);
|
_logger.Information("No calendar sync identifier for calendar {Name}. Performing initial sync.", calendar.Name);
|
||||||
|
|
||||||
// ISO 8601 format as expected by Microsoft Graph API (e.g., "2019-11-08T19:00:00-08:00")
|
// ISO 8601 format as expected by Microsoft Graph API (e.g., "2019-11-08T19:00:00-08:00")
|
||||||
var startDate = DateTimeOffset.UtcNow.AddYears(-2).ToString("yyyy-MM-ddTHH:mm:sszzz");
|
var startDate = DateTimeOffset.Now.AddYears(-2).ToString("yyyy-MM-ddTHH:mm:sszzz");
|
||||||
var endDate = DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:sszzz");
|
var endDate = DateTimeOffset.Now.ToString("yyyy-MM-ddTHH:mm:sszzz");
|
||||||
|
|
||||||
eventsDeltaResponse = await _graphClient.Me.Calendars[calendar.RemoteCalendarId].CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
|
eventsDeltaResponse = await _graphClient.Me.Calendars[calendar.RemoteCalendarId].CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
|
||||||
{
|
{
|
||||||
@@ -1691,18 +1690,44 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
|||||||
|
|
||||||
foreach (var item in events)
|
foreach (var item in events)
|
||||||
{
|
{
|
||||||
try
|
if (IsResourceDeleted(item.AdditionalData))
|
||||||
{
|
{
|
||||||
await _handleItemRetrievalSemaphore.WaitAsync();
|
await _outlookChangeProcessor.DeleteCalendarItemAsync(item.Id, calendar.Id).ConfigureAwait(false);
|
||||||
await _outlookChangeProcessor.ManageCalendarEventAsync(item, calendar, Account).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
else
|
||||||
{
|
{
|
||||||
// _logger.Error(ex, "Error occurred while handling item {Id} for calendar {Name}", item.Id, calendar.Name);
|
try
|
||||||
}
|
{
|
||||||
finally
|
await _handleCalendarEventRetrievalSemaphore.WaitAsync();
|
||||||
{
|
|
||||||
_handleItemRetrievalSemaphore.Release();
|
// Check if the event has complete information
|
||||||
|
// Sometimes delta sync returns events with only Id available
|
||||||
|
Event fullEvent = item;
|
||||||
|
if (string.IsNullOrEmpty(item.Subject) || item.Start == null || item.End == null)
|
||||||
|
{
|
||||||
|
_logger.Information("Event {Id} has incomplete data. Downloading full event details.", item.Id);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fullEvent = await _graphClient.Me.Calendars[calendar.RemoteCalendarId].Events[item.Id].GetAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception downloadEx)
|
||||||
|
{
|
||||||
|
_logger.Error(downloadEx, "Failed to download full event details for {Id}. Using partial data.", item.Id);
|
||||||
|
fullEvent = item; // Fallback to partial data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _outlookChangeProcessor.ManageCalendarEventAsync(fullEvent, calendar, Account).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Error occurred while handling item {Id} for calendar {Name}", item.Id, calendar.Name);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_handleCalendarEventRetrievalSemaphore.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1715,7 +1740,7 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
|||||||
|
|
||||||
var deltaToken = GetDeltaTokenFromDeltaLink(latestDeltaLink);
|
var deltaToken = GetDeltaTokenFromDeltaLink(latestDeltaLink);
|
||||||
|
|
||||||
/// await _outlookChangeProcessor.UpdateCalendarDeltaSynchronizationToken(calendar.Id, deltaToken).ConfigureAwait(false);
|
await _outlookChangeProcessor.UpdateCalendarDeltaSynchronizationToken(calendar.Id, deltaToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,17 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteCalendarItemAsync(string calendarRemoteEventId, Guid calendarId)
|
||||||
|
{
|
||||||
|
var calendarItem = await Connection.FindWithQueryAsync<CalendarItem>(
|
||||||
|
"SELECT * FROM CalendarItem WHERE CalendarId = ? AND RemoteEventId = ?",
|
||||||
|
calendarId, calendarRemoteEventId);
|
||||||
|
|
||||||
|
if (calendarItem == null) return;
|
||||||
|
|
||||||
|
await DeleteCalendarItemAsync(calendarItem.Id);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees)
|
public async Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
Reference in New Issue
Block a user