Ejemplo n.º 1
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap        = context.JobDetail.JobDataMap;
            int        expirationDays = dataMap.GetInt("ExpirationPeriod");
            int        delayMinutes   = dataMap.GetInt("DelayPeriod");

            var rockContext = new RockContext();
            var qry         = new CommunicationService(rockContext)
                              .GetQueued(expirationDays, delayMinutes, false, false)
                              .OrderBy(c => c.Id);

            var exceptionMsgs      = new List <string>();
            int communicationsSent = 0;

            foreach (var comm in qry.AsNoTracking().ToList())
            {
                try
                {
                    Rock.Model.Communication.Send(comm);
                    communicationsSent++;
                }

                catch (Exception ex)
                {
                    exceptionMsgs.Add(string.Format("Exception occurred sending communication ID:{0}:{1}    {2}", comm.Id, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                    ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                }
            }

            if (communicationsSent > 0)
            {
                context.Result = string.Format("Sent {0} {1}", communicationsSent, "communication".PluralizeIf(communicationsSent > 1));
            }
            else
            {
                context.Result = "No communications to send";
            }

            if (exceptionMsgs.Any())
            {
                throw new Exception("One or more exceptions occurred sending communications..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
            }

            // check for communications that have not been sent but are past the expire date. Mark them as failed and set a warning.
            var beginWindow          = RockDateTime.Now.AddDays(0 - expirationDays);
            var qryExpiredRecipients = new CommunicationRecipientService(rockContext).Queryable()
                                       .Where(cr =>
                                              cr.Communication.Status == CommunicationStatus.Approved &&
                                              cr.Status == CommunicationRecipientStatus.Pending &&
                                              (
                                                  (!cr.Communication.FutureSendDateTime.HasValue && cr.Communication.CreatedDateTime.HasValue && cr.Communication.CreatedDateTime < beginWindow) ||
                                                  (cr.Communication.FutureSendDateTime.HasValue && cr.Communication.FutureSendDateTime < beginWindow)
                                              ));

            var count = qryExpiredRecipients.Count();

            rockContext.BulkUpdate(qryExpiredRecipients, c => new CommunicationRecipient {
                Status = CommunicationRecipientStatus.Failed, StatusNote = "Communication was not sent before the expire window (possibly due to delayed approval)."
            });
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Updates the step set with step program completion
        /// </summary>
        public static void UpdateStepProgramCompletion(List <Step> stepSet, int personAliasId, int stepProgramId, RockContext rockContext = null)
        {
            rockContext = rockContext ?? new RockContext();
            var campusId      = stepSet.Where(a => a.CampusId.HasValue).Select(a => a.CampusId).FirstOrDefault();
            var startDateTime = stepSet.Select(a => a.StartDateTime ?? a.CreatedDateTime).OrderBy(a => a).FirstOrDefault();
            var endDateTime   = stepSet.Select(a => a.CompletedDateTime ?? a.EndDateTime).OrderByDescending(a => a).FirstOrDefault();

            var stepProgramCompletionService = new StepProgramCompletionService(rockContext);
            var stepService = new StepService(rockContext);

            var stepProgramCompletion = new StepProgramCompletion
            {
                StepProgramId = stepProgramId,
                PersonAliasId = personAliasId,
                CampusId      = campusId,
                StartDateTime = startDateTime.Value,
                EndDateTime   = endDateTime
            };

            stepProgramCompletionService.Add(stepProgramCompletion);
            rockContext.SaveChanges();

            var stepIds = stepSet.Select(b => b.Id);
            var stepQry = stepService.Queryable().Where(a => stepIds.Contains(a.Id));

            rockContext.BulkUpdate(stepQry, a => new Step {
                StepProgramCompletionId = stepProgramCompletion.Id
            });
        }
        /// <summary>
        /// Executes this instance.
        /// </summary>
        /// <param name="message"></param>
        public override void Execute(Message message)
        {
            var pageCache = PageCache.Get(message.PageGuid);

            if (pageCache == null)
            {
                return;
            }

            var rockContext = new RockContext();
            var interactionComponentService = new InteractionComponentService(rockContext);
            var componentQuery = interactionComponentService.QueryByPage(pageCache);

            rockContext.BulkUpdate(componentQuery, ic => new InteractionComponent {
                Name = pageCache.InternalName
            });
        }
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var familyGroupTypeId = GroupTypeCache.GetFamilyGroupType().Id;

            var rockContext = new RockContext();

            // just in case there are Groups that have a null or empty Name, update them.
            var familiesWithoutNames = new GroupService(rockContext)
                                       .Queryable().Where(a => a.GroupTypeId == familyGroupTypeId)
                                       .Where(a => string.IsNullOrEmpty(a.Name));

            if (familiesWithoutNames.Any())
            {
                rockContext.BulkUpdate(familiesWithoutNames, g => new Group {
                    Name = "Family"
                });
            }

            // Re-calculates all GroupSalutation values on Family Groups.
            var familyIdList = new GroupService(rockContext)
                               .Queryable().Where(a => a.GroupTypeId == familyGroupTypeId)
                               .Select(a => a.Id).ToList();

            foreach (var familyId in familyIdList)
            {
                try
                {
                    using (var rockContextUpdate = new RockContext())
                    {
                        GroupService.UpdateGroupSalutations(familyId, rockContextUpdate);
                    }
                }
                catch (Exception ex)
                {
                    ExceptionLogService.LogException(new Exception($"Error running the job 'PostV127DataMigrationsRebuildGroupSalutations'. UpdateGroupSalutations failed for Group Id {familyId}", ex));
                }
            }


            ServiceJobService.DeleteJob(context.GetJobId());
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Sends the note watch notifications.
        /// </summary>
        /// <param name="context">The context.</param>
        private List <string> SendNoteWatchNotifications(IJobExecutionContext context)
        {
            var        errors = new List <string>();
            List <int> noteIdsToProcessNoteWatchesList = new List <int>();

            using (var rockContext = new RockContext())
            {
                var noteService      = new NoteService(rockContext);
                var noteWatchService = new NoteWatchService(rockContext);
                var noteWatchQuery   = noteWatchService.Queryable();

                if (!noteWatchQuery.Any())
                {
                    // there aren't any note watches, so there is nothing to do
                    return(errors);
                }

                // get all notes that haven't processed notifications yet
                var notesToNotifyQuery = noteService.Queryable().Where(a =>
                                                                       a.NotificationsSent == false &&
                                                                       a.NoteType.AllowsWatching == true &&
                                                                       a.EditedDateTime > _cutoffNoteEditDateTime);

                // limit to notes that don't require approval or are approved
                notesToNotifyQuery = notesToNotifyQuery.Where(a => a.NoteType.RequiresApprovals == false || a.ApprovalStatus == NoteApprovalStatus.Approved);

                if (!notesToNotifyQuery.Any())
                {
                    // there aren't any notes that haven't had notifications processed yet
                    return(errors);
                }

                noteIdsToProcessNoteWatchesList = notesToNotifyQuery.Select(a => a.Id).ToList();
            }

            // make a list of notifications to send to each personId
            Dictionary <int, NoteWatchPersonToNotifyList> personNotificationDigestList = new Dictionary <int, NoteWatchPersonToNotifyList>();

            using (var rockContext = new RockContext())
            {
                foreach (int noteId in noteIdsToProcessNoteWatchesList)
                {
                    this.UpdateNoteWatchNotificationDigest(personNotificationDigestList, rockContext, noteId);
                }

                // Send NoteWatch notifications
                if (personNotificationDigestList.Any())
                {
                    foreach (var personNotificationDigest in personNotificationDigestList)
                    {
                        var         recipients     = new List <RecipientData>();
                        Person      personToNotify = personNotificationDigest.Value.Person;
                        List <Note> noteList       = personNotificationDigest.Value.Select(a => a.Note).OrderBy(a => a.EditedDateTime).ToList();

                        // make sure a person doesn't get a notification on a note that they wrote
                        noteList = noteList.Where(a => a.EditedByPersonAlias?.PersonId != personToNotify.Id).ToList();

                        if (!string.IsNullOrEmpty(personToNotify.Email) && personToNotify.IsEmailActive && personToNotify.EmailPreference != EmailPreference.DoNotEmail && noteList.Any())
                        {
                            var mergeFields = new Dictionary <string, object>(_defaultMergeFields);
                            mergeFields.Add("Person", personToNotify);
                            mergeFields.Add("NoteList", noteList);
                            recipients.Add(new RecipientData(personToNotify.Email, mergeFields));
                        }

                        if (_noteWatchNotificationEmailGuid.HasValue)
                        {
                            var emailMessage = new RockEmailMessage(_noteWatchNotificationEmailGuid.Value);
                            emailMessage.SetRecipients(recipients);
                            emailMessage.Send(out errors);
                            _noteWatchNotificationsSent += recipients.Count();
                        }
                    }
                }
            }

            using (var rockUpdateContext = new RockContext())
            {
                var notesToMarkNotified = new NoteService(rockUpdateContext).Queryable().Where(a => noteIdsToProcessNoteWatchesList.Contains(a.Id));

                // use BulkUpdate to mark all the notes that we processed to NotificationsSent = true
                rockUpdateContext.BulkUpdate(notesToMarkNotified, n => new Note {
                    NotificationsSent = true
                });
            }
            return(errors);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Sends the note approval notifications.
        /// </summary>
        /// <param name="context">The context.</param>
        private List <string> SendNoteApprovalNotifications(IJobExecutionContext context)
        {
            var        errors = new List <string>();
            List <int> noteIdsToProcessApprovalsList = new List <int>();

            using (var rockContext = new RockContext())
            {
                var noteService = new Rock.Model.NoteService(rockContext);

                // get all notes that are pending approval and haven't sent approval notifications yet
                var notesThatNeedApprovalNotifyQuery = noteService.Queryable().Where(a =>
                                                                                     a.NoteType.RequiresApprovals &&
                                                                                     a.NoteType.SendApprovalNotifications &&
                                                                                     a.ApprovalsSent == false &&
                                                                                     a.ApprovalStatus == NoteApprovalStatus.PendingApproval &&
                                                                                     a.EditedDateTime > _cutoffNoteEditDateTime);

                if (!notesThatNeedApprovalNotifyQuery.Any())
                {
                    // there aren't any notes that haven't had approval notifications processed yet
                    return(errors);
                }

                noteIdsToProcessApprovalsList = notesThatNeedApprovalNotifyQuery.Select(a => a.Id).ToList();
            }

            using (var rockContext = new RockContext())
            {
                // get the approvers for each notetypeId
                Dictionary <int, List <Person> > noteTypeApprovers = new Dictionary <int, List <Person> >();

                NoteTypeService noteTypeService     = new NoteTypeService(rockContext);
                var             noteTypeIdsForNotes = new NoteService(rockContext).Queryable()
                                                      .Where(a => noteIdsToProcessApprovalsList.Contains(a.Id)).Select(a => a.NoteTypeId).Distinct().ToList();

                foreach (var noteTypeId in noteTypeIdsForNotes)
                {
                    var approvers = noteTypeService.GetApprovers(noteTypeId).ToList();
                    noteTypeApprovers.Add(noteTypeId, approvers);
                }

                // make a list of notes for each approver so we can send a digest of notes to approve to each approver
                Dictionary <Person, List <Note> > approverNotesToApproveList = new Dictionary <Person, List <Note> >();
                foreach (var noteId in noteIdsToProcessApprovalsList)
                {
                    var noteService      = new Rock.Model.NoteService(rockContext);
                    var note             = noteService.Get(noteId);
                    var approversForNote = noteTypeApprovers.GetValueOrNull(note.NoteTypeId);
                    if (approversForNote?.Any() == true)
                    {
                        List <Note> notesToApprove;
                        foreach (Person approverPerson in approversForNote)
                        {
                            if (approverNotesToApproveList.ContainsKey(approverPerson))
                            {
                                notesToApprove = approverNotesToApproveList[approverPerson] ?? new List <Note>();
                            }
                            else
                            {
                                notesToApprove = new List <Note>();
                                approverNotesToApproveList.Add(approverPerson, notesToApprove);
                            }

                            notesToApprove.Add(note);
                        }
                    }
                    else
                    {
                        // if there are no approvers for this note type, leave it as pending approval
                    }
                }

                if (!approverNotesToApproveList.Any())
                {
                    // nothing to do so exit
                    return(errors);
                }

                // send approval emails
                var recipients = new List <RecipientData>();
                foreach (var approverNotesToApprove in approverNotesToApproveList)
                {
                    Person      approverPerson = approverNotesToApprove.Key;
                    List <Note> noteList       = approverNotesToApprove.Value;
                    if (!string.IsNullOrEmpty(approverPerson.Email) && approverPerson.IsEmailActive && noteList.Any())
                    {
                        var mergeFields = new Dictionary <string, object>(_defaultMergeFields);
                        mergeFields.Add("ApproverPerson", approverPerson);
                        mergeFields.Add("NoteList", noteList);
                        recipients.Add(new RecipientData(approverPerson.Email, mergeFields));
                    }

                    if (_noteApprovalNotificationEmailGuid.HasValue)
                    {
                        var emailMessage = new RockEmailMessage(_noteApprovalNotificationEmailGuid.Value);
                        emailMessage.SetRecipients(recipients);
                        emailMessage.Send(out errors);
                        _noteApprovalNotificationsSent += recipients.Count();

                        using (var rockUpdateContext = new RockContext())
                        {
                            var noteListIds             = noteList.Select(a => a.Id).ToList();
                            var notesToMarkApprovalSent = new NoteService(rockUpdateContext).Queryable().Where(a => noteListIds.Contains(a.Id));

                            // use BulkUpdate to mark all the notes that we processed to ApprovalsSent = true
                            rockUpdateContext.BulkUpdate(notesToMarkApprovalSent, n => new Note {
                                ApprovalsSent = true
                            });
                        }
                    }
                }
            }

            return(errors);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap            = context.JobDetail.JobDataMap;
            int        expirationDays     = dataMap.GetInt("ExpirationPeriod");
            int        delayMinutes       = dataMap.GetInt("DelayPeriod");
            int        maxParallelization = dataMap.GetInt("ParallelCommunications");

            List <Model.Communication> sendCommunications = null;
            var stopWatch = Stopwatch.StartNew();

            using (var rockContext = new RockContext())
            {
                sendCommunications = new CommunicationService(rockContext)
                                     .GetQueued(expirationDays, delayMinutes, false, false)
                                     .AsNoTracking()
                                     .ToList()
                                     .OrderBy(c => c.Id)
                                     .ToList();
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: Queued communication query runtime: {1} ms", nameof(SendCommunications), stopWatch.ElapsedMilliseconds);

            if (sendCommunications == null)
            {
                context.Result = "No communications to send";
            }

            var exceptionMsgs      = new List <string>();
            int communicationsSent = 0;

            stopWatch = Stopwatch.StartNew();
            var sendCommunicationTasks = new List <Task <SendCommunicationAsyncResult> >();

            RockLogger.Log.Debug(RockLogDomains.Jobs, "{0}: Send communications {1} communications.", nameof(SendCommunications), sendCommunicationTasks.Count);
            using (var mutex = new SemaphoreSlim(maxParallelization))
            {
                for (var i = 0; i < sendCommunications.Count(); i++)
                {
                    mutex.Wait();
                    var comm = sendCommunications[i];

                    sendCommunicationTasks.Add(Task.Run <SendCommunicationAsyncResult>(async() => await SendCommunicationAsync(comm, mutex).ConfigureAwait(false)));
                }

                /*
                 * Now that we have fired off all of the task, we need to wait for them to complete, get their results,
                 * and then process that result. Once all of the task have been completed we can continue.
                 */
                while (sendCommunicationTasks.Count > 0)
                {
                    // Wait for a task to complete using WhenAny and then return the completed task. Since we are not running in an asynchronous method we need to use RunSync.
                    var completedTask = AsyncHelper.RunSync(() => Task.WhenAny <SendCommunicationAsyncResult>(sendCommunicationTasks.ToArray()));

                    // Get and process the result of the completed task.
                    var communicationResult = completedTask.Result;
                    if (communicationResult.Exception != null)
                    {
                        var agException = communicationResult.Exception as AggregateException;
                        if (agException == null)
                        {
                            exceptionMsgs.Add($"Exception occurred sending communication ID:{communicationResult.Communication.Id}:{Environment.NewLine}    {communicationResult.Exception.Messages().AsDelimited( Environment.NewLine + "   " )}");
                        }
                        else
                        {
                            var allExceptions = agException.Flatten();
                            foreach (var ex in allExceptions.InnerExceptions)
                            {
                                exceptionMsgs.Add($"Exception occurred sending communication ID:{communicationResult.Communication.Id}:{Environment.NewLine}    {ex.Messages().AsDelimited( Environment.NewLine + "   " )}");
                            }
                        }

                        ExceptionLogService.LogException(communicationResult.Exception, System.Web.HttpContext.Current);
                    }
                    else
                    {
                        communicationsSent++;
                    }

                    sendCommunicationTasks.Remove(completedTask);
                }
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: Send communications runtime: {1} ms", nameof(SendCommunications), stopWatch.ElapsedMilliseconds);

            if (communicationsSent > 0)
            {
                context.Result = string.Format("Sent {0} {1}", communicationsSent, "communication".PluralizeIf(communicationsSent > 1));
            }
            else
            {
                context.Result = "No communications to send";
            }

            if (exceptionMsgs.Any())
            {
                throw new Exception("One or more exceptions occurred sending communications..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
            }

            // check for communications that have not been sent but are past the expire date. Mark them as failed and set a warning.
            var expireDateTimeEndWindow = RockDateTime.Now.AddDays(0 - expirationDays);

            // limit the query to only look a week prior to the window to avoid performance issue (it could be slow to query at ALL the communication recipient before the expire date, as there could several years worth )
            var expireDateTimeBeginWindow = expireDateTimeEndWindow.AddDays(-7);

            stopWatch = Stopwatch.StartNew();
            using (var rockContext = new RockContext())
            {
                var qryExpiredRecipients = new CommunicationRecipientService(rockContext).Queryable()
                                           .Where(cr =>
                                                  cr.Communication.Status == CommunicationStatus.Approved &&
                                                  cr.Status == CommunicationRecipientStatus.Pending &&
                                                  (
                                                      (!cr.Communication.FutureSendDateTime.HasValue && cr.Communication.ReviewedDateTime.HasValue && cr.Communication.ReviewedDateTime <expireDateTimeEndWindow && cr.Communication.ReviewedDateTime> expireDateTimeBeginWindow) ||
                                                      (cr.Communication.FutureSendDateTime.HasValue && cr.Communication.FutureSendDateTime <expireDateTimeEndWindow && cr.Communication.FutureSendDateTime> expireDateTimeBeginWindow)
                                                  ));

                rockContext.BulkUpdate(qryExpiredRecipients, c => new CommunicationRecipient {
                    Status = CommunicationRecipientStatus.Failed, StatusNote = "Communication was not sent before the expire window (possibly due to delayed approval)."
                });
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: Query expired communications runtime: {1} ms", nameof(SendCommunications), stopWatch.ElapsedMilliseconds);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Updates Group Historical for any groups that have data group history enabled
        /// </summary>
        /// <param name="context">The context.</param>
        public void UpdateGroupHistorical(IJobExecutionContext context)
        {
            var rockContext            = new RockContext();
            var groupHistoricalService = new GroupHistoricalService(rockContext);
            var groupService           = new GroupService(rockContext);

            // Note that this query utilizes .AsNoFilter() to avoid having archived groups filtered out by the GroupConfiguration class.
            var groupsWithHistoryEnabledQuery = groupService.AsNoFilter()
                                                .Where(a => a.GroupType.EnableGroupHistory == true)
                                                .AsNoTracking();

            var groupHistoricalsCurrentQuery = groupHistoricalService.Queryable().Where(a => a.CurrentRowIndicator == true).AsNoTracking();

            // Mark GroupHistorical Rows as History ( CurrentRowIndicator = false, etc ) if any of the tracked field values change
            var groupHistoricalNoLongerCurrent = groupHistoricalsCurrentQuery.Join(
                groupsWithHistoryEnabledQuery,
                gh => gh.GroupId,
                g => g.Id, (gh, g) => new
            {
                Group           = g,
                GroupHistorical = gh
            })
                                                 .Where(a =>
                                                        a.Group.Name != a.GroupHistorical.GroupName ||
                                                        a.Group.GroupType.Name != a.GroupHistorical.GroupTypeName ||
                                                        a.Group.CampusId != a.GroupHistorical.CampusId ||
                                                        a.Group.ParentGroupId != a.GroupHistorical.ParentGroupId ||
                                                        a.Group.ScheduleId != a.GroupHistorical.ScheduleId ||
                                                        (a.Group.ScheduleId.HasValue && (a.Group.Schedule.ModifiedDateTime != a.GroupHistorical.ScheduleModifiedDateTime)) ||
                                                        a.Group.Description != a.GroupHistorical.Description ||
                                                        a.Group.StatusValueId != a.GroupHistorical.StatusValueId ||
                                                        a.Group.IsArchived != a.GroupHistorical.IsArchived ||
                                                        a.Group.ArchivedDateTime != a.GroupHistorical.ArchivedDateTime ||
                                                        a.Group.ArchivedByPersonAliasId != a.GroupHistorical.ArchivedByPersonAliasId ||
                                                        a.Group.IsActive != a.GroupHistorical.IsActive ||
                                                        a.Group.InactiveDateTime != a.GroupHistorical.InactiveDateTime
                                                        ).Select(a => a.GroupHistorical).AsNoTracking();

            var effectiveExpireDateTime = RockDateTime.Now;

            int groupsLoggedToHistory      = 0;
            int groupsSaveToHistoryCurrent = 0;

            if (groupHistoricalNoLongerCurrent.Any())
            {
                groupsLoggedToHistory = rockContext.BulkUpdate(groupHistoricalNoLongerCurrent, gh => new GroupHistorical
                {
                    CurrentRowIndicator = false,
                    ExpireDateTime      = effectiveExpireDateTime
                });
            }

            // Insert Groups (that have GroupType.EnableGroupHistory) that don't have a CurrentRowIndicator row yet ( or don't have a CurrentRowIndicator because it was stamped with CurrentRowIndicator=false )
            var groupsToAddToHistoricalCurrentsQuery = groupsWithHistoryEnabledQuery.Where(g => !groupHistoricalsCurrentQuery.Any(gh => gh.GroupId == g.Id)).AsNoTracking();

            if (groupsToAddToHistoricalCurrentsQuery.Any())
            {
                List <GroupHistorical> groupHistoricalCurrentsToInsert = groupsToAddToHistoricalCurrentsQuery
                                                                         .Include(a => a.GroupType)
                                                                         .Include(a => a.Schedule)
                                                                         .ToList()
                                                                         .Select(g => GroupHistorical.CreateCurrentRowFromGroup(g, effectiveExpireDateTime)).ToList();

                groupsSaveToHistoryCurrent = groupHistoricalCurrentsToInsert.Count();

                rockContext.BulkInsert(groupHistoricalCurrentsToInsert);
            }

            if (groupsLoggedToHistory > 0)
            {
                _jobStatusMessages.Add($"Logged {groupsLoggedToHistory} {"group history snapshot".PluralizeIf( groupsLoggedToHistory != 0 )}");
            }

            if (groupsSaveToHistoryCurrent > 0)
            {
                int newGroupsAddedToHistory = groupsSaveToHistoryCurrent - groupsLoggedToHistory;
                if (newGroupsAddedToHistory > 0)
                {
                    _jobStatusMessages.Add($"Added {newGroupsAddedToHistory} new {"group history snapshot".PluralizeIf( newGroupsAddedToHistory != 0 )}");
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Updates GroupLocationHistorical for any group locations in groups that have data group history enabled
        /// </summary>
        /// <param name="context">The context.</param>
        public void UpdateGroupLocationHistorical(IJobExecutionContext context)
        {
            var rockContext = new RockContext();
            var groupLocationHistoricalService = new GroupLocationHistoricalService(rockContext);
            var groupLocationService           = new GroupLocationService(rockContext);

            var groupLocationsWithHistoryEnabledQuery = groupLocationService.Queryable().Where(a => a.Group.GroupType.EnableGroupHistory == true).AsNoTracking();
            var groupLocationsHistoricalCurrentQuery  = groupLocationHistoricalService.Queryable().Where(a => a.CurrentRowIndicator == true).AsNoTracking();

            // Mark GroupLocationHistorical Rows as History ( CurrentRowIndicator = false, etc ) if any of the tracked field values change
            var groupLocationHistoricalNoLongerCurrentQuery = groupLocationsHistoricalCurrentQuery.Join(
                groupLocationsWithHistoryEnabledQuery,
                glh => glh.GroupLocationId,
                gl => gl.Id, (glh, gl) => new
            {
                GroupLocation           = gl,
                GroupLocationHistorical = glh
            })
                                                              .Where(a =>
                                                                     a.GroupLocation.GroupId != a.GroupLocationHistorical.GroupId ||
                                                                     (a.GroupLocation.GroupLocationTypeValueId != a.GroupLocation.GroupLocationTypeValueId) ||
                                                                     (a.GroupLocation.GroupLocationTypeValueId.HasValue && a.GroupLocation.GroupLocationTypeValue.Value != a.GroupLocationHistorical.GroupLocationTypeName) ||
                                                                     a.GroupLocation.LocationId != a.GroupLocationHistorical.LocationId ||
                                                                     a.GroupLocation.Location.ModifiedDateTime != a.GroupLocationHistorical.LocationModifiedDateTime ||
                                                                     (a.GroupLocation.Schedules.Select(s => new { ScheduleId = s.Id, s.ModifiedDateTime }).Except(a.GroupLocationHistorical.GroupLocationHistoricalSchedules.Select(hs => new { hs.ScheduleId, ModifiedDateTime = hs.ScheduleModifiedDateTime }))).Any()
                                                                     );

            var effectiveExpireDateTime            = RockDateTime.Now;
            int groupLocationsLoggedToHistory      = 0;
            int groupLocationsSaveToHistoryCurrent = 0;

            if (groupLocationHistoricalNoLongerCurrentQuery.Any())
            {
                var groupLocationHistoricalNoLongerCurrent = groupLocationHistoricalNoLongerCurrentQuery.Select(a => a.GroupLocationHistorical).AsNoTracking();

                groupLocationsLoggedToHistory = rockContext.BulkUpdate(groupLocationHistoricalNoLongerCurrent, glh => new GroupLocationHistorical
                {
                    CurrentRowIndicator = false,
                    ExpireDateTime      = effectiveExpireDateTime
                });
            }

            // Insert Group Locations (that have a group with GroupType.EnableGroupHistory) that don't have a CurrentRowIndicator row yet ( or don't have a CurrentRowIndicator because it was stamped with CurrentRowIndicator=false )
            var groupLocationsToAddToHistoricalCurrentsQuery = groupLocationsWithHistoryEnabledQuery.Where(gl => !groupLocationsHistoricalCurrentQuery.Any(glh => glh.GroupLocationId == gl.Id));

            if (groupLocationsToAddToHistoricalCurrentsQuery.Any())
            {
                List <GroupLocationHistorical> groupLocationHistoricalCurrentsToInsert = groupLocationsToAddToHistoricalCurrentsQuery
                                                                                         .Include(a => a.GroupLocationTypeValue)
                                                                                         .Include(a => a.Location).ToList()
                                                                                         .Select(gl => GroupLocationHistorical.CreateCurrentRowFromGroupLocation(gl, effectiveExpireDateTime)).ToList();

                groupLocationsSaveToHistoryCurrent = groupLocationHistoricalCurrentsToInsert.Count();

                // get the current max GroupLocatiionHistorical.Id to help narrow down which ones were inserted
                int groupLocationHistoricalStartId = groupLocationHistoricalService.Queryable().Max(a => ( int? )a.Id) ?? 0;

                rockContext.BulkInsert(groupLocationHistoricalCurrentsToInsert);

                // since we used BulkInsert, we'll need to go back and get the Ids and the associated GroupLocation's Schedules for the GroupLocationHistorical records that we just inserted
                var insertedGroupLocationHistoricalIdsWithSchedules = groupLocationHistoricalService.Queryable()
                                                                      .Where(a => a.Id > groupLocationHistoricalStartId && a.GroupLocation.Schedules.Any()).ToList()
                                                                      .Select(a => new { GroupLocationHistoricalId = a.Id, a.GroupLocation.Schedules });

                List <GroupLocationHistoricalSchedule> groupLocationHistoricalScheduleCurrentsToInsert = new List <GroupLocationHistoricalSchedule>();
                foreach (var insertedGroupLocationHistoricalIdWithSchedules in insertedGroupLocationHistoricalIdsWithSchedules)
                {
                    foreach (Schedule schedule in insertedGroupLocationHistoricalIdWithSchedules.Schedules)
                    {
                        groupLocationHistoricalScheduleCurrentsToInsert.Add(new GroupLocationHistoricalSchedule
                        {
                            GroupLocationHistoricalId = insertedGroupLocationHistoricalIdWithSchedules.GroupLocationHistoricalId,
                            ScheduleId               = schedule.Id,
                            ScheduleName             = schedule.ToString(),
                            ScheduleModifiedDateTime = schedule.ModifiedDateTime
                        });
                    }
                }

                if (groupLocationHistoricalScheduleCurrentsToInsert.Any())
                {
                    rockContext.BulkInsert(groupLocationHistoricalScheduleCurrentsToInsert);
                }
            }

            if (groupLocationsLoggedToHistory > 0)
            {
                _jobStatusMessages.Add($"Logged {groupLocationsLoggedToHistory} {"group location history snapshot".PluralizeIf( groupLocationsLoggedToHistory != 0 )}");
            }

            if (groupLocationsSaveToHistoryCurrent > 0)
            {
                int newGroupLocationsAddedToHistory = groupLocationsSaveToHistoryCurrent - groupLocationsLoggedToHistory;
                if (newGroupLocationsAddedToHistory > 0)
                {
                    _jobStatusMessages.Add($"Added {newGroupLocationsAddedToHistory} new {"group location history snapshot".PluralizeIf( newGroupLocationsAddedToHistory != 0 )}");
                }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Updates GroupMemberHistorical for any group members in groups that have data group history enabled
        /// </summary>
        /// <param name="context">The context.</param>
        public void UpdateGroupMemberHistorical(IJobExecutionContext context)
        {
            var rockContext = new RockContext();
            var groupMemberHistoricalService = new GroupMemberHistoricalService(rockContext);
            var groupMemberService           = new GroupMemberService(rockContext);

            var groupMembersWithHistoryEnabledQuery = groupMemberService.AsNoFilter().Where(a => a.Group.GroupType.EnableGroupHistory == true).AsNoTracking();
            var groupMemberHistoricalsCurrentQuery  = groupMemberHistoricalService.Queryable().Where(a => a.CurrentRowIndicator == true).AsNoTracking();

            // Mark GroupMemberHistorical Rows as History ( CurrentRowIndicator = false, etc ) if any of the tracked field values change
            var groupMemberHistoricalNoLongerCurrent = groupMemberHistoricalsCurrentQuery.Join(
                groupMembersWithHistoryEnabledQuery,
                gmh => gmh.GroupMemberId,
                gm => gm.Id, (gmh, gm) => new
            {
                GroupMember           = gm,
                GroupMemberHistorical = gmh
            })
                                                       .Where(a =>
                                                              a.GroupMember.GroupRoleId != a.GroupMemberHistorical.GroupRoleId ||
                                                              a.GroupMember.GroupId != a.GroupMemberHistorical.GroupId ||
                                                              a.GroupMember.GroupRole.Name != a.GroupMemberHistorical.GroupRoleName ||
                                                              a.GroupMember.GroupRole.IsLeader != a.GroupMemberHistorical.IsLeader ||
                                                              a.GroupMember.GroupMemberStatus != a.GroupMemberHistorical.GroupMemberStatus ||
                                                              a.GroupMember.IsArchived != a.GroupMemberHistorical.IsArchived ||
                                                              a.GroupMember.ArchivedDateTime != a.GroupMemberHistorical.ArchivedDateTime ||
                                                              a.GroupMember.ArchivedByPersonAliasId != a.GroupMemberHistorical.ArchivedByPersonAliasId ||
                                                              a.GroupMember.InactiveDateTime != a.GroupMemberHistorical.InactiveDateTime
                                                              ).Select(a => a.GroupMemberHistorical).AsNoTracking();

            var effectiveExpireDateTime = RockDateTime.Now;

            int groupMembersLoggedToHistory      = 0;
            int groupMembersSaveToHistoryCurrent = 0;

            if (groupMemberHistoricalNoLongerCurrent.Any())
            {
                groupMembersLoggedToHistory = rockContext.BulkUpdate(groupMemberHistoricalNoLongerCurrent, gmh => new GroupMemberHistorical
                {
                    CurrentRowIndicator = false,
                    ExpireDateTime      = effectiveExpireDateTime
                });
            }

            // Insert Group Members (that have a group with GroupType.EnableGroupHistory) that don't have a CurrentRowIndicator row yet ( or don't have a CurrentRowIndicator because it was stamped with CurrentRowIndicator=false )
            var groupMembersToAddToHistoricalCurrentsQuery = groupMembersWithHistoryEnabledQuery.Where(gm => !groupMemberHistoricalsCurrentQuery.Any(gmh => gmh.GroupMemberId == gm.Id));

            if (groupMembersToAddToHistoricalCurrentsQuery.Any())
            {
                List <GroupMemberHistorical> groupMemberHistoricalCurrentsToInsert = groupMembersToAddToHistoricalCurrentsQuery
                                                                                     .Include(a => a.GroupRole)
                                                                                     .ToList()
                                                                                     .Select(gm => GroupMemberHistorical.CreateCurrentRowFromGroupMember(gm, effectiveExpireDateTime)).ToList();

                groupMembersSaveToHistoryCurrent = groupMemberHistoricalCurrentsToInsert.Count();

                rockContext.BulkInsert(groupMemberHistoricalCurrentsToInsert);
            }

            if (groupMembersLoggedToHistory > 0)
            {
                _jobStatusMessages.Add($"Logged {groupMembersLoggedToHistory} {"group member history snapshot".PluralizeIf( groupMembersLoggedToHistory != 0 )}");
            }

            if (groupMembersSaveToHistoryCurrent > 0)
            {
                int newGroupMembersAddedToHistory = groupMembersSaveToHistoryCurrent - groupMembersLoggedToHistory;
                if (newGroupMembersAddedToHistory > 0)
                {
                    _jobStatusMessages.Add($"Added {newGroupMembersAddedToHistory} new {"group member history snapshot".PluralizeIf( newGroupMembersAddedToHistory != 0 )}");
                }
            }
        }