public void GetBookmarks()
        {
            IHistoryService service = new HistoryService();
            const int       userId  = 290;

            const int postId1 = 19;
            const int postId2 = 709;
            const int postId3 = 1760;
            const int postId4 = 1711;

            bool addResult1 = service.Add(userId, postId1, false);
            bool addResult2 = service.Add(userId, postId2, true);
            bool addResult3 = service.Add(userId, postId3, true);
            bool addResult4 = service.Add(userId, postId4, false);
            var  history    = service.GetBookmarkList(userId);


            //clean up todo delete when mock is working
            service.DeleteHistory(service.Get(userId, postId1).Id);
            service.DeleteHistory(service.Get(userId, postId2).Id);
            service.DeleteHistory(service.Get(userId, postId3).Id);
            service.DeleteHistory(service.Get(userId, postId4).Id);
            //end of clean up

            Assert.True(addResult1);
            Assert.True(addResult2);
            Assert.True(addResult3);
            Assert.True(addResult4);

            Assert.Equal(2, history.Count);
            Assert.Equal(postId3, history[1].Postid);
            Assert.Equal(postId2, history[0].Postid);
        }
        public void HistoryDeleteUserHistory()
        {
            IHistoryService service = new HistoryService();
            const int       userid  = 290;

            const int postId1 = 19;
            const int postId2 = 709;
            const int postId3 = 1760;
            const int postId4 = 1711;

            bool addResult1 = service.Add(userid, postId1, false);
            bool addResult2 = service.Add(userid, postId2, false);
            bool addResult3 = service.Add(userid, postId3, true);
            bool addResult4 = service.Add(userid, postId4, false);

            var  historyPre      = service.GetHistoryList(userid);
            bool historyDeletion = service.DeleteUserHistory(userid);
            var  historyPost     = service.GetHistoryList(userid);

            //clean up todo delete when mock is working
            service.DeleteHistory(service.Get(userid, postId3).Id);
            //end of clean up

            Assert.True(addResult1);
            Assert.True(addResult2);
            Assert.True(addResult3);
            Assert.True(addResult4);

            Assert.Equal(3, historyPre.Count);
            Assert.True(historyDeletion);
            Assert.Empty(historyPost);
        }
Exemple #3
0
        public async Task Add_Should_Pass()
        {
            var repositoryMock = new Mock <IHistoryRepository>();
            var mockDbSet      = new Mock <DbSet <HistoryRecord> >();

            repositoryMock
            .Setup(c => c.Histories)
            .Returns(mockDbSet.Object);

            var value = new HistoryViewModel
            {
                Operation = "add",
                NewValue  = "5"
            };
            var key = "Calculator[1]";

            var service = new HistoryService(repositoryMock.Object);
            await service.Add(key, value, CancellationToken.None);

            var result = await service.Add(key, value, CancellationToken.None);

            Assert.AreEqual("add", result.Operation);
            Assert.AreEqual(null, result.OldValue);
            Assert.AreEqual("5", result.NewValue);
        }
        public async Task Play()
        {
            TrackCollection.IsRunning = true;
            Stop();
            var trackItem = TrackCollection.TrackCollection[TrackCollection.CurrentTrack];

            var file = await StorageFile.GetFileFromPathAsync(trackItem.Path);

            string token = await _historyService.Add(file);

            Debug.WriteLine("Opening file: " + file.Path);

            SetActiveMusicInfo(token, trackItem);

            // Setting the info for windows 8 controls
            var resourceLoader = new ResourceLoader();

            MediaControl.IsPlaying  = true;
            MediaControl.ArtistName = trackItem.ArtistName ?? resourceLoader.GetString("UnknownArtist");
            MediaControl.TrackName  = trackItem.Name ?? resourceLoader.GetString("UnknownTrack");
            _timeTotal   = TimeSpan.Zero;
            _elapsedTime = TimeSpan.Zero;
            try
            {
                MediaControl.AlbumArt = new Uri(Locator.MusicPlayerVM.Artist.CurrentAlbumItem.Picture);
            }
            catch
            {
                // If album cover is from the internet then it's impossible to pass it to the MediaControl
            }

            TrackCollection.IsNextPossible();
            TrackCollection.IsPreviousPossible();

            if (TrackCollection.CanGoNext)
            {
                MediaControl.NextTrackPressed += MediaControl_NextTrackPressed;
            }
            else
            {
                MediaControl.NextTrackPressed -= MediaControl_NextTrackPressed;
            }

            if (TrackCollection.CanGoPrevious)
            {
                MediaControl.PreviousTrackPressed += MediaControl_PreviousTrackPressed;
            }
            else
            {
                MediaControl.PreviousTrackPressed -= MediaControl_PreviousTrackPressed;
            }
        }
Exemple #5
0
        public static void AddExitHistory(RockContext rockContext, Location location, Attendance attendeeAttendance, bool isSubroom)
        {
            HistoryService historyService = new HistoryService(rockContext);
            var            summary        = string.Format("Exited <span class=\"field-name\">{0}</span> at <span class=\"field-name\">{1}</span>", location.Name, Rock.RockDateTime.Now);

            if (isSubroom)
            {
                summary += string.Format(" (a subroom of <span class=\"field-name\">{0}</span>)", location.ParentLocation.Name);
            }

            History history = new History()
            {
                EntityTypeId        = personEntityTypeId,
                EntityId            = attendeeAttendance.PersonAlias.PersonId,
                RelatedEntityTypeId = locationEntityTypeId,
                RelatedEntityId     = location.Id,
                Verb        = "Exit",
                Summary     = summary,
                Caption     = "Exited Location",
                RelatedData = GetHostInfo(),
                CategoryId  = 4
            };

            historyService.Add(history);
            InMemoryPersonStatus.RemoveFromWorship(attendeeAttendance.PersonAlias.PersonId);
        }
Exemple #6
0
        public static void AddMoveHistory(RockContext rockContext, Location location, Attendance attendeeAttendance, Person authorizedPerson, bool isSubroom)
        {
            HistoryService historyService = new HistoryService(rockContext);
            var            moveSummary    = string.Format("Moved to and Entered <span class=\"field-name\">{0}</span> at <span class=\"field-name\">{1}</span> under the authority of {2}", location.Name, Rock.RockDateTime.Now, authorizedPerson.FullName);

            if (isSubroom)
            {
                moveSummary += string.Format(" (a subroom of <span class=\"field-name\">{0}</span>)", location.ParentLocation.Name);
            }

            History moveHistory = new History()
            {
                EntityTypeId        = personEntityTypeId,
                EntityId            = attendeeAttendance.PersonAlias.PersonId,
                RelatedEntityTypeId = locationEntityTypeId,
                RelatedEntityId     = location.Id,
                Verb        = "Entry",
                Summary     = moveSummary,
                Caption     = "Moved To Location",
                RelatedData = GetHostInfo(),
                CategoryId  = 4
            };

            historyService.Add(moveHistory);
        }
        protected void Distribute_Click(object sender, Rock.Web.UI.Controls.RowEventArgs e)
        {
            RockContext    rockContext    = new RockContext();
            HistoryService historyService = new HistoryService(rockContext);
            var            keys           = (( string )e.RowKeyValue).SplitDelimitedValues();
            var            personId       = keys[0].AsInteger();
            var            matrixId       = keys[1].AsInteger();
            var            scheduleGuid   = keys[2].AsGuid();

            AttributeMatrixItemService attributeMatrixItemService = new AttributeMatrixItemService(rockContext);
            var matrix = attributeMatrixItemService.Get(matrixId);

            matrix.LoadAttributes();
            var category = new CategoryService(rockContext).Get(GetAttributeValue("HistoryCategory").AsGuid());

            History history = new History()
            {
                CategoryId          = category.Id,
                EntityTypeId        = EntityTypeCache.GetId <Person>().Value,
                EntityId            = personId,
                RelatedEntityTypeId = EntityTypeCache.GetId <AttributeMatrixItem>().Value,
                RelatedEntityId     = matrixId,
                Verb        = "Distributed",
                Caption     = "Medication Distributed",
                Summary     = string.Format("<span class=\"field-name\">{0}</span> was distributed at <span class=\"field-name\">{1}</span>", matrix.GetAttributeValue("Medication"), Rock.RockDateTime.Now),
                RelatedData = scheduleGuid.ToString()
            };

            historyService.Add(history);
            rockContext.SaveChanges();
            BindGrid();
        }
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            errorMessages = new List <string>();

            var personGuid = GetAttributeValue(action, "Person", true).AsGuidOrNull();

            if (personGuid == null)
            {
                errorMessages.Add("Person Add History requires a valid person");
                return(false);
            }

            var categoryGuid = GetAttributeValue(action, "Category").AsGuid();
            var category     = new CategoryService(rockContext).Get(categoryGuid);

            if (category == null)
            {
                errorMessages.Add("Person Add History requires a valid category");
                return(false);
            }

            PersonAliasService personAliasService = new PersonAliasService(rockContext);
            var personAlias = personAliasService.Get(personGuid.Value);

            if (personAlias != null)
            {
                var            person               = personAlias.Person;
                var            entityTypeId         = EntityTypeCache.GetId(typeof(Rock.Model.Person));
                var            workflowEntityTypeId = EntityTypeCache.GetId(typeof(Rock.Model.Workflow));
                var            mergeFields          = GetMergeFields(action);
                var            caption              = GetAttributeValue(action, "Caption").ResolveMergeFields(mergeFields);
                var            summary              = GetAttributeValue(action, "Summary").ResolveMergeFields(mergeFields);
                var            verb           = GetAttributeValue(action, "Verb").ResolveMergeFields(mergeFields);
                HistoryService historyService = new HistoryService(rockContext);
                History        history        = new History
                {
                    Caption      = caption,
                    Summary      = summary,
                    Verb         = verb,
                    EntityId     = person.Id,
                    EntityTypeId = entityTypeId.Value,
                    CategoryId   = category.Id
                };
                if (action?.Activity?.Workflow != null && action.Activity.WorkflowId != 0)
                {
                    history.RelatedEntityTypeId = workflowEntityTypeId;
                    history.RelatedEntityId     = action.Activity.WorkflowId;
                }
                historyService.Add(history);
                rockContext.SaveChanges();

                return(true);
            }
            else
            {
                errorMessages.Add("Person Add History requires a valid person");
                return(false);
            }
        }
Exemple #9
0
        private async Task SendToCommunicationRecipient(Model.Communication communication, string fromPhone, Dictionary <string, object> mergeFields, Person currentPerson, List <Uri> attachmentMediaUrls, int personEntityTypeId, int communicationCategoryId, int communicationEntityTypeId, string publicAppRoot, string callbackUrl, CommunicationRecipient recipient)
        {
            using (var rockContext = new RockContext())
            {
                try
                {
                    recipient = new CommunicationRecipientService(rockContext).Get(recipient.Id);
                    var twilioNumber = recipient.PersonAlias.Person.PhoneNumbers.GetFirstSmsNumber();
                    if (!string.IsNullOrWhiteSpace(twilioNumber))
                    {
                        // Create merge field dictionary
                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                        string message = ResolveText(communication.SMSMessage, currentPerson, recipient, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                        var response = await SendToTwilioAsync(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber).ConfigureAwait(false);

                        recipient.Status                  = CommunicationRecipientStatus.Delivered;
                        recipient.SendDateTime            = RockDateTime.Now;
                        recipient.TransportEntityTypeName = this.GetType().FullName;
                        recipient.UniqueMessageId         = response.Sid;

                        try
                        {
                            var historyService = new HistoryService(rockContext);
                            historyService.Add(new History
                            {
                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                EntityTypeId           = personEntityTypeId,
                                CategoryId             = communicationCategoryId,
                                EntityId            = recipient.PersonAlias.PersonId,
                                Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                ChangeType          = History.HistoryChangeType.Record.ToString(),
                                ValueName           = "SMS message",
                                Caption             = message.Truncate(200),
                                RelatedEntityTypeId = communicationEntityTypeId,
                                RelatedEntityId     = communication.Id
                            });
                        }
                        catch (Exception ex)
                        {
                            ExceptionLogService.LogException(ex, null);
                        }
                    }
                    else
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "No Phone Number with Messaging Enabled";
                    }
                }
                catch (Exception ex)
                {
                    recipient.Status     = CommunicationRecipientStatus.Failed;
                    recipient.StatusNote = "Twilio Exception: " + ex.Message;
                }

                rockContext.SaveChanges();
            }
        }
        public void HistoryAddInvalid()
        {
            IHistoryService service = new HistoryService();
            var             history = new History
            {
                Userid     = 15,
                Postid     = 110,
                isBookmark = false
            };

            Assert.False(service.Add(history));
        }
        public void HistoryDeleteBookmarkValid()
        {
            IHistoryService service = new HistoryService();

            const int userid = 290;
            const int postId = 1760;

            bool resultAdd = service.Add(userid, postId, true);

            Assert.True(resultAdd);
            Assert.True(service.DeleteBookmark(userid, postId));

            //clean up todo delete when mock is working
            service.DeleteHistory(service.Get(userid, postId).Id);
        }
        public void HistoryDeleteBookmarkInvalidUserAndPost()
        {
            IHistoryService service = new HistoryService();

            const int invalidModifier = -1;
            const int userid          = 290;
            const int postId          = 1711;

            bool resultAdd = service.Add(userid, postId, true);

            Assert.True(resultAdd);
            Assert.False(service.DeleteBookmark(userid * invalidModifier, postId * invalidModifier));

            //clean up todo delete when mock is working
            service.DeleteHistory(service.Get(userid, postId).Id);
        }
        public void HistoryAddValid()
        {
            IHistoryService service = new HistoryService();
            var             history = new History
            {
                Userid     = 0,
                Postid     = 1760,
                isBookmark = false
            };

            bool result = service.Add(history);

            Assert.True(result);

            //clean up todo delete when mock is working
            service.DeleteHistory(service.Get(0, 1760).Id);
        }
        public void HistoryDeleteValid()
        {
            IHistoryService service      = new HistoryService();
            const int       userId       = 0;
            const int       postId       = 709;
            const bool      isBookmark   = true;
            var             historyToAdd = new History {
                Userid = userId, Postid = postId, isBookmark = isBookmark
            };

            bool    resultAdd = service.Add(historyToAdd);
            History history   = service.Get(userId, postId);

            Assert.True(resultAdd);
            Assert.True(service.HistoryExist(history.Id));
            Assert.True(service.DeleteHistory(history.Id));
            Assert.False(service.HistoryExist(history.Id));
        }
Exemple #15
0
        public static void AddWithParentHistory(RockContext rockContext, Person person)
        {
            HistoryService historyService = new HistoryService(rockContext);
            var            summary        = string.Format("Moved to be with Parent at <span class=\"field-name\">{0}</span>", Rock.RockDateTime.Now);

            History history = new History()
            {
                EntityTypeId = personEntityTypeId,
                EntityId     = person.Id,
                Verb         = "Moved",
                Summary      = summary,
                Caption      = "Moved be with Parent",
                RelatedData  = GetHostInfo(),
                CategoryId   = 4
            };

            historyService.Add(history);
            AttendanceCache.SetWithParent(person.Id);
        }
 public IActionResult CashedOut(int?WithdrawnCash, string UserName)
 {
     if (UserName != null && WithdrawnCash != null)
     {
         string       resultMessage = "Insufficient funds on the card";
         HistoryModel history       = new HistoryModel {
             UsedUserName = UserName, WithdrawnCash = WithdrawnCash.Value
         };
         if (WithdrawnCash <= CustomerService.GetBalance(UserName))
         {
             resultMessage          = "Please take your money";
             history.OperationState = true;
             CustomerService.BalanceUpdate(WithdrawnCash.Value, UserName);
         }
         HistoryService.Add(history);
         return(Ok(new { history = HistoryService.GetHistory(UserName), resultMessage }));
     }
     return(BadRequest());
 }
Exemple #17
0
        public static void AddMoveTwoWorshipHistory(RockContext rockContext, Person person)
        {
            HistoryService historyService = new HistoryService(rockContext);
            var            summary        = string.Format("Moved to Worship at <span class=\"field-name\">{0}</span>", Rock.RockDateTime.Now);

            History history = new History()
            {
                EntityTypeId = personEntityTypeId,
                EntityId     = person.Id,
                Verb         = "Moved",
                Summary      = summary,
                Caption      = "Moved To Worship",
                RelatedData  = GetHostInfo(),
                CategoryId   = 4
            };

            historyService.Add(history);
            InMemoryPersonStatus.AddToWorship(person.Id);
        }
Exemple #18
0
        public static void AddReturnToRoomHistory(RockContext rockContext, Person person)
        {
            var            summary        = "";
            var            caption        = "";
            HistoryService historyService = new HistoryService(rockContext);

            if (InMemoryPersonStatus.IsInWorship(person.Id) && InMemoryPersonStatus.IsWithParent(person.Id))
            {
                InMemoryPersonStatus.RemoveFromWorship(person.Id);
                InMemoryPersonStatus.RemoveFromWithParent(person.Id);
                summary = string.Format("Returned from Worship and Parent at <span class=\"field-name\">{0}</span>", Rock.RockDateTime.Now);
                caption = "Returned from Worship and Parent";
            }
            else if (InMemoryPersonStatus.IsInWorship(person.Id))
            {
                InMemoryPersonStatus.RemoveFromWorship(person.Id);
                summary = string.Format("Returned from Worship at <span class=\"field-name\">{0}</span>", Rock.RockDateTime.Now);
                caption = "Returned from Worship";
            }
            else if (InMemoryPersonStatus.IsWithParent(person.Id))
            {
                InMemoryPersonStatus.RemoveFromWithParent(person.Id);
                summary = string.Format("Returned from Parent at <span class=\"field-name\">{0}</span>", Rock.RockDateTime.Now);
                caption = "Returned from Parent";
            }
            if (!string.IsNullOrWhiteSpace(caption))
            {
                History history = new History()
                {
                    EntityTypeId = personEntityTypeId,
                    EntityId     = person.Id,
                    Verb         = "Returned",
                    Summary      = summary,
                    Caption      = "Returned from Worship",
                    RelatedData  = GetHostInfo(),
                    CategoryId   = 4
                };
                historyService.Add(history);
            }
        }
Exemple #19
0
        public static void AddReturnToRoomHistory(RockContext rockContext, Person person)
        {
            HistoryService historyService = new HistoryService(rockContext);

            if (AttendanceCache.IsWithParent(person.Id))
            {
                AttendanceCache.RemoveWithParent(person.Id);
                var summary = string.Format("Returned from Parent at <span class=\"field-name\">{0}</span>", Rock.RockDateTime.Now);

                History history = new History()
                {
                    EntityTypeId = personEntityTypeId,
                    EntityId     = person.Id,
                    Verb         = "Returned",
                    Summary      = summary,
                    Caption      = "Returned from Parent",
                    RelatedData  = GetHostInfo(),
                    CategoryId   = 4
                };
                historyService.Add(history);
            }
        }
        public void HistoryGetValid()
        {
            IHistoryService service = new HistoryService();

            const int  userId     = 0;
            const int  postId     = 709;
            const bool isBookmark = true;
            var        history    = new History {
                Userid = userId, Postid = postId, isBookmark = isBookmark
            };

            bool    historyAdd = service.Add(history);
            History historyGet = service.Get(userId, postId);

            //todo fix this
            Assert.True(historyAdd);
            Assert.Equal(userId, historyGet.Userid);
            Assert.Equal(postId, historyGet.Postid);
            Assert.Equal(isBookmark, historyGet.isBookmark);

            //clean up todo delete when mock is working
            service.DeleteHistory(history.Id);
        }
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            var pushData = communication.PushData.FromJsonOrNull <PushData>();

            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot");
                    var    mergeFields      = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string serverKey = GetAttributeValue("ServerKey");
                    var    sender    = new Sender(serverKey);

                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                try
                                {
                                    var           siteId  = pushData?.MobileApplicationId;
                                    List <string> devices = null;

                                    if (recipient.PersonAliasId.HasValue)
                                    {
                                        int personAliasId = recipient.PersonAliasId.Value;
                                        var service       = new PersonalDeviceService(recipientRockContext);

                                        devices = service.Queryable()
                                                  .Where(p => p.PersonAliasId.HasValue && p.PersonAliasId.Value == personAliasId && p.NotificationsEnabled && !string.IsNullOrEmpty(p.DeviceRegistrationId))
                                                  .Where(p => !siteId.HasValue || siteId.Value == p.SiteId)
                                                  .Select(p => p.DeviceRegistrationId)
                                                  .ToList();
                                    }
                                    else if (!string.IsNullOrEmpty(recipient.PersonalDevice?.DeviceRegistrationId))
                                    {
                                        devices = new List <string> {
                                            recipient.PersonalDevice?.DeviceRegistrationId
                                        };
                                    }

                                    if (devices != null && devices.Any())
                                    {
                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                        var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var title   = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var sound   = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                        var notification = new Message
                                        {
                                            RegistrationIds = devices.Distinct().ToList(),
                                            Notification    = new FCM.Net.Notification
                                            {
                                                Title = title,
                                                Body  = message,
                                                Sound = sound,
                                            },
                                            Data = GetPushNotificationData(communication.PushOpenAction, pushData, recipient)
                                        };

                                        ResponseContent response = Utility.AsyncHelpers.RunSync(() => sender.SendAsync(notification));

                                        bool failed = response.MessageResponse.Failure == devices.Count || response.MessageResponse.Success == 0;
                                        var  status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered;

                                        if (failed)
                                        {
                                            recipient.StatusNote = "Firebase failed to notify devices";
                                        }
                                        else
                                        {
                                            recipient.SendDateTime = RockDateTime.Now;
                                        }

                                        recipient.Status = status;
                                        recipient.TransportEntityTypeName = this.GetType().FullName;
                                        recipient.UniqueMessageId         = response.MessageResponse.MulticastId;

                                        if (recipient.PersonAlias != null)
                                        {
                                            try
                                            {
                                                var historyService = new HistoryService(recipientRockContext);
                                                historyService.Add(new History
                                                {
                                                    CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                    EntityTypeId           = personEntityTypeId,
                                                    CategoryId             = communicationCategoryId,
                                                    EntityId            = recipient.PersonAlias.PersonId,
                                                    Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                    ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                    ValueName           = "Push Notification",
                                                    Caption             = message.Truncate(200),
                                                    RelatedEntityTypeId = communicationEntityTypeId,
                                                    RelatedEntityId     = communication.Id
                                                });
                                            }
                                            catch (Exception ex)
                                            {
                                                ExceptionLogService.LogException(ex, null);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "No Personal Devices with Messaging Enabled";
                                    }
                                }
                                catch (Exception ex)
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "Firebase Exception: " + ex.Message;
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Rock.Model.Communication communication)
        {
            using (var rockContext = new RockContext())
            {
                // Requery the Communication object
                communication = new CommunicationService(rockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    communication.Recipients.Where(r => r.Status == Model.CommunicationRecipientStatus.Pending).Any() &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var currentPerson      = communication.CreatedByPersonAlias.Person;
                    var globalAttributes   = Rock.Web.Cache.GlobalAttributesCache.Read();
                    var globalConfigValues = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields(currentPerson);

                    // From - if none is set, use the one in the Organization's GlobalAttributes.
                    string fromAddress = communication.GetMediumDataValue("FromAddress");
                    if (string.IsNullOrWhiteSpace(fromAddress))
                    {
                        fromAddress = globalAttributes.GetValue("OrganizationEmail");
                    }

                    string fromName = communication.GetMediumDataValue("FromName");
                    if (string.IsNullOrWhiteSpace(fromName))
                    {
                        fromName = globalAttributes.GetValue("OrganizationName");
                    }

                    // Resolve any possible merge fields in the from address
                    fromAddress = fromAddress.ResolveMergeFields(globalConfigValues, currentPerson);
                    fromName    = fromName.ResolveMergeFields(globalConfigValues, currentPerson);

                    MailMessage message = new MailMessage();
                    message.From = new MailAddress(fromAddress, fromName);

                    // Reply To
                    string replyTo = communication.GetMediumDataValue("ReplyTo");
                    if (!string.IsNullOrWhiteSpace(replyTo))
                    {
                        message.ReplyToList.Add(new MailAddress(replyTo));
                    }

                    CheckSafeSender(message, globalAttributes);

                    // CC
                    string cc = communication.GetMediumDataValue("CC");
                    if (!string.IsNullOrWhiteSpace(cc))
                    {
                        foreach (string ccRecipient in cc.SplitDelimitedValues())
                        {
                            message.CC.Add(new MailAddress(ccRecipient));
                        }
                    }

                    // BCC
                    string bcc = communication.GetMediumDataValue("BCC");
                    if (!string.IsNullOrWhiteSpace(bcc))
                    {
                        foreach (string bccRecipient in bcc.SplitDelimitedValues())
                        {
                            message.Bcc.Add(new MailAddress(bccRecipient));
                        }
                    }

                    message.IsBodyHtml = true;
                    message.Priority   = MailPriority.Normal;

                    var smtpClient = GetSmtpClient();

                    // Add Attachments
                    string attachmentIds = communication.GetMediumDataValue("Attachments");
                    if (!string.IsNullOrWhiteSpace(attachmentIds))
                    {
                        var binaryFileService = new BinaryFileService(rockContext);

                        foreach (string idVal in attachmentIds.SplitDelimitedValues())
                        {
                            int binaryFileId = int.MinValue;
                            if (int.TryParse(idVal, out binaryFileId))
                            {
                                var binaryFile = binaryFileService.Get(binaryFileId);
                                if (binaryFile != null)
                                {
                                    message.Attachments.Add(new Attachment(binaryFile.ContentStream, binaryFile.FileName));
                                }
                            }
                        }
                    }

                    var historyService   = new HistoryService(rockContext);
                    var recipientService = new CommunicationRecipientService(rockContext);

                    var personEntityTypeId        = EntityTypeCache.Read("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Read("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Read(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        var recipient = Rock.Model.Communication.GetNextPending(communication.Id, rockContext);
                        if (recipient != null)
                        {
                            if (string.IsNullOrWhiteSpace(recipient.PersonAlias.Person.Email))
                            {
                                recipient.Status     = CommunicationRecipientStatus.Failed;
                                recipient.StatusNote = "No Email Address";
                            }
                            else
                            {
                                message.To.Clear();
                                message.Headers.Clear();
                                message.AlternateViews.Clear();

                                message.To.Add(new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName));

                                // Create merge field dictionary
                                var mergeObjects = recipient.CommunicationMergeValues(globalConfigValues);

                                // Subject
                                message.Subject = communication.Subject.ResolveMergeFields(mergeObjects, currentPerson);

                                // Add any additional headers that specific SMTP provider needs
                                AddAdditionalHeaders(message, recipient);

                                // Add text view first as last view is usually treated as the preferred view by email readers (gmail)
                                string plainTextBody = Rock.Communication.Medium.Email.ProcessTextBody(communication, globalAttributes, mergeObjects, currentPerson);
                                if (!string.IsNullOrWhiteSpace(plainTextBody))
                                {
                                    AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainTextBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Plain));
                                    message.AlternateViews.Add(plainTextView);
                                }

                                // Add Html view
                                string htmlBody = Rock.Communication.Medium.Email.ProcessHtmlBody(communication, globalAttributes, mergeObjects, currentPerson);
                                if (!string.IsNullOrWhiteSpace(htmlBody))
                                {
                                    AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Html));
                                    message.AlternateViews.Add(htmlView);
                                }

                                try
                                {
                                    smtpClient.Send(message);
                                    recipient.Status = CommunicationRecipientStatus.Delivered;

                                    string statusNote = StatusNote;
                                    if (!string.IsNullOrWhiteSpace(statusNote))
                                    {
                                        recipient.StatusNote = statusNote;
                                    }

                                    recipient.TransportEntityTypeName = this.GetType().FullName;

                                    historyService.Add(new History
                                    {
                                        CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                        EntityTypeId           = personEntityTypeId,
                                        CategoryId             = communicationCategoryId,
                                        EntityId            = recipient.PersonAlias.PersonId,
                                        Summary             = string.Format("Sent communication from <span class='field-value'>{0}</span>.", message.From.DisplayName),
                                        Caption             = message.Subject,
                                        RelatedEntityTypeId = communicationEntityTypeId,
                                        RelatedEntityId     = communication.Id
                                    });
                                }

                                catch (Exception ex)
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "SMTP Exception: " + ex.Message;
                                }
                            }

                            rockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext).Get(communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string fromPhone = communication.SMSFromDefinedValue?.Value;
                    if (string.IsNullOrWhiteSpace(fromPhone))
                    {
                        // just in case we got this far without a From Number, throw an exception
                        throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString());
                    }

                    if (!string.IsNullOrWhiteSpace(fromPhone))
                    {
                        int?throttlingWaitTimeMS = null;
                        if (this.IsLongCodePhoneNumber(fromPhone))
                        {
                            throttlingWaitTimeMS = this.GetAttributeValue("Long-CodeThrottling").AsIntegerOrNull();
                        }

                        string accountSid = GetAttributeValue("SID");
                        string authToken  = GetAttributeValue("Token");
                        TwilioClient.Init(accountSid, authToken);

                        var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                        var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                        var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                        string callbackUrl = publicAppRoot + "Webhooks/Twilio.ashx";

                        var        smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS);
                        List <Uri> attachmentMediaUrls            = new List <Uri>();
                        if (smsAttachmentsBinaryFileIdList.Any())
                        {
                            attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(communicationRockContext).GetByIds(smsAttachmentsBinaryFileIdList));
                        }

                        bool recipientFound = true;
                        while (recipientFound)
                        {
                            // make a new rockContext per recipient
                            var recipientRockContext = new RockContext();
                            var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                            if (recipient != null)
                            {
                                if (ValidRecipient(recipient, communication.IsBulkCommunication))
                                {
                                    try
                                    {
                                        var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers
                                                          .Where(p => p.IsMessagingEnabled)
                                                          .FirstOrDefault();

                                        if (phoneNumber != null)
                                        {
                                            // Create merge field dictionary
                                            var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                            string message = ResolveText(communication.SMSMessage, currentPerson, recipient, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                            string twilioNumber = phoneNumber.Number;
                                            if (!string.IsNullOrWhiteSpace(phoneNumber.CountryCode))
                                            {
                                                twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number;
                                            }

                                            MessageResource response = SendToTwilio(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber);

                                            recipient.Status                  = CommunicationRecipientStatus.Delivered;
                                            recipient.SendDateTime            = RockDateTime.Now;
                                            recipient.TransportEntityTypeName = this.GetType().FullName;
                                            recipient.UniqueMessageId         = response.Sid;

                                            try
                                            {
                                                var historyService = new HistoryService(recipientRockContext);
                                                historyService.Add(new History
                                                {
                                                    CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                    EntityTypeId           = personEntityTypeId,
                                                    CategoryId             = communicationCategoryId,
                                                    EntityId            = recipient.PersonAlias.PersonId,
                                                    Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                    ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                    ValueName           = "SMS message",
                                                    Caption             = message.Truncate(200),
                                                    RelatedEntityTypeId = communicationEntityTypeId,
                                                    RelatedEntityId     = communication.Id
                                                });
                                            }
                                            catch (Exception ex)
                                            {
                                                ExceptionLogService.LogException(ex, null);
                                            }
                                        }
                                        else
                                        {
                                            recipient.Status     = CommunicationRecipientStatus.Failed;
                                            recipient.StatusNote = "No Phone Number with Messaging Enabled";
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "Twilio Exception: " + ex.Message;
                                    }
                                }

                                recipientRockContext.SaveChanges();

                                if (throttlingWaitTimeMS.HasValue)
                                {
                                    System.Threading.Tasks.Task.Delay(throttlingWaitTimeMS.Value).Wait();
                                }
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
Exemple #24
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Rock.Model.Communication communication)
        {
            var rockContext = new RockContext();

            // Requery the Communication
            communication = new CommunicationService(rockContext).Get(communication.Id);

            if (communication != null &&
                communication.Status == Model.CommunicationStatus.Approved &&
                communication.HasPendingRecipients(rockContext) &&
                (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
            {
                string fromPhone   = string.Empty;
                string fromValue   = communication.GetMediumDataValue("FromValue");
                int    fromValueId = int.MinValue;
                if (int.TryParse(fromValue, out fromValueId))
                {
                    fromPhone = DefinedValueCache.Read(fromValueId, rockContext).Value;
                }

                if (!string.IsNullOrWhiteSpace(fromPhone))
                {
                    string accountSid = GetAttributeValue("SID");
                    string authToken  = GetAttributeValue("Token");
                    var    twilio     = new TwilioRestClient(accountSid, authToken);

                    var historyService   = new HistoryService(rockContext);
                    var recipientService = new CommunicationRecipientService(rockContext);

                    var personEntityTypeId        = EntityTypeCache.Read("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Read("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Read(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext).Id;

                    var globalConfigValues = GlobalAttributesCache.GetMergeFields(null);

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        var recipient = Rock.Model.Communication.GetNextPending(communication.Id, rockContext);
                        if (recipient != null)
                        {
                            try
                            {
                                var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers
                                                  .Where(p => p.IsMessagingEnabled)
                                                  .FirstOrDefault();

                                if (phoneNumber != null)
                                {
                                    // Create merge field dictionary
                                    var    mergeObjects = recipient.CommunicationMergeValues(globalConfigValues);
                                    string message      = communication.GetMediumDataValue("Message");

                                    // convert any special microsoft word characters to normal chars so they don't look funny (for example "Hey “double-quotes” from ‘single quote’")
                                    message = message.ReplaceWordChars();
                                    message = message.ResolveMergeFields(mergeObjects);

                                    string twilioNumber = phoneNumber.Number;
                                    if (!string.IsNullOrWhiteSpace(phoneNumber.CountryCode))
                                    {
                                        twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number;
                                    }

                                    var    globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read();
                                    string callbackUrl      = globalAttributes.GetValue("PublicApplicationRoot") + "Webhooks/Twilio.ashx";

                                    var response = twilio.SendMessage(fromPhone, twilioNumber, message, callbackUrl);

                                    recipient.Status = CommunicationRecipientStatus.Delivered;
                                    recipient.TransportEntityTypeName = this.GetType().FullName;
                                    recipient.UniqueMessageId         = response.Sid;

                                    try
                                    {
                                        historyService.Add(new History
                                        {
                                            CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                            EntityTypeId           = personEntityTypeId,
                                            CategoryId             = communicationCategoryId,
                                            EntityId            = recipient.PersonAlias.PersonId,
                                            Summary             = "Sent SMS message.",
                                            Caption             = message.Truncate(200),
                                            RelatedEntityTypeId = communicationEntityTypeId,
                                            RelatedEntityId     = communication.Id
                                        });
                                    }
                                    catch (Exception ex)
                                    {
                                        ExceptionLogService.LogException(ex, null);
                                    }
                                }
                                else
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "No Phone Number with Messaging Enabled";
                                }
                            }
                            catch (Exception ex)
                            {
                                recipient.Status     = CommunicationRecipientStatus.Failed;
                                recipient.StatusNote = "Twilio Exception: " + ex.Message;
                            }

                            rockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
Exemple #25
0
        /// <summary>
        /// Sends the specified communication from the Communication Wizard in Rock.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                if (recipient.PersonAliasId.HasValue)
                                {
                                    try
                                    {
                                        var             mergeObjects = recipient.CommunicationMergeValues(mergeFields);
                                        var             message      = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var             title        = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var             sound        = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var             data         = ResolveText(communication.PushData, currentPerson, communication.EnabledLavaCommands, mergeFields, publicAppRoot);
                                        var             jsonData     = Newtonsoft.Json.JsonConvert.DeserializeObject <PushData>(data);
                                        var             url          = jsonData.Url;
                                        string          appId        = GetAttributeValue("AppId");
                                        string          restApiKey   = GetAttributeValue("RestAPIKey");
                                        OneSignalClient client       = new OneSignalClient(restApiKey);

                                        var options = new NotificationCreateOptions
                                        {
                                            AppId = new Guid(appId),
                                            IncludeExternalUserIds = new List <string> {
                                                recipient.PersonAliasId.ToString()
                                            }
                                        };

                                        options.Headings.Add(LanguageCodes.English, title);
                                        options.Contents.Add(LanguageCodes.English, message);
                                        options.Url = url;
                                        NotificationCreateResult response = client.Notifications.Create(options);

                                        bool failed = !string.IsNullOrWhiteSpace(response.Error);

                                        var status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered;

                                        if (failed)
                                        {
                                            recipient.StatusNote = "OneSignal failed to notify devices";
                                        }
                                        else
                                        {
                                            recipient.SendDateTime = RockDateTime.Now;
                                        }

                                        recipient.Status = status;
                                        recipient.TransportEntityTypeName = this.GetType().FullName;
                                        recipient.UniqueMessageId         = response.Id;

                                        try
                                        {
                                            var historyService = new HistoryService(recipientRockContext);
                                            historyService.Add(new History
                                            {
                                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                EntityTypeId           = personEntityTypeId,
                                                CategoryId             = communicationCategoryId,
                                                EntityId            = recipient.PersonAlias.PersonId,
                                                Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                ValueName           = "Push Notification",
                                                Caption             = message.Truncate(200),
                                                RelatedEntityTypeId = communicationEntityTypeId,
                                                RelatedEntityId     = communication.Id
                                            });
                                        }
                                        catch (Exception ex)
                                        {
                                            ExceptionLogService.LogException(ex, null);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "OneSignal Exception: " + ex.Message;
                                    }
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
Exemple #26
0
        /// <summary>
        /// Job that will run quick SQL queries on a schedule.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            Guid?entryWorkflowType = dataMap.GetString("EraEntryWorkflow").AsGuidOrNull();
            Guid?exitWorkflowType  = dataMap.GetString("EraExitWorkflow").AsGuidOrNull();
            bool updateVisitDates  = dataMap.GetBooleanValue("SetVisitDates");

            int commandTimeout = dataMap.GetString("CommandTimeout").AsIntegerOrNull() ?? 3600;

            // configuration
            //

            // giving
            int exitGivingCount = 1;

            // attendance
            int exitAttendanceCountShort = 1;
            int exitAttendanceCountLong  = 8;

            // get era dataset from stored proc
            var resultContext = new RockContext();


            var eraAttribute      = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid());
            var eraStartAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid());
            var eraEndAttribute   = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid());

            if (eraAttribute == null || eraStartAttribute == null || eraEndAttribute == null)
            {
                throw new Exception("Family analytic attributes could not be found");
            }

            resultContext.Database.CommandTimeout = commandTimeout;

            context.UpdateLastStatusMessage("Getting Family Analytics Era Dataset...");

            var results = resultContext.Database.SqlQuery <EraResult>("spCrm_FamilyAnalyticsEraDataset").ToList();

            int personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
            int attributeEntityTypeId     = EntityTypeCache.Get("Rock.Model.Attribute").Id;
            int eraAttributeId            = eraAttribute.Id;
            int personAnalyticsCategoryId = CategoryCache.Get(SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid()).Id;

            int progressPosition = 0;
            int progressTotal    = results.Count;

            foreach (var result in results)
            {
                progressPosition++;
                // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops)
                RockContext updateContext = new RockContext();
                updateContext.SourceOfChange          = SOURCE_OF_CHANGE;
                updateContext.Database.CommandTimeout = commandTimeout;
                var attributeValueService = new AttributeValueService(updateContext);
                var historyService        = new HistoryService(updateContext);

                // if era ensure it still meets requirements
                if (result.IsEra)
                {
                    // This process will not remove eRA status from a single inactive family member if the family is considered eRA, even if the person record status is inactive.
                    // It removes eRA status from all family members if the family no longer meets the eRA requirements.
                    if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong)
                    {
                        // exit era (delete attribute value from each person in family)
                        var family = new GroupService(updateContext).Queryable("Members, Members.Person").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault();

                        if (family != null)
                        {
                            foreach (var person in family.Members.Select(m => m.Person))
                            {
                                // remove the era flag
                                var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                                if (eraAttributeValue != null)
                                {
                                    attributeValueService.Delete(eraAttributeValue);
                                }

                                // set end date
                                var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                                if (eraEndAttributeValue == null)
                                {
                                    eraEndAttributeValue             = new AttributeValue();
                                    eraEndAttributeValue.EntityId    = person.Id;
                                    eraEndAttributeValue.AttributeId = eraEndAttribute.Id;
                                    attributeValueService.Add(eraEndAttributeValue);
                                }
                                eraEndAttributeValue.Value = RockDateTime.Now.ToString();

                                // add a history record
                                if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0)
                                {
                                    History historyRecord = new History();
                                    historyService.Add(historyRecord);
                                    historyRecord.EntityTypeId           = personEntityTypeId;
                                    historyRecord.EntityId               = person.Id;
                                    historyRecord.CreatedDateTime        = RockDateTime.Now;
                                    historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId;
                                    historyRecord.Caption = "eRA";

                                    historyRecord.Verb       = "EXITED";
                                    historyRecord.ChangeType = History.HistoryChangeType.Attribute.ConvertToString();
                                    historyRecord.ValueName  = "eRA";
                                    historyRecord.NewValue   = "Exited";

                                    historyRecord.RelatedEntityTypeId = attributeEntityTypeId;
                                    historyRecord.RelatedEntityId     = eraAttributeId;
                                    historyRecord.CategoryId          = personAnalyticsCategoryId;
                                    historyRecord.SourceOfChange      = SOURCE_OF_CHANGE;
                                }

                                updateContext.SaveChanges();
                            }

                            // launch exit workflow
                            if (exitWorkflowType.HasValue)
                            {
                                LaunchWorkflow(exitWorkflowType.Value, family);
                            }
                        }
                    }
                }
                else
                {
                    // entered era
                    var family = new GroupService(updateContext).Queryable("Members").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault();

                    if (family != null)
                    {
                        // The stored procedure does not filter out inactive users because we want to exit the family from eRA if they are not active.
                        // So check the status for each person here and do not add the person if they are inactive. If the system defined value for
                        // an inactive person is not available then use "-1" as every record should pass != -1.
                        int inactiveStatusId = DefinedValueCache.GetId(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE.AsGuid()) ?? -1;

                        var familyMembers = family.Members
                                            .Where(m => !m.Person.IsDeceased)
                                            .Where(m => m.Person.RecordStatusValueId != inactiveStatusId)
                                            .Select(m => m.Person);

                        foreach (var person in familyMembers)
                        {
                            // set era attribute to true
                            var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraAttributeValue == null)
                            {
                                eraAttributeValue             = new AttributeValue();
                                eraAttributeValue.EntityId    = person.Id;
                                eraAttributeValue.AttributeId = eraAttribute.Id;
                                attributeValueService.Add(eraAttributeValue);
                            }
                            eraAttributeValue.Value = bool.TrueString;

                            // add start date
                            var eraStartAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraStartAttributeValue == null)
                            {
                                eraStartAttributeValue             = new AttributeValue();
                                eraStartAttributeValue.EntityId    = person.Id;
                                eraStartAttributeValue.AttributeId = eraStartAttribute.Id;
                                attributeValueService.Add(eraStartAttributeValue);
                            }
                            eraStartAttributeValue.Value = RockDateTime.Now.ToString();

                            // delete end date if it exists
                            var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraEndAttributeValue != null)
                            {
                                attributeValueService.Delete(eraEndAttributeValue);
                            }

                            // add a history record
                            if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0)
                            {
                                History historyRecord = new History();
                                historyService.Add(historyRecord);
                                historyRecord.EntityTypeId           = personEntityTypeId;
                                historyRecord.EntityId               = person.Id;
                                historyRecord.CreatedDateTime        = RockDateTime.Now;
                                historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId;
                                historyRecord.Caption             = "eRA";
                                historyRecord.Verb                = "ENTERED";
                                historyRecord.ChangeType          = History.HistoryChangeType.Attribute.ConvertToString();
                                historyRecord.RelatedEntityTypeId = attributeEntityTypeId;
                                historyRecord.RelatedEntityId     = eraAttributeId;
                                historyRecord.CategoryId          = personAnalyticsCategoryId;
                                historyRecord.SourceOfChange      = SOURCE_OF_CHANGE;
                            }

                            updateContext.SaveChanges();
                        }

                        // launch entry workflow
                        if (entryWorkflowType.HasValue)
                        {
                            LaunchWorkflow(entryWorkflowType.Value, family);
                        }
                    }
                }

                // update stats
                context.UpdateLastStatusMessage($"Updating eRA {progressPosition} of {progressTotal}");
            }

            // load giving attributes
            context.UpdateLastStatusMessage("Updating Giving...");
            resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsGiving");

            // load attendance attributes
            context.UpdateLastStatusMessage("Updating Attendance...");
            resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsAttendance");

            // process visit dates
            if (updateVisitDates)
            {
                context.UpdateLastStatusMessage("Updating Visit Dates...");
                resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsUpdateVisitDates");
            }

            context.UpdateLastStatusMessage("");
        }
Exemple #27
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Rock.Model.Communication communication)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication object in case we need to load any properties from the database
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients.Where(a => a.CommunicationId == communication.Id).Where(r => r.Status == Model.CommunicationRecipientStatus.Pending).Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var currentPerson    = communication.CreatedByPersonAlias.Person;
                    var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read();
                    var mergeFields      = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    // From - if none is set, use the one in the Organization's GlobalAttributes.
                    string fromAddress = communication.GetMediumDataValue("FromAddress");
                    if (string.IsNullOrWhiteSpace(fromAddress))
                    {
                        fromAddress = globalAttributes.GetValue("OrganizationEmail");
                    }

                    string fromName = communication.GetMediumDataValue("FromName");
                    if (string.IsNullOrWhiteSpace(fromName))
                    {
                        fromName = globalAttributes.GetValue("OrganizationName");
                    }

                    // Resolve any possible merge fields in the from address
                    fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);
                    fromName    = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);

                    MailMessage message = new MailMessage();
                    message.From = new MailAddress(fromAddress, fromName);

                    // Reply To
                    try
                    {
                        string replyTo = communication.GetMediumDataValue("ReplyTo");
                        if (!string.IsNullOrWhiteSpace(replyTo))
                        {
                            message.ReplyToList.Add(new MailAddress(replyTo));
                        }
                    }
                    catch { }

                    CheckSafeSender(message, globalAttributes);

                    // CC
                    string cc = communication.GetMediumDataValue("CC");
                    if (!string.IsNullOrWhiteSpace(cc))
                    {
                        foreach (string ccRecipient in cc.SplitDelimitedValues())
                        {
                            message.CC.Add(new MailAddress(ccRecipient));
                        }
                    }

                    // BCC
                    string bcc = communication.GetMediumDataValue("BCC");
                    if (!string.IsNullOrWhiteSpace(bcc))
                    {
                        foreach (string bccRecipient in bcc.SplitDelimitedValues())
                        {
                            message.Bcc.Add(new MailAddress(bccRecipient));
                        }
                    }

                    message.IsBodyHtml = true;
                    message.Priority   = MailPriority.Normal;

                    using (var smtpClient = GetSmtpClient())
                    {
                        // Add Attachments
                        var    attachments   = new List <BinaryFile>();
                        string attachmentIds = communication.GetMediumDataValue("Attachments");
                        if (!string.IsNullOrWhiteSpace(attachmentIds))
                        {
                            var binaryFileService = new BinaryFileService(communicationRockContext);

                            foreach (int binaryFileId in attachmentIds.SplitDelimitedValues().AsIntegerList())
                            {
                                var binaryFile = binaryFileService.Get(binaryFileId);
                                if (binaryFile != null)
                                {
                                    attachments.Add(binaryFile);
                                }
                            }
                        }

                        var personEntityTypeId        = EntityTypeCache.Read("Rock.Model.Person").Id;
                        var communicationEntityTypeId = EntityTypeCache.Read("Rock.Model.Communication").Id;
                        var communicationCategoryId   = CategoryCache.Read(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                        bool recipientFound = true;
                        while (recipientFound)
                        {
                            // make a new rockContext per recipient so that DbChangeTracker doesn't get gummed up on large communications
                            var recipientRockContext = new RockContext();
                            var recipient            = Rock.Model.Communication.GetNextPending(communication.Id, recipientRockContext);
                            if (recipient != null)
                            {
                                if (string.IsNullOrWhiteSpace(recipient.PersonAlias.Person.Email))
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "No Email Address";
                                }
                                else
                                {
                                    try
                                    {
                                        message.To.Clear();
                                        message.Headers.Clear();
                                        message.AlternateViews.Clear();

                                        message.To.Add(new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName));

                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                        // Subject
                                        message.Subject = communication.Subject.ResolveMergeFields(mergeObjects, currentPerson, communication.EnabledLavaCommands);

                                        // convert any special microsoft word characters to normal chars so they don't look funny (for example "Hey “double-quotes” from ‘single quote’")
                                        message.Subject = message.Subject.ReplaceWordChars();

                                        // Add text view first as last view is usually treated as the preferred view by email readers (gmail)
                                        string plainTextBody = Rock.Communication.Medium.Email.ProcessTextBody(communication, globalAttributes, mergeObjects, currentPerson);

                                        // convert any special microsoft word characters to normal chars so they don't look funny
                                        plainTextBody = plainTextBody.ReplaceWordChars();

                                        if (!string.IsNullOrWhiteSpace(plainTextBody))
                                        {
                                            AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainTextBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Plain));
                                            message.AlternateViews.Add(plainTextView);
                                        }

                                        // Add Html view
                                        string htmlBody = Rock.Communication.Medium.Email.ProcessHtmlBody(communication, globalAttributes, mergeObjects, currentPerson);

                                        // convert any special microsoft word characters to normal chars so they don't look funny
                                        htmlBody = htmlBody.ReplaceWordChars();

                                        if (!string.IsNullOrWhiteSpace(htmlBody))
                                        {
                                            AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Html));
                                            message.AlternateViews.Add(htmlView);
                                        }

                                        // Add any additional headers that specific SMTP provider needs
                                        var metaData = new Dictionary <string, string>();
                                        metaData.Add("communication_recipient_guid", recipient.Guid.ToString());
                                        AddAdditionalHeaders(message, metaData);

                                        // Recreate the attachments
                                        message.Attachments.Clear();
                                        if (attachments.Any())
                                        {
                                            foreach (var attachment in attachments)
                                            {
                                                message.Attachments.Add(new Attachment(attachment.ContentStream, attachment.FileName));
                                            }
                                        }

                                        smtpClient.Send(message);
                                        recipient.Status = CommunicationRecipientStatus.Delivered;

                                        string statusNote = StatusNote;
                                        if (!string.IsNullOrWhiteSpace(statusNote))
                                        {
                                            recipient.StatusNote = statusNote;
                                        }

                                        recipient.TransportEntityTypeName = this.GetType().FullName;

                                        var historyService = new HistoryService(recipientRockContext);
                                        historyService.Add(new History
                                        {
                                            CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                            EntityTypeId           = personEntityTypeId,
                                            CategoryId             = communicationCategoryId,
                                            EntityId            = recipient.PersonAlias.PersonId,
                                            Summary             = string.Format("Sent communication from <span class='field-value'>{0}</span>.", message.From.DisplayName),
                                            Caption             = message.Subject,
                                            RelatedEntityTypeId = communicationEntityTypeId,
                                            RelatedEntityId     = communication.Id
                                        });
                                    }

                                    catch (Exception ex)
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "Exception: " + ex.Message;
                                    }
                                }

                                recipientRockContext.SaveChanges();
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
Exemple #28
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>Medi
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        public override void Send(Rock.Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable().Include(a => a.CreatedByPersonAlias.Person).Include(a => a.CommunicationTemplate)
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson      = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes   = Rock.Web.Cache.GlobalAttributesCache.Read();
                    string publicAppRoot      = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields        = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);
                    var    cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false;

                    // From - if none is set, use the one in the Organization's GlobalAttributes.
                    string fromAddress = communication.FromEmail;
                    if (string.IsNullOrWhiteSpace(fromAddress))
                    {
                        fromAddress = globalAttributes.GetValue("OrganizationEmail");
                    }

                    string fromName = communication.FromName;
                    if (string.IsNullOrWhiteSpace(fromName))
                    {
                        fromName = globalAttributes.GetValue("OrganizationName");
                    }

                    // Resolve any possible merge fields in the from address
                    fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);
                    fromName    = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);

                    MailMessage message = new MailMessage();

                    // Reply To
                    try
                    {
                        string replyTo = communication.ReplyToEmail;
                        if (!string.IsNullOrWhiteSpace(replyTo))
                        {
                            // Resolve any possible merge fields in the replyTo address
                            message.ReplyToList.Add(new MailAddress(replyTo.ResolveMergeFields(mergeFields, currentPerson)));
                        }
                    }
                    catch { }

                    message.IsBodyHtml = true;
                    message.Priority   = MailPriority.Normal;

                    using (var smtpClient = GetSmtpClient())
                    {
                        var personEntityTypeId        = EntityTypeCache.Read("Rock.Model.Person").Id;
                        var communicationEntityTypeId = EntityTypeCache.Read("Rock.Model.Communication").Id;
                        var communicationCategoryId   = CategoryCache.Read(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                        bool recipientFound = true;
                        while (recipientFound)
                        {
                            // make a new rockContext per recipient
                            var recipientRockContext = new RockContext();
                            var recipient            = Rock.Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                            if (recipient != null)
                            {
                                if (ValidRecipient(recipient, communication.IsBulkCommunication))
                                {
                                    try
                                    {
                                        message.To.Clear();
                                        message.CC.Clear();
                                        message.Bcc.Clear();
                                        message.Headers.Clear();
                                        message.AlternateViews.Clear();

                                        // Set From/To and check safe sender
                                        message.From = new MailAddress(fromAddress, fromName);
                                        message.To.Add(new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName));
                                        CheckSafeSender(message, globalAttributes);

                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                        // CC
                                        string cc = communication.CCEmails;
                                        if (!string.IsNullOrWhiteSpace(cc))
                                        {
                                            // Resolve any possible merge fields in the cc address
                                            cc = cc.ResolveMergeFields(mergeObjects, currentPerson);
                                            foreach (string ccRecipient in cc.SplitDelimitedValues())
                                            {
                                                message.CC.Add(new MailAddress(ccRecipient));
                                            }
                                        }

                                        // BCC
                                        string bcc = communication.BCCEmails;
                                        if (!string.IsNullOrWhiteSpace(bcc))
                                        {
                                            bcc = bcc.ResolveMergeFields(mergeObjects, currentPerson);
                                            foreach (string bccRecipient in bcc.SplitDelimitedValues())
                                            {
                                                // Resolve any possible merge fields in the bcc address
                                                message.Bcc.Add(new MailAddress(bccRecipient));
                                            }
                                        }

                                        // Subject
                                        message.Subject = ResolveText(communication.Subject, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                        // Plain text
                                        if (mediumAttributes.ContainsKey("DefaultPlainText"))
                                        {
                                            string plainText = ResolveText(mediumAttributes["DefaultPlainText"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                            if (!string.IsNullOrWhiteSpace(plainText))
                                            {
                                                AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainText, new System.Net.Mime.ContentType(MediaTypeNames.Text.Plain));
                                                message.AlternateViews.Add(plainTextView);
                                            }
                                        }

                                        // Add Html view
                                        // Get the unsubscribe content and add a merge field for it
                                        string htmlBody = communication.Message;
                                        if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML"))
                                        {
                                            string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                            mergeObjects.AddOrReplace("UnsubscribeOption", unsubscribeHtml);
                                            htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                            // Resolve special syntax needed if option was included in global attribute
                                            if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]"))
                                            {
                                                htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml);
                                            }

                                            // Add the unsubscribe option at end if it wasn't included in content
                                            if (!htmlBody.Contains(unsubscribeHtml))
                                            {
                                                htmlBody += unsubscribeHtml;
                                            }
                                        }
                                        else
                                        {
                                            htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                            htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty);
                                        }

                                        if (!string.IsNullOrWhiteSpace(htmlBody))
                                        {
                                            if (cssInliningEnabled)
                                            {
                                                // move styles inline to help it be compatible with more email clients
                                                htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes();
                                            }

                                            // add the main Html content to the email
                                            AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Html));
                                            message.AlternateViews.Add(htmlView);
                                        }

                                        // Add any additional headers that specific SMTP provider needs
                                        var metaData = new Dictionary <string, string>();
                                        metaData.Add("communication_recipient_guid", recipient.Guid.ToString());
                                        AddAdditionalHeaders(message, metaData);

                                        // Recreate the attachments
                                        message.Attachments.Clear();
                                        foreach (var binaryFile in communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile))
                                        {
                                            message.Attachments.Add(new Attachment(binaryFile.ContentStream, binaryFile.FileName));
                                        }

                                        smtpClient.Send(message);
                                        recipient.Status = CommunicationRecipientStatus.Delivered;

                                        string statusNote = StatusNote;
                                        if (!string.IsNullOrWhiteSpace(statusNote))
                                        {
                                            recipient.StatusNote = statusNote;
                                        }

                                        recipient.TransportEntityTypeName = this.GetType().FullName;

                                        try
                                        {
                                            var historyService = new HistoryService(recipientRockContext);
                                            historyService.Add(new History
                                            {
                                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                EntityTypeId           = personEntityTypeId,
                                                CategoryId             = communicationCategoryId,
                                                EntityId            = recipient.PersonAlias.PersonId,
                                                Summary             = string.Format("Sent communication from <span class='field-value'>{0}</span>.", message.From.DisplayName),
                                                Caption             = message.Subject,
                                                RelatedEntityTypeId = communicationEntityTypeId,
                                                RelatedEntityId     = communication.Id
                                            });
                                        }
                                        catch (Exception ex)
                                        {
                                            ExceptionLogService.LogException(ex, null);
                                        }
                                    }

                                    catch (Exception ex)
                                    {
                                        ExceptionLogService.LogException(ex);
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => ");
                                    }
                                }

                                recipientRockContext.SaveChanges();
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);


                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    var client = new RestClient(GetAttributeValue("APIEndpoint"));

                    JsonSerializerSettings serializerSettings = new JsonSerializerSettings
                    {
                        ConstructorHandling  = ConstructorHandling.AllowNonPublicDefaultConstructor,
                        DateTimeZoneHandling = DateTimeZoneHandling.Local
                    };

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                try
                                {
                                    int personAlias = recipient.PersonAliasId;

                                    // Create merge field dictionary
                                    var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                    var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                    var title   = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                    var sound   = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);


                                    var notification = new subsplash.Model.Notification();
                                    notification.AppKey                = GetAttributeValue("AppKey");
                                    notification.Body                  = message;
                                    notification.Title                 = title;
                                    notification.PublishedAt           = RockDateTime.Now;
                                    notification.Embedded              = new NotificationEmbedded();
                                    notification.Embedded.ExternalUser = new ExternalUser();
                                    notification.Embedded.ExternalUser.AuthProviderId = Encryption.DecryptString(GetAttributeValue("AuthProviderId")).AsGuidOrNull();
                                    notification.Embedded.ExternalUser.UserIds        = recipient.PersonAlias.Person.Aliases.Select(a => a.AliasPersonId.ToString()).ToList();

                                    var sendPush = new RestRequest("notifications", Method.POST);
                                    sendPush.AddHeader("Content-Type", "application/json");
                                    sendPush.AddHeader("Authorization", "Bearer " + Encryption.DecryptString(GetAttributeValue("JWTToken")));
                                    sendPush.RequestFormat = DataFormat.Json;
                                    sendPush.AddParameter("application/json", JsonConvert.SerializeObject(notification, serializerSettings), ParameterType.RequestBody);


                                    var response = client.Execute(sendPush);

                                    ErrorResponse error = ( ErrorResponse )JsonConvert.DeserializeObject(response.Content, typeof(ErrorResponse), serializerSettings);

                                    if (error != null && error.Errors != null)
                                    {
                                        recipient.StatusNote = string.Join("\n", error.Errors.Select(e => e.Code + ": " + (e.Message ?? e.Detail)).ToList());
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                    }
                                    else
                                    {
                                        recipient.SendDateTime = RockDateTime.Now;
                                        recipient.Status       = CommunicationRecipientStatus.Delivered;
                                        subsplash.Model.Notification notificationResponse = (subsplash.Model.Notification)JsonConvert.DeserializeObject(response.Content, typeof(subsplash.Model.Notification), serializerSettings);

                                        recipient.UniqueMessageId = notificationResponse.Id.ToString();
                                    }

                                    recipient.TransportEntityTypeName = this.GetType().FullName;

                                    try
                                    {
                                        var historyService = new HistoryService(recipientRockContext);
                                        historyService.Add(new History
                                        {
                                            CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                            EntityTypeId           = personEntityTypeId,
                                            CategoryId             = communicationCategoryId,
                                            EntityId            = recipient.PersonAlias.PersonId,
                                            Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                            ChangeType          = History.HistoryChangeType.Record.ToString(),
                                            ValueName           = "Push Notification",
                                            Caption             = message.Truncate(200),
                                            RelatedEntityTypeId = communicationEntityTypeId,
                                            RelatedEntityId     = communication.Id
                                        });
                                    }
                                    catch (Exception ex)
                                    {
                                        ExceptionLogService.LogException(ex, null);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "Subsplash Push Notification Exception: " + ex.Message;
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
Exemple #30
0
        /// <summary>
        /// Job that will run quick SQL queries on a schedule.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            Guid?entryWorkflowType = dataMap.GetString("EraEntryWorkflow").AsGuidOrNull();
            Guid?exitWorkflowType  = dataMap.GetString("EraExitWorkflow").AsGuidOrNull();
            bool updateVisitDates  = dataMap.GetBooleanValue("SetVisitDates");
            var  groupTypeList     = dataMap.GetString("GroupTypes");

            // configuration
            //

            // giving
            int exitGivingCount = 1;

            // attendance
            int exitAttendanceCountShort = 1;
            int exitAttendanceCountLong  = 8;

            // get era dataset from stored proc
            var resultContext = new RockContext();


            var eraAttribute      = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid());
            var eraStartAttribute = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid());
            var eraEndAttribute   = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid());

            resultContext.Database.CommandTimeout = 3600;

            var results = resultContext.Database.SqlQuery <EraResult>("spCrm_FamilyAnalyticsEraDataset").ToList();

            int personEntityTypeId        = EntityTypeCache.Read("Rock.Model.Person").Id;
            int attributeEntityTypeId     = EntityTypeCache.Read("Rock.Model.Attribute").Id;
            int eraAttributeId            = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid()).Id;
            int personAnalyticsCategoryId = CategoryCache.Read(SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid()).Id;

            foreach (var result in results)
            {
                // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops)
                RockContext updateContext         = new RockContext();
                var         attributeValueService = new AttributeValueService(updateContext);
                var         historyService        = new HistoryService(updateContext);

                // if era ensure it still meets requirements
                if (result.IsEra)
                {
                    if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong)
                    {
                        // exit era (delete attribute value from each person in family)
                        var family = new GroupService(updateContext).Queryable("Members, Members.Person").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault();

                        if (family != null)
                        {
                            foreach (var person in family.Members.Select(m => m.Person))
                            {
                                // remove the era flag
                                var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                                if (eraAttributeValue != null)
                                {
                                    attributeValueService.Delete(eraAttributeValue);
                                }

                                // set end date
                                var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                                if (eraEndAttributeValue == null)
                                {
                                    eraEndAttributeValue             = new AttributeValue();
                                    eraEndAttributeValue.EntityId    = person.Id;
                                    eraEndAttributeValue.AttributeId = eraEndAttribute.Id;
                                    attributeValueService.Add(eraEndAttributeValue);
                                }
                                eraEndAttributeValue.Value = RockDateTime.Now.ToString();

                                // add a history record
                                if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0)
                                {
                                    History historyRecord = new History();
                                    historyService.Add(historyRecord);
                                    historyRecord.EntityTypeId           = personEntityTypeId;
                                    historyRecord.EntityId               = person.Id;
                                    historyRecord.CreatedDateTime        = RockDateTime.Now;
                                    historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId;
                                    historyRecord.Caption             = "eRA";
                                    historyRecord.Summary             = "Exited eRA Status";
                                    historyRecord.Verb                = "EXITED";
                                    historyRecord.RelatedEntityTypeId = attributeEntityTypeId;
                                    historyRecord.RelatedEntityId     = eraAttributeId;
                                    historyRecord.CategoryId          = personAnalyticsCategoryId;
                                }

                                updateContext.SaveChanges();
                            }

                            // launch exit workflow
                            if (exitWorkflowType.HasValue)
                            {
                                LaunchWorkflow(exitWorkflowType.Value, family);
                            }
                        }
                    }
                }
                else
                {
                    // entered era
                    var family = new GroupService(updateContext).Queryable("Members").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault();

                    if (family != null)
                    {
                        foreach (var person in family.Members.Where(m => !m.Person.IsDeceased).Select(m => m.Person))
                        {
                            // set era attribute to true
                            var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraAttributeValue == null)
                            {
                                eraAttributeValue             = new AttributeValue();
                                eraAttributeValue.EntityId    = person.Id;
                                eraAttributeValue.AttributeId = eraAttribute.Id;
                                attributeValueService.Add(eraAttributeValue);
                            }
                            eraAttributeValue.Value = bool.TrueString;

                            // add start date
                            var eraStartAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraStartAttributeValue == null)
                            {
                                eraStartAttributeValue             = new AttributeValue();
                                eraStartAttributeValue.EntityId    = person.Id;
                                eraStartAttributeValue.AttributeId = eraStartAttribute.Id;
                                attributeValueService.Add(eraStartAttributeValue);
                            }
                            eraStartAttributeValue.Value = RockDateTime.Now.ToString();

                            // delete end date if it exists
                            var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraEndAttributeValue != null)
                            {
                                attributeValueService.Delete(eraEndAttributeValue);
                            }

                            // add a history record
                            if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0)
                            {
                                History historyRecord = new History();
                                historyService.Add(historyRecord);
                                historyRecord.EntityTypeId           = personEntityTypeId;
                                historyRecord.EntityId               = person.Id;
                                historyRecord.CreatedDateTime        = RockDateTime.Now;
                                historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId;
                                historyRecord.Caption             = "eRA";
                                historyRecord.Summary             = "Entered eRA Status";
                                historyRecord.Verb                = "ENTERED";
                                historyRecord.RelatedEntityTypeId = attributeEntityTypeId;
                                historyRecord.RelatedEntityId     = eraAttributeId;
                                historyRecord.CategoryId          = personAnalyticsCategoryId;
                            }

                            updateContext.SaveChanges();
                        }

                        // launch entry workflow
                        if (entryWorkflowType.HasValue)
                        {
                            LaunchWorkflow(entryWorkflowType.Value, family);
                        }
                    }
                }

                // update stats
            }

            // load giving attributes
            resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsGiving");

            // load attendance attributes
            resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsAttendance");

            // process history for group types
            if (!string.IsNullOrWhiteSpace(groupTypeList))
            {
                string[] groupTypeGuids = groupTypeList.Split(',');

                var inactiveRecordValue = DefinedValueCache.Read(SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE);

                var groupTypeEntityTypeId = EntityTypeCache.Read("Rock.Model.GroupType").Id;

                foreach (var groupTypeGuid in groupTypeGuids)
                {
                    var groupType = GroupTypeCache.Read(groupTypeGuid.AsGuid());

                    if (groupType != null)
                    {
                        // if the person is in a group of that type and the last history record for that group type isn't START write a start
                        RockContext rockContext = new RockContext();

                        // get history for this group type
                        var historyRecords = new HistoryService(rockContext).Queryable()
                                             .Where(h =>
                                                    h.EntityTypeId == personEntityTypeId &&
                                                    h.RelatedEntityTypeId == groupTypeEntityTypeId &&
                                                    h.RelatedEntityId == groupType.Id
                                                    )
                                             .GroupBy(h => h.EntityId)
                                             .Select(g => g.OrderByDescending(h => h.CreatedDateTime).Select(h => new { h.EntityId, h.Verb }).FirstOrDefault())
                                             .ToList();

                        // get group member information
                        var groupMemberInfo = new GroupMemberService(rockContext).Queryable()
                                              .Where(m =>
                                                     m.Group.GroupTypeId == groupType.Id &&
                                                     m.GroupMemberStatus == GroupMemberStatus.Active &&
                                                     m.Group.IsActive
                                                     //&& m.Person.RecordStatusValueId != inactiveRecordValue.Id
                                                     )
                                              .GroupBy(m => m.PersonId)
                                              .Select(g => g.OrderBy(m => m.CreatedDateTime).Select(m => new { m.PersonId, m.CreatedDateTime, PersonAliasId = m.Person.Aliases.Select(p => p.Id).FirstOrDefault() }).FirstOrDefault())
                                              .ToList();

                        var needsStartDate = groupMemberInfo.Where(m => !historyRecords.Any(h => h.EntityId == m.PersonId && h.Verb == "STARTED"));

                        foreach (var startItem in needsStartDate)
                        {
                            using (RockContext updateContext = new RockContext())
                            {
                                var     historyService = new HistoryService(updateContext);
                                History history        = new History();
                                historyService.Add(history);
                                history.EntityTypeId        = personEntityTypeId;
                                history.EntityId            = startItem.PersonId;
                                history.RelatedEntityTypeId = groupTypeEntityTypeId;
                                history.RelatedEntityId     = groupType.Id;
                                history.Caption             = groupType.Name;
                                history.Summary             = "Started Membership in Group Of Type";
                                history.Verb                   = "STARTED";
                                history.CreatedDateTime        = startItem.CreatedDateTime;
                                history.CreatedByPersonAliasId = startItem.PersonAliasId;
                                history.CategoryId             = personAnalyticsCategoryId;

                                updateContext.SaveChanges();
                            }
                        }

                        var needsStoppedDate = historyRecords.Where(h => h.Verb == "STARTED" && !groupMemberInfo.Any(m => m.PersonId == h.EntityId));

                        foreach (var stopItem in needsStoppedDate)
                        {
                            using (RockContext updateContext = new RockContext())
                            {
                                var person = new PersonService(updateContext).Get(stopItem.EntityId);

                                if (person != null)
                                {
                                    var     historyService = new HistoryService(updateContext);
                                    History history        = new History();
                                    historyService.Add(history);
                                    history.EntityTypeId        = personEntityTypeId;
                                    history.EntityId            = person.Id;
                                    history.RelatedEntityTypeId = groupTypeEntityTypeId;
                                    history.RelatedEntityId     = groupType.Id;
                                    history.Caption             = groupType.Name;
                                    history.Summary             = "Stopped Membership in Group Of Type";
                                    history.Verb                   = "STOPPED";
                                    history.CreatedDateTime        = RockDateTime.Now;
                                    history.CreatedByPersonAliasId = person.PrimaryAliasId;
                                    history.CategoryId             = personAnalyticsCategoryId;

                                    updateContext.SaveChanges();
                                }
                            }
                        }
                    }
                }
            }

            // process visit dates
            if (updateVisitDates)
            {
                resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsUpdateVisitDates");
            }
        }