public async Task ExecuteAsync(IJobExecutionContext context) { // Get the configuration for the job JobDataMap dataMap = context.JobDetail.JobDataMap; var approvalAttributeGuid = dataMap.GetString(AttributeKey_ApprovedAttribute).AsGuid(); var approvalAttribute = AttributeCache.Get(approvalAttributeGuid); // Collect some values for matching var campuses = CampusCache.All(); var audiences = DefinedTypeCache.Get(Rock.SystemGuid.DefinedType.MARKETING_CAMPAIGN_AUDIENCE_TYPE).DefinedValues; // Get the calendars var calendarGuid = dataMap.GetString(AttributeKey_Calendar).AsGuid(); var publicCalendarGuid = dataMap.GetString(AttributeKey_PublicCalendar).AsGuidOrNull(); var calendar = EventCalendarCache.Get(calendarGuid); var publicCalendar = publicCalendarGuid.HasValue ? EventCalendarCache.Get(publicCalendarGuid.Value) : null; // Get the login credentials string eSpaceUsername = dataMap.GetString(AttributeKey_eSpaceUsername); string eSpacePassword = dataMap.GetString(AttributeKey_eSpacePassword); // Decrypt the password eSpacePassword = Rock.Security.Encryption.DecryptString(eSpacePassword); // Create a new api client var client = new Client(); // Log in client.SetCredentials(eSpaceUsername, eSpacePassword); // Get all future events var eSpaceEvents = await client.GetEvents(new GetEventsOptions { StartDate = DateTime.Now, TopX = 2000 }); // Group by event id (the eSpace api returns "events" as a merged event and schedule) var eSpaceEventsById = eSpaceEvents.GroupBy(e => e.EventId); var eventTotalCount = eSpaceEventsById.Count(); // Loop through each eSpace event group var eventSyncedCount = 0; var eventErrorCount = 0; foreach (var eSpaceEventGroup in eSpaceEventsById) { eventSyncedCount++; try { // Use the first item as the main event - Note that some properties // here are actually part of the schedule, not the event var eSpaceEvent = eSpaceEventGroup.FirstOrDefault(); // Skip draft events if (eSpaceEvent.Status == "Draft") { continue; } // Update the job status context.UpdateLastStatusMessage($@"Syncing event {eventSyncedCount} of {eventTotalCount} ({Math.Round( (double) eventSyncedCount / eventTotalCount * 100, 0 )}%, {eventErrorCount} events with errors)"); // Sync the event await SyncHelper.SyncEvent( client, eSpaceEvent, new GetEventOccurrencesOptions { StartDate = DateTime.Now }, calendar, publicCalendar, null, approvalAttribute?.Key ); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); eventErrorCount++; } } var eSpaceEventIds = eSpaceEvents.Select(e => e.EventId).ToArray(); var rockContext = new RockContext(); var eventItemService = new EventItemService(rockContext); var desyncedEvents = eventItemService.Queryable().Where(e => e.ForeignKey == SyncHelper.ForeignKey_eSpaceEventId && !eSpaceEventIds.Contains(e.ForeignId)); if (desyncedEvents.Any()) { eventItemService.DeleteRange(desyncedEvents); rockContext.SaveChanges(); } // Update the job status context.UpdateLastStatusMessage($@"Synced {eventSyncedCount} events with {eventErrorCount} errors."); }