Outlook delta synchronization.
This commit is contained in:
@@ -221,7 +221,7 @@ namespace Wino.Calendar.ViewModels
|
|||||||
{
|
{
|
||||||
var t = new NewCalendarSynchronizationRequested(new CalendarSynchronizationOptions()
|
var t = new NewCalendarSynchronizationRequested(new CalendarSynchronizationOptions()
|
||||||
{
|
{
|
||||||
AccountId = Guid.Parse("bd0fc1ab-168a-436d-86ce-0661c0eabaf9"),
|
AccountId = Guid.Parse("5b2e28bb-3179-4a7f-a62b-373878ee2b53"),
|
||||||
Type = CalendarSynchronizationType.CalendarMetadata
|
Type = CalendarSynchronizationType.CalendarMetadata
|
||||||
}, SynchronizationSource.Client);
|
}, SynchronizationSource.Client);
|
||||||
|
|
||||||
|
|||||||
@@ -295,7 +295,7 @@
|
|||||||
Closed="EventDetailsPopupClosed"
|
Closed="EventDetailsPopupClosed"
|
||||||
DesiredPlacement="{x:Bind calendarHelpers:CalendarXamlHelpers.GetDesiredPlacementModeForEventsDetailsPopup(ViewModel.DisplayDetailsCalendarItemViewModel, ViewModel.StatePersistanceService.CalendarDisplayType), Mode=OneWay}"
|
DesiredPlacement="{x:Bind calendarHelpers:CalendarXamlHelpers.GetDesiredPlacementModeForEventsDetailsPopup(ViewModel.DisplayDetailsCalendarItemViewModel, ViewModel.StatePersistanceService.CalendarDisplayType), Mode=OneWay}"
|
||||||
HorizontalOffset="16"
|
HorizontalOffset="16"
|
||||||
IsLightDismissEnabled="False"
|
IsLightDismissEnabled="True"
|
||||||
IsOpen="{x:Bind ViewModel.IsEventDetailsVisible, Mode=OneWay}"
|
IsOpen="{x:Bind ViewModel.IsEventDetailsVisible, Mode=OneWay}"
|
||||||
PlacementTarget="{x:Bind TeachingTipPositionerGrid}"
|
PlacementTarget="{x:Bind TeachingTipPositionerGrid}"
|
||||||
VerticalOffset="16">
|
VerticalOffset="16">
|
||||||
@@ -319,7 +319,6 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
FontWeight="Normal"
|
FontWeight="Normal"
|
||||||
Foreground="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(ViewModel.DisplayDetailsCalendarItemViewModel.AssignedCalendar.BackgroundColorHex), Mode=OneWay}"
|
|
||||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||||
Text="{x:Bind ViewModel.DisplayDetailsCalendarItemViewModel.Title, Mode=OneWay}" />
|
Text="{x:Bind ViewModel.DisplayDetailsCalendarItemViewModel.Title, Mode=OneWay}" />
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,6 @@ namespace Wino.Core.Domain.Interfaces
|
|||||||
Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
|
Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
|
||||||
Task<List<CalendarItem>> GetCalendarEventsAsync(IAccountCalendar calendar, DayRangeRenderModel dayRangeRenderModel);
|
Task<List<CalendarItem>> GetCalendarEventsAsync(IAccountCalendar calendar, DayRangeRenderModel dayRangeRenderModel);
|
||||||
Task<CalendarItem> GetCalendarItemAsync(Guid accountCalendarId, string remoteEventId);
|
Task<CalendarItem> GetCalendarItemAsync(Guid accountCalendarId, string remoteEventId);
|
||||||
|
Task UpdateCalendarDeltaSynchronizationToken(Guid calendarId, string deltaToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ namespace Wino.Core.Integration.Processors
|
|||||||
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
|
|
||||||
|
Task UpdateCalendarDeltaSynchronizationToken(Guid calendarId, string deltaToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IGmailChangeProcessor : IDefaultChangeProcessor
|
public interface IGmailChangeProcessor : IDefaultChangeProcessor
|
||||||
@@ -103,7 +105,11 @@ namespace Wino.Core.Integration.Processors
|
|||||||
/// <param name="accountId">Account identifier to reset delta token for.</param>
|
/// <param name="accountId">Account identifier to reset delta token for.</param>
|
||||||
/// <returns>Empty string to assign account delta sync for.</returns>
|
/// <returns>Empty string to assign account delta sync for.</returns>
|
||||||
Task<string> ResetAccountDeltaTokenAsync(Guid accountId);
|
Task<string> ResetAccountDeltaTokenAsync(Guid accountId);
|
||||||
|
|
||||||
|
|
||||||
Task ManageCalendarEventAsync(Microsoft.Graph.Models.Event calendarEvent, AccountCalendar assignedCalendar, MailAccount organizerAccount);
|
Task ManageCalendarEventAsync(Microsoft.Graph.Models.Event calendarEvent, AccountCalendar assignedCalendar, MailAccount organizerAccount);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IImapChangeProcessor : IDefaultChangeProcessor
|
public interface IImapChangeProcessor : IDefaultChangeProcessor
|
||||||
@@ -199,5 +205,8 @@ namespace Wino.Core.Integration.Processors
|
|||||||
|
|
||||||
public Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar)
|
public Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar)
|
||||||
=> CalendarService.UpdateAccountCalendarAsync(accountCalendar);
|
=> CalendarService.UpdateAccountCalendarAsync(accountCalendar);
|
||||||
|
|
||||||
|
public Task UpdateCalendarDeltaSynchronizationToken(Guid calendarId, string deltaToken)
|
||||||
|
=> CalendarService.UpdateCalendarDeltaSynchronizationToken(calendarId, deltaToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -966,44 +966,66 @@ namespace Wino.Core.Synchronizers.Mail
|
|||||||
|
|
||||||
// await SynchronizeCalendarsAsync(cancellationToken).ConfigureAwait(false);
|
// await SynchronizeCalendarsAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
bool isInitialSync = string.IsNullOrEmpty(Account.CalendarSynchronizationDeltaIdentifier);
|
|
||||||
|
|
||||||
var localCalendars = await _outlookChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
|
var localCalendars = await _outlookChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
Microsoft.Graph.Me.CalendarView.Delta.DeltaGetResponse eventsDeltaResponse = null;
|
Microsoft.Graph.Me.Calendars.Item.CalendarView.Delta.DeltaGetResponse eventsDeltaResponse = null;
|
||||||
|
|
||||||
|
// TODO: Maybe we can batch each calendar?
|
||||||
|
|
||||||
|
foreach (var calendar in localCalendars)
|
||||||
|
{
|
||||||
|
bool isInitialSync = string.IsNullOrEmpty(calendar.SynchronizationDeltaToken);
|
||||||
|
|
||||||
if (isInitialSync)
|
if (isInitialSync)
|
||||||
{
|
{
|
||||||
_logger.Debug("No calendar sync identifier for account {Name}. Performing initial sync.", Account.Name);
|
_logger.Information("No calendar sync identifier for calendar {Name}. Performing initial sync.", calendar.Name);
|
||||||
|
|
||||||
var startDate = DateTime.UtcNow.AddYears(-2).ToString("u");
|
var startDate = DateTime.UtcNow.AddYears(-2).ToString("u");
|
||||||
var endDate = DateTime.UtcNow.ToString("u");
|
var endDate = DateTime.UtcNow.ToString("u");
|
||||||
|
|
||||||
// No delta link. Performing initial sync.
|
eventsDeltaResponse = await _graphClient.Me.Calendars[calendar.RemoteCalendarId].CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
|
||||||
eventsDeltaResponse = await _graphClient.Me.CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
|
|
||||||
{
|
{
|
||||||
requestConfiguration.QueryParameters.StartDateTime = startDate;
|
requestConfiguration.QueryParameters.StartDateTime = startDate;
|
||||||
requestConfiguration.QueryParameters.EndDateTime = endDate;
|
requestConfiguration.QueryParameters.EndDateTime = endDate;
|
||||||
|
|
||||||
// TODO: Expand does not work.
|
|
||||||
// https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2358
|
|
||||||
|
|
||||||
requestConfiguration.QueryParameters.Expand = new string[] { "calendar($select=name,id)" }; // Expand the calendar and select name and id. Customize as needed.
|
|
||||||
}, cancellationToken: cancellationToken);
|
}, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
// No delta link. Performing initial sync.
|
||||||
|
//eventsDeltaResponse = await _graphClient.Me.CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
|
||||||
|
//{
|
||||||
|
// requestConfiguration.QueryParameters.StartDateTime = startDate;
|
||||||
|
// requestConfiguration.QueryParameters.EndDateTime = endDate;
|
||||||
|
|
||||||
|
// // TODO: Expand does not work.
|
||||||
|
// // https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2358
|
||||||
|
|
||||||
|
// requestConfiguration.QueryParameters.Expand = new string[] { "calendar($select=name,id)" }; // Expand the calendar and select name and id. Customize as needed.
|
||||||
|
//}, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//var requestInformation = _graphClient.Me.Calendars[calendar.RemoteCalendarId].Events.Delta.ToGetRequestInformation((config) =>
|
var currentDeltaToken = calendar.SynchronizationDeltaToken;
|
||||||
|
|
||||||
|
_logger.Information("Performing delta sync for calendar {Name}.", calendar.Name);
|
||||||
|
|
||||||
|
var requestInformation = _graphClient.Me.Calendars[calendar.RemoteCalendarId].CalendarView.Delta.ToGetRequestInformation((requestConfiguration) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
//requestConfiguration.QueryParameters.StartDateTime = startDate;
|
||||||
|
//requestConfiguration.QueryParameters.EndDateTime = endDate;
|
||||||
|
});
|
||||||
|
|
||||||
|
//var requestInformation = _graphClient.Me.Calendars[calendar.RemoteCalendarId].CalendarView.Delta.ToGetRequestInformation((config) =>
|
||||||
//{
|
//{
|
||||||
// config.QueryParameters.Top = (int)InitialMessageDownloadCountPerFolder;
|
// config.QueryParameters.Top = (int)InitialMessageDownloadCountPerFolder;
|
||||||
// config.QueryParameters.Select = outlookMessageSelectParameters;
|
// config.QueryParameters.Select = outlookMessageSelectParameters;
|
||||||
// config.QueryParameters.Orderby = ["receivedDateTime desc"];
|
// config.QueryParameters.Orderby = ["receivedDateTime desc"];
|
||||||
//});
|
//});
|
||||||
|
|
||||||
//requestInformation.UrlTemplate = requestInformation.UrlTemplate.Insert(requestInformation.UrlTemplate.Length - 1, ",%24deltatoken");
|
|
||||||
//requestInformation.QueryParameters.Add("%24deltatoken", currentDeltaToken);
|
|
||||||
|
|
||||||
// eventsDeltaResponse = await _graphClient.RequestAdapter.SendAsync(requestInformation, Microsoft.Graph.Me.Calendars.Item.Events.Delta.DeltaGetResponse.CreateFromDiscriminatorValue);
|
requestInformation.UrlTemplate = requestInformation.UrlTemplate.Insert(requestInformation.UrlTemplate.Length - 1, ",%24deltatoken");
|
||||||
|
requestInformation.QueryParameters.Add("%24deltatoken", currentDeltaToken);
|
||||||
|
|
||||||
|
eventsDeltaResponse = await _graphClient.RequestAdapter.SendAsync(requestInformation, Microsoft.Graph.Me.Calendars.Item.CalendarView.Delta.DeltaGetResponse.CreateFromDiscriminatorValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Event> events = new();
|
List<Event> events = new();
|
||||||
@@ -1011,7 +1033,7 @@ namespace Wino.Core.Synchronizers.Mail
|
|||||||
// We must first save the parent recurring events to not lose exceptions.
|
// We must first save the parent recurring events to not lose exceptions.
|
||||||
// Therefore, order the existing items by their type and save the parent recurring events first.
|
// Therefore, order the existing items by their type and save the parent recurring events first.
|
||||||
|
|
||||||
var messageIteratorAsync = PageIterator<Event, Microsoft.Graph.Me.CalendarView.Delta.DeltaGetResponse>.CreatePageIterator(_graphClient, eventsDeltaResponse, (item) =>
|
var messageIteratorAsync = PageIterator<Event, Microsoft.Graph.Me.Calendars.Item.CalendarView.Delta.DeltaGetResponse>.CreatePageIterator(_graphClient, eventsDeltaResponse, (item) =>
|
||||||
{
|
{
|
||||||
events.Add(item);
|
events.Add(item);
|
||||||
|
|
||||||
@@ -1025,12 +1047,14 @@ namespace Wino.Core.Synchronizers.Mail
|
|||||||
// Desc-order will move parent recurring events to the top.
|
// Desc-order will move parent recurring events to the top.
|
||||||
events = events.OrderByDescending(a => a.Type).ToList();
|
events = events.OrderByDescending(a => a.Type).ToList();
|
||||||
|
|
||||||
|
_logger.Information("Found {Count} events in total.", events.Count);
|
||||||
|
|
||||||
foreach (var item in events)
|
foreach (var item in events)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _handleItemRetrievalSemaphore.WaitAsync();
|
await _handleItemRetrievalSemaphore.WaitAsync();
|
||||||
//await _outlookChangeProcessor.ManageCalendarEventAsync(item, calendar, Account).ConfigureAwait(false);
|
await _outlookChangeProcessor.ManageCalendarEventAsync(item, calendar, Account).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1042,7 +1066,18 @@ namespace Wino.Core.Synchronizers.Mail
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// latestDeltaLink = messageIteratorAsync.Deltalink;
|
var latestDeltaLink = messageIteratorAsync.Deltalink;
|
||||||
|
|
||||||
|
//Store delta link for tracking new changes.
|
||||||
|
if (!string.IsNullOrEmpty(latestDeltaLink))
|
||||||
|
{
|
||||||
|
// Parse Delta Token from Delta Link since v5 of Graph SDK works based on the token, not the link.
|
||||||
|
|
||||||
|
var deltaToken = GetDeltaTokenFromDeltaLink(latestDeltaLink);
|
||||||
|
|
||||||
|
await _outlookChangeProcessor.UpdateCalendarDeltaSynchronizationToken(calendar.Id, deltaToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,5 +198,15 @@ namespace Wino.Services
|
|||||||
|
|
||||||
return calendarItem;
|
return calendarItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task UpdateCalendarDeltaSynchronizationToken(Guid calendarId, string deltaToken)
|
||||||
|
{
|
||||||
|
var query = new Query()
|
||||||
|
.From(nameof(AccountCalendar))
|
||||||
|
.Where(nameof(AccountCalendar.Id), calendarId)
|
||||||
|
.AsUpdate(new { SynchronizationDeltaToken = deltaToken });
|
||||||
|
|
||||||
|
return Connection.ExecuteAsync(query.GetRawQuery());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user