/// <summary> /// Returns all appointments for period from <paramref name="folder"/>. Recurring apointments included. /// </summary> /// <param name="context"><see cref="SyncContext"/> instance.</param> /// <param name="folder"><see cref=" Exchange.Folder"/> instance.</param> /// <returns><see cref="Exchange.Item"/> collection.</returns> protected IEnumerable <Exchange.Item> GetAppointmentsForPeriod(SyncContext context, Exchange.Folder folder) { if (GetExchangeRecurringAppointmentsSupported(context.UserConnection)) { var type = LoadFromDateType.GetInstance(context.UserConnection); var starDate = type.GetLoadFromDate(UserSettings.ActivitySyncPeriod); var endDate = type.GetLoadFromDate(UserSettings.ActivitySyncPeriod, true); context?.LogInfo(SyncAction.None, SyncDirection.Download, "GetAppointmentsForPeriod with: starDate {0}, endDate {1}.", starDate, endDate); var currentStartDate = starDate; while (currentStartDate < endDate) { var calendarItemView = new Exchange.CalendarView(currentStartDate, currentStartDate.AddDays(1), 150); context?.LogInfo(SyncAction.None, SyncDirection.Download, "GetAppointmentsForPeriod with: currentStartDate {0}.", currentStartDate); Exchange.FindItemsResults <Exchange.Appointment> calendarItemCollection; calendarItemCollection = Service.FindAppointments(folder.Id, calendarItemView); context?.LogInfo(SyncAction.None, SyncDirection.Download, "GetAppointmentsForPeriod - Service found {0} items.", calendarItemCollection.Count()); foreach (var item in calendarItemCollection) { yield return(item); } currentStartDate = currentStartDate.AddDays(1); } context?.LogInfo(SyncAction.None, SyncDirection.Download, "GetAppointmentsForPeriod - End method."); } }
private IEnumerable <LocalItem> GetNotSyncedActivities(SyncContext context, SyncItemSchema primarySchema) { string primarySchemaName = primarySchema.PrimaryEntityConfig.SchemaName; UserConnection userConnection = context.UserConnection; var esq = new EntitySchemaQuery(userConnection.EntitySchemaManager, primarySchemaName); esq.PrimaryQueryColumn.IsAlwaysSelect = true; AddActivityQueryColumns(esq); AddExportFiltersBySettings(context, esq); Select select = esq.GetSelectQuery(userConnection); AddExportFilters(userConnection, select); EntityCollection entities = esq.GetEntityCollection(userConnection); if (entities.Count > 0) { select.BuildParametersAsValue = true; context?.LogInfo(SyncAction.None, SyncDirection.Download, "loaded {0} activities from bpm, Select: {1}", entities.Count, select.GetSqlText()); } foreach (Entity entity in entities) { var localItem = new LocalItem(primarySchema); localItem.Entities[primarySchemaName].Add(new SyncEntity(entity, SyncState.New)); yield return(localItem); } }
/// <summary>Returns activity instance for exchange appointment, in case of changed remote id.</summary> /// <param name="context">Synchronization context.</param> /// <param name="exchangeItem">Exchange item in external storage.</param> /// <param name="storedId">Id of bpm activity, stored in external property of exchange item.</param> /// <param name="localItem">Local storage item.</param> /// <returns>Activity instance.</returns> protected Entity GetSyncedActivityWithChangedRemoteId(SyncContext context, Exchange.Item exchangeItem, Guid storedId, LocalItem localItem) { Entity instance; var syncValueName = localItem.Schema.SyncValueName; var schema = context.UserConnection.EntitySchemaManager.GetInstanceByName("Activity"); instance = schema.CreateEntity(context.UserConnection); if (!localItem.Entities["Activity"].Any(se => se.EntityId.Equals(storedId)) && instance.FetchFromDB(storedId)) { SyncEntity syncEntity = SyncEntity.CreateNew(instance); var isCurrentUserOwner = context.UserConnection.CurrentUser.ContactId == instance.GetTypedColumnValue <Guid>("OwnerId"); syncEntity.Action = isCurrentUserOwner ? SyncAction.Update : SyncAction.None; context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "GetSyncedActivityWithChangedRemoteId set action {0} for {1}", syncEntity.Action, GetDisplayName()); localItem.AddOrReplace("Activity", syncEntity); if (syncValueName == ExchangeConsts.ExchangeAppointmentClassName) { context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "GetSyncedActivityWithChangedRemoteId ExchangeAppointmentClassName action update for {0}", GetDisplayName()); Action = SyncAction.Update; syncEntity.Action = SyncAction.Update; } else { Action = isCurrentUserOwner ? SyncAction.Update : SyncAction.None; context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "GetSyncedActivityWithChangedRemoteId action {0} for {1}", Action, GetDisplayName()); if (isCurrentUserOwner) { ActualizeOldMetadata(context, storedId, Id); } } } else { context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "GetSyncedActivityWithChangedRemoteId not found entity action {0} for {1}", Action, GetDisplayName()); instance = GetEntityInstance <Entity>(context, localItem, "Activity"); } return(instance); }
/// <summary> /// Writes log message. /// </summary> /// <param name="context"><see cref="SyncContext"/> instance.</param> /// <param name="action"><see cref="SyncAction"/> enumeration.</param> /// <param name="syncDirection"><see cref="SyncDirection"/> enumeration.</param> /// <param name="format">String a composite format.</param> /// <param name="ex">Exception.</param> /// <param name="args">An array of additional parameters.</param> public virtual void LogMessage(SyncContext context, SyncAction action, SyncDirection syncDirection, string format, Exception ex, params object[] args) { if (ex == null) { context.LogInfo(action, syncDirection, format, args); } else { context.LogError(action, syncDirection, format, ex, args); } }
/// <summary> /// Returns activity instance. /// </summary> /// <param name="context">Synchronization context.</param> /// <param name="exchangeItem">Sync element in external storage.</param> /// <param name="localItem">Sync element in local storage.</param> protected Entity GetActivity(SyncContext context, Exchange.Item exchangeItem, ref LocalItem localItem) { Entity instance; Object localId; if (exchangeItem.TryGetProperty(ExchangeUtilityImpl.LocalIdProperty, out localId)) { context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "GetActivity use localId action {0} for {1}", Action, GetDisplayName()); instance = GetSyncedActivityWithChangedRemoteId(context, exchangeItem, Guid.Parse(localId.ToString()), localItem); } else { context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "GetActivity not use localId action {0} for {1}", Action, GetDisplayName()); instance = GetEntityInstance <Entity>(context, localItem, "Activity"); } return(instance); }
/// <summary> /// Creates and fills <see cref="LocalItem"/> instance. /// </summary> /// <param name="context"><see cref="SyncContext"/> instance.</param> /// <param name="itemId">Email item identifier.</param> /// <returns><see cref="LocalItem"/> instance.</returns> protected LocalItem GetLocalItem(SyncContext context, string itemId) { var remoteProvider = context.RemoteProvider; context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "Start processing item {0}", itemId); SyncItemSchema schema = remoteProvider.SyncItemSchemaCollection.FirstOrDefault(s => s.SyncValueName == "ExchangeEmailMessage"); IRemoteItem item = remoteProvider.LoadSyncItem(schema, itemId); LocalItem localItem = context.LocalProvider.FetchItem(null, schema, true); item.FillLocalItem(context, ref localItem); ProcessItemSyncAction(context, item); return(localItem); }
/// <summary> /// Additional actions after synchronization, based on paramref name="item"/> sync action. /// </summary> /// <param name="context"><see cref="SyncContext"/> instance.</param> /// <param name="item">Current email <see cref="IRemoteItem"/> implementation instance.</param> protected void ProcessItemSyncAction(SyncContext context, IRemoteItem item) { if (!context.UserConnection.GetIsFeatureEnabled("AsyncEmailEventHandling")) { return; } if (item.Action == SyncAction.Repeat) { var itemId = item.Id; context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "Item {0} synchronization need to be repeated", itemId); NeedReRun = true; } }
/// <summary> /// Set action for all synchronization schemes in local item. /// </summary> /// <param name="context">Synchronization context.</param> /// <param name="localItem">Sync element in local storage.</param> protected void SetLocalItemSchemasAction(SyncContext context, LocalItem entities, SyncAction action) { List <EntityConfig> schemas = entities.Schema.Configs; foreach (EntityConfig schema in schemas) { foreach (var syncEntity in entities.Entities[schema.SchemaName]) { context.LogInfo(SyncAction.None, SyncDirection.DownloadAndUpload, "SetLocalItemSchemasAction action {0} for {1}", action, GetDisplayName()); syncEntity.Action = action; } } }
/// <summary> /// Gets filters for Exchange data query. /// </summary> /// <returns>Filter instance.</returns> private Exchange.SearchFilter GetItemsSearchFilters(SyncContext context = null) { Exchange.SearchFilter filter = null; DateTime lastSyncDateUtc = TimeZoneInfo.ConvertTimeToUtc(UserSettings.LastSyncDate, TimeZone); DateTime importActivitiesFromDate = UserSettings.ImportActivitiesFrom; context?.LogInfo(SyncAction.None, SyncDirection.Download, "lastSyncDateUtc = {0}, importActivitiesFromDate = {1}", lastSyncDateUtc, importActivitiesFromDate); if (lastSyncDateUtc != DateTime.MinValue && UserSettings.ImportActivitiesFrom != DateTime.MinValue) { var lastSyncDateUtcFilter = new Exchange.SearchFilter.IsGreaterThan( Exchange.ItemSchema.LastModifiedTime, lastSyncDateUtc.ToLocalTime()); var filterCollection = new Exchange.SearchFilter.SearchFilterCollection(Exchange.LogicalOperator.Or); var customPropSetFilter = new Exchange.SearchFilter.Exists(ExchangeUtilityImpl.LocalIdProperty); var notCustomPropSetFilter = new Exchange.SearchFilter.Not(customPropSetFilter); filterCollection.AddRange(new List <Exchange.SearchFilter> { lastSyncDateUtcFilter, notCustomPropSetFilter }); if (context != null && GetExchangeRecurringAppointmentsSupported(context.UserConnection)) { return(filterCollection); } var allFilterCollection = new Exchange.SearchFilter.SearchFilterCollection(Exchange.LogicalOperator.And); var importActivitiesFromDateFilter = new Exchange.SearchFilter.IsGreaterThanOrEqualTo( Exchange.AppointmentSchema.Start, importActivitiesFromDate); allFilterCollection.AddRange(new List <Exchange.SearchFilter> { importActivitiesFromDateFilter, filterCollection }); filter = allFilterCollection; } else if (lastSyncDateUtc != DateTime.MinValue && UserSettings.ImportActivitiesFrom == DateTime.MinValue) { filter = new Exchange.SearchFilter.IsGreaterThan( Exchange.ItemSchema.LastModifiedTime, lastSyncDateUtc.ToLocalTime()); } else if (lastSyncDateUtc == DateTime.MinValue && UserSettings.ImportActivitiesFrom != DateTime.MinValue) { filter = new Exchange.SearchFilter.IsGreaterThanOrEqualTo( Exchange.AppointmentSchema.Start, importActivitiesFromDate); } return(filter); }
/// <summary> /// <see cref="ExchangeSyncProvider.EnumerateChanges"/> /// </summary> public override IEnumerable <IRemoteItem> EnumerateChanges(SyncContext context) { base.EnumerateChanges(context); FillFoldersList(context); var result = new List <IRemoteItem>(); if (!UserSettings.ImportActivities) { return(result); } Exchange.SearchFilter itemsFilter = GetItemsSearchFilters(context); SyncItemSchema schema = FindSchemaBySyncValueName(typeof(ExchangeAppointment).Name); var needGetRecurringAppointments = NeedGetRecurringAppointments(context); Exchange.PropertySet properties = new Exchange.PropertySet(Exchange.BasePropertySet.IdOnly); properties.AddRange(new[] { Exchange.ItemSchema.Subject, Exchange.ItemSchema.LastModifiedTime, Exchange.AppointmentSchema.Recurrence, Exchange.AppointmentSchema.IsRecurring, Exchange.AppointmentSchema.AppointmentType, Exchange.AppointmentSchema.ICalUid, Exchange.AppointmentSchema.ICalRecurrenceId, Exchange.AppointmentSchema.Start }); foreach (Exchange.Folder folder in Folders) { bool hasRecurence = false; if (!needGetRecurringAppointments) { foreach (Exchange.Item item in GetCalendarItems(folder, itemsFilter)) { Exchange.Appointment appointment = ExchangeUtility.SafeBindItem <Exchange.Appointment>(Service, item.Id, properties); if (appointment != null) { var recurentAppointment = GetExchangeRecurringAppointmentsSupported(context.UserConnection) && appointment.Recurrence != null; var isRecurringMaster = appointment.AppointmentType == Exchange.AppointmentType.RecurringMaster; if ((!recurentAppointment || isRecurringMaster) && CheckItemInSyncPeriod(context, appointment)) { context?.LogInfo(SyncAction.None, SyncDirection.Download, "Adding single or master appoitment {0}", appointment.Subject); var remoteItem = CreateExchangeAppointment(schema, appointment, TimeZone); context?.LogInfo(SyncAction.None, SyncDirection.Download, "Created ExchangeAppointment with Id {0}", remoteItem.Id); if (isRecurringMaster) { context?.LogInfo(SyncAction.None, SyncDirection.Download, "Adding master appoitment {0}", appointment.Subject); remoteItem.Action = SyncAction.CreateRecurringMaster; } result.Add(remoteItem); } hasRecurence = hasRecurence || recurentAppointment; } } } if (hasRecurence || needGetRecurringAppointments) { foreach (Exchange.Item item in GetAppointmentsForPeriod(context, folder)) { context?.LogInfo(SyncAction.None, SyncDirection.Download, "Input item - Subject {0}, UniqueId - {1}", item.Subject, item.Id.UniqueId); Exchange.Appointment appointment = ExchangeUtility.SafeBindItem <Exchange.Appointment>(Service, item.Id, properties); context?.LogInfo(SyncAction.None, SyncDirection.Download, "Adding recurence appoitment {0}", appointment.Subject); if (appointment != null) { var remoteItem = CreateExchangeAppointment(schema, appointment, TimeZone); context?.LogInfo(SyncAction.None, SyncDirection.Download, "Created recurence ExchangeAppointment with Id {0}", remoteItem.Id); result.Add(remoteItem); } } } } context?.LogInfo(SyncAction.None, SyncDirection.Download, "loaded {0} items from Exchange", result.Count); return(result); }
/// <summary> /// Writes information message to the log. /// </summary> /// <param name="context"><see cref="SyncContext"/> instance.</param> /// <param name="operation"> Log action for an object synchronization.</param> /// <param name="direction">Synchronization direction.</param> /// <param name="format">Format.</param> /// <param name="args">Format patameters.</param> protected virtual void LogInfo(SyncContext context, SyncAction operation, SyncDirection direction, string format, params object[] args) { context.LogInfo(operation, direction, format, args); }