Single isntances and some updates shit.
This commit is contained in:
@@ -161,6 +161,9 @@ public class GmailChangeProcessor : DefaultChangeProcessor, IGmailChangeProcesso
|
||||
// Hide canceled events.
|
||||
calendarItem.IsHidden = calendarItem.Status == CalendarItemStatus.Cancelled;
|
||||
|
||||
// Set assigned calendar for navigation properties to work.
|
||||
calendarItem.AssignedCalendar = assignedCalendar;
|
||||
|
||||
// Manage the recurring event id.
|
||||
if (parentRecurringEvent != null)
|
||||
{
|
||||
|
||||
@@ -42,11 +42,8 @@ public class OutlookChangeProcessor(IDatabaseService databaseService,
|
||||
|
||||
public async Task ManageCalendarEventAsync(Event calendarEvent, AccountCalendar assignedCalendar, MailAccount organizerAccount)
|
||||
{
|
||||
// We parse the occurrences based on the parent event.
|
||||
// There is literally no point to store them because
|
||||
// type=Exception events are the exceptional childs of recurrency parent event.
|
||||
|
||||
if (calendarEvent.Type == EventType.Occurrence) return;
|
||||
// All event types are now handled: SingleInstance, SeriesMaster, Occurrence, and Exception.
|
||||
// Occurrences from CalendarView are individual instances that are saved separately.
|
||||
|
||||
var savingItem = await CalendarService.GetCalendarItemAsync(assignedCalendar.Id, calendarEvent.Id);
|
||||
|
||||
@@ -81,10 +78,12 @@ public class OutlookChangeProcessor(IDatabaseService databaseService,
|
||||
savingItem.Description = calendarEvent.Body?.Content;
|
||||
savingItem.Location = calendarEvent.Location?.DisplayName;
|
||||
|
||||
if (calendarEvent.Type == EventType.Exception && !string.IsNullOrEmpty(calendarEvent.SeriesMasterId))
|
||||
// Handle recurring event relationships for both Exception and Occurrence types
|
||||
if ((calendarEvent.Type == EventType.Exception || calendarEvent.Type == EventType.Occurrence)
|
||||
&& !string.IsNullOrEmpty(calendarEvent.SeriesMasterId))
|
||||
{
|
||||
// This is a recurring event exception.
|
||||
// We need to find the parent event and set it as recurring event id.
|
||||
// This is a recurring event instance (either an exception or a regular occurrence).
|
||||
// Link it to the parent series master.
|
||||
|
||||
var parentEvent = await CalendarService.GetCalendarItemAsync(assignedCalendar.Id, calendarEvent.SeriesMasterId);
|
||||
|
||||
@@ -94,12 +93,14 @@ public class OutlookChangeProcessor(IDatabaseService databaseService,
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"Parent recurring event is missing for event. Skipping creation of {calendarEvent.Id}");
|
||||
return;
|
||||
// Parent not found yet - this can happen if occurrences sync before the series master.
|
||||
// We still save the event but without the parent link for now.
|
||||
Log.Warning($"Parent recurring event (SeriesMasterId: {calendarEvent.SeriesMasterId}) not found for event {calendarEvent.Id}. Event will be saved without parent link.");
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the recurrence pattern to string for parent recurring events.
|
||||
// Note: We store this for reference but don't use it to calculate occurrences.
|
||||
if (calendarEvent.Type == EventType.SeriesMaster && calendarEvent.Recurrence != null)
|
||||
{
|
||||
savingItem.Recurrence = OutlookIntegratorExtensions.ToRfc5545RecurrenceString(calendarEvent.Recurrence);
|
||||
@@ -234,6 +235,9 @@ public class OutlookChangeProcessor(IDatabaseService databaseService,
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Set assigned calendar for navigation properties to work.
|
||||
savingItem.AssignedCalendar = assignedCalendar;
|
||||
|
||||
// Use CalendarService to create or update the event
|
||||
if (isNewItem)
|
||||
{
|
||||
|
||||
@@ -392,7 +392,10 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
{
|
||||
var request = _calendarService.Events.List(calendar.RemoteCalendarId);
|
||||
|
||||
request.SingleEvents = false;
|
||||
// Fetch individual event instances (including recurring event occurrences)
|
||||
// rather than recurring event masters. This ensures we get all occurrences
|
||||
// as separate events that can be stored and displayed directly.
|
||||
request.SingleEvents = true;
|
||||
request.ShowDeleted = true;
|
||||
|
||||
if (!string.IsNullOrEmpty(calendar.SynchronizationDeltaToken))
|
||||
@@ -1975,6 +1978,31 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
return [new HttpRequestBundle<IClientServiceRequest>(updateRequest, request)];
|
||||
}
|
||||
|
||||
public override List<IRequestBundle<IClientServiceRequest>> DeleteCalendarEvent(DeleteCalendarEventRequest request)
|
||||
{
|
||||
var calendarItem = request.Item;
|
||||
|
||||
// Get the calendar for this event
|
||||
var calendar = calendarItem.AssignedCalendar;
|
||||
if (calendar == null)
|
||||
{
|
||||
throw new InvalidOperationException("Calendar item must have an assigned calendar");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(calendarItem.RemoteEventId))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot delete event without remote event ID");
|
||||
}
|
||||
|
||||
// Delete the event using Google Calendar API
|
||||
var deleteRequest = _calendarService.Events.Delete(calendar.RemoteCalendarId, calendarItem.RemoteEventId);
|
||||
|
||||
// Send cancellation notifications to attendees
|
||||
deleteRequest.SendUpdates = Google.Apis.Calendar.v3.EventsResource.DeleteRequest.SendUpdatesEnum.All;
|
||||
|
||||
return [new HttpRequestBundle<IClientServiceRequest>(deleteRequest, request)];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override async Task KillSynchronizerAsync()
|
||||
|
||||
@@ -1811,14 +1811,8 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
|
||||
var messageIteratorAsync = PageIterator<Event, Microsoft.Graph.Me.Calendars.Item.CalendarView.Delta.DeltaGetResponse>.CreatePageIterator(_graphClient, eventsDeltaResponse, (item) =>
|
||||
{
|
||||
// Skip occurrence events during initial sync - only sync master recurring events and single instances
|
||||
// Occurrences are individual instances of recurring events and will be generated from the seriesMaster
|
||||
if (item.Type == Microsoft.Graph.Models.EventType.Occurrence)
|
||||
{
|
||||
_logger.Debug("Skipping occurrence event {EventId} during initial sync", item.Id);
|
||||
return true; // Skip this occurrence
|
||||
}
|
||||
|
||||
// Include all event types: SingleInstance, SeriesMaster, Occurrence, and Exception
|
||||
// CalendarView already expands recurring events into individual occurrences
|
||||
events.Add(item);
|
||||
|
||||
return true;
|
||||
@@ -1835,10 +1829,6 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
|
||||
foreach (var item in events)
|
||||
{
|
||||
if (item.Id == "f275fdd0-8622-4e14-8f5d-b73d7f68018f")
|
||||
{
|
||||
|
||||
}
|
||||
// Declined events are returned as Deleted from the API.
|
||||
// There is no way to distinguish unfortunately atm.
|
||||
|
||||
@@ -2217,6 +2207,28 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
return [new HttpRequestBundle<RequestInformation>(updateRequest, request)];
|
||||
}
|
||||
|
||||
public override List<IRequestBundle<RequestInformation>> DeleteCalendarEvent(DeleteCalendarEventRequest request)
|
||||
{
|
||||
var calendarItem = request.Item;
|
||||
|
||||
// Get the calendar for this event
|
||||
var calendar = calendarItem.AssignedCalendar;
|
||||
if (calendar == null)
|
||||
{
|
||||
throw new InvalidOperationException("Calendar item must have an assigned calendar");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(calendarItem.RemoteEventId))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot delete event without remote event ID");
|
||||
}
|
||||
|
||||
// Delete the event using Graph API
|
||||
var deleteRequest = _graphClient.Me.Calendars[calendar.RemoteCalendarId].Events[calendarItem.RemoteEventId].ToDeleteRequestInformation();
|
||||
|
||||
return [new HttpRequestBundle<RequestInformation>(deleteRequest, request)];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override async Task KillSynchronizerAsync()
|
||||
|
||||
@@ -384,7 +384,7 @@ public abstract class WinoSynchronizer<TBaseRequest, TMessageType, TCalendarEven
|
||||
nativeRequests.AddRange(UpdateCalendarEvent(group.ElementAt(0) as UpdateCalendarEventRequest));
|
||||
break;
|
||||
case CalendarSynchronizerOperation.DeleteEvent:
|
||||
// TODO: Implement DeleteCalendarEvent
|
||||
nativeRequests.AddRange(DeleteCalendarEvent(group.ElementAt(0) as DeleteCalendarEventRequest));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -511,6 +511,7 @@ public abstract class WinoSynchronizer<TBaseRequest, TMessageType, TCalendarEven
|
||||
|
||||
public virtual List<IRequestBundle<TBaseRequest>> CreateCalendarEvent(CreateCalendarEventRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||
public virtual List<IRequestBundle<TBaseRequest>> UpdateCalendarEvent(UpdateCalendarEventRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||
public virtual List<IRequestBundle<TBaseRequest>> DeleteCalendarEvent(DeleteCalendarEventRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||
public virtual List<IRequestBundle<TBaseRequest>> AcceptEvent(AcceptEventRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||
public virtual List<IRequestBundle<TBaseRequest>> DeclineEvent(DeclineEventRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||
public virtual List<IRequestBundle<TBaseRequest>> OutlookDeclineEvent(OutlookDeclineEventRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||
|
||||
Reference in New Issue
Block a user