The data access/service class for the Rock.Model.History entity. This inherits from the Service class
        /// <summary>
        /// Adds the changes.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="modelType">Type of the model.</param>
        /// <param name="categoryGuid">The category unique identifier.</param>
        /// <param name="entityId">The entity identifier.</param>
        /// <param name="changes">The changes.</param>
        /// <param name="caption">The caption.</param>
        /// <param name="relatedModelType">Type of the related model.</param>
        /// <param name="relatedEntityId">The related entity identifier.</param>
        /// <param name="modifiedByPersonAliasId">The modified by person alias identifier.</param>
        public static void AddChanges( RockContext rockContext, Type modelType, Guid categoryGuid, int entityId, List<string> changes, string caption, Type relatedModelType, int? relatedEntityId, int? modifiedByPersonAliasId = null )
        {
            var entityType = EntityTypeCache.Read( modelType );
            var category = CategoryCache.Read( categoryGuid );
            var creationDate = RockDateTime.Now;

            int? relatedEntityTypeId = null;
            if ( relatedModelType != null )
            {
                var relatedEntityType = EntityTypeCache.Read( relatedModelType );
                if ( relatedModelType != null )
                {
                    relatedEntityTypeId = relatedEntityType.Id;
                }
            }

            if ( entityType != null && category != null )
            {
                var historyService = new HistoryService( rockContext );

                foreach ( string message in changes.Where( m => m != null && m != "" ) )
                {
                    var history = new History();
                    history.EntityTypeId = entityType.Id;
                    history.CategoryId = category.Id;
                    history.EntityId = entityId;
                    history.Caption = caption.Truncate(200);
                    history.Summary = message;
                    history.RelatedEntityTypeId = relatedEntityTypeId;
                    history.RelatedEntityId = relatedEntityId;

                    if ( modifiedByPersonAliasId.HasValue )
                    {
                        history.CreatedByPersonAliasId = modifiedByPersonAliasId;
                    }

                    // Manually set creation date on these history items so that they will be grouped together
                    history.CreatedDateTime = creationDate;

                    historyService.Add( history );
                }
            }
        }
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid()
        {
            if (Person != null)
            {
                var familyIds = families.Select( f => f.Key ).ToList();
                var qry = new HistoryService( new RockContext() ).Queryable( "CreatedByPersonAlias.Person" )
                    .Where( h =>
                        ( h.EntityTypeId == personEntityTypeId && h.EntityId == Person.Id ) ||
                        ( h.EntityTypeId == groupEntityTypeId && familyIds.Contains( h.EntityId ) ) );

                int categoryId = int.MinValue;
                if (int.TryParse(gfSettings.GetUserPreference("Category"), out categoryId))
                {
                    qry = qry.Where( h => h.CategoryId == categoryId);
                }

                string summary = gfSettings.GetUserPreference("Summary Contains");
                if (!string.IsNullOrWhiteSpace(summary))
                {
                    qry = qry.Where( h => h.Summary.Contains( summary ) );
                }

                int personId = int.MinValue;
                if ( int.TryParse( gfSettings.GetUserPreference( "Who" ), out personId ) )
                {
                    qry = qry.Where( h => h.CreatedByPersonAlias.PersonId == personId );
                }

                var drp = new DateRangePicker();
                drp.DelimitedValues = gfSettings.GetUserPreference( "Date Range" );
                if ( drp.LowerValue.HasValue )
                {
                    qry = qry.Where( h => h.CreatedDateTime >= drp.LowerValue.Value );
                }
                if ( drp.UpperValue.HasValue )
                {
                    DateTime upperDate = drp.UpperValue.Value.Date.AddDays( 1 );
                    qry = qry.Where( h => h.CreatedDateTime < upperDate );
                }

                SortProperty sortProperty = gHistory.SortProperty;
                if ( sortProperty != null )
                {
                    qry = qry.Sort( sortProperty );
                }
                else
                {
                    qry = qry.OrderByDescending( t => t.CreatedDateTime );
                }

                // Combine history records that were saved at the same time
                var histories = new List<History>();
                foreach(var history in qry)
                {
                    var existingHistory = histories
                        .Where( h =>
                            h.CreatedByPersonAliasId == history.CreatedByPersonAliasId &&
                            h.CreatedDateTime == history.CreatedDateTime &&
                            h.EntityTypeId == history.EntityTypeId &&
                            h.EntityId == history.EntityId &&
                            h.CategoryId == history.CategoryId &&
                            h.RelatedEntityTypeId == history.RelatedEntityTypeId &&
                            h.RelatedEntityId == history.RelatedEntityId ).FirstOrDefault();
                    if (existingHistory != null)
                    {
                        existingHistory.Summary += "<br/>" + history.Summary;
                    }
                    else
                    {
                        histories.Add(history);
                    }
                }

                gHistory.DataSource = histories.Select( h => new
                {
                    Id = h.Id,
                    CategoryId = h.CategoryId,
                    Category = h.Category != null ? h.Category.Name : "",
                    EntityTypeId = h.EntityTypeId,
                    EntityId = h.EntityId,
                    Caption = h.Caption ?? string.Empty,
                    Summary = h.Summary,
                    RelatedEntityTypeId = h.RelatedEntityTypeId ?? 0,
                    RelatedEntityId = h.RelatedEntityId ?? 0,
                    CreatedByPersonId = h.CreatedByPersonAlias != null ? h.CreatedByPersonAlias.PersonId : 0,
                    PersonName = h.CreatedByPersonAlias != null && h.CreatedByPersonAlias.Person != null ? h.CreatedByPersonAlias.Person.NickName + " " + h.CreatedByPersonAlias.Person.LastName : "",
                    CreatedDateTime = h.CreatedDateTime
                } ).ToList();
                gHistory.DataBind();
            }
        }
        /// <summary>
        /// Deletes any saved history items.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="modelType">Type of the model.</param>
        /// <param name="entityId">The entity identifier.</param>
        public static void DeleteChanges( RockContext rockContext, Type modelType, int entityId )
        {
            var entityType = EntityTypeCache.Read( modelType );
            if ( entityType != null  )
            {
                var historyService = new HistoryService( rockContext );
                foreach( var history in historyService.Queryable()
                    .Where( h =>
                        h.EntityTypeId == entityType.Id &&
                        h.EntityId == entityId ) )
                {
                    historyService.Delete( history );
                }

                rockContext.SaveChanges();
            }
        }
        /// <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
                communication = new CommunicationService( rockContext ).Get( communication.Id );

                if ( communication != null &&
                    communication.Status == CommunicationStatus.Approved &&
                    communication.Recipients.Any(r => r.Status == CommunicationRecipientStatus.Pending) &&
                    ( !communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo( RockDateTime.Now ) <= 0 ) )
                {
                    // Remove all non alpha numeric from fromValue
                    string fromValue = communication.GetMediumDataValue( "NoReply_FromValue" );
                    //Ensure that the fromValue is correct
                    fromValue = new string( fromValue.ToCharArray().Where( c => char.IsLetterOrDigit( c ) || char.IsWhiteSpace( c ) ).Take( 11 ).ToArray() ) ;
                    string senderGuid = communication.GetMediumDataValue( "SenderGuid" );
                    if ( !string.IsNullOrWhiteSpace( fromValue ) && !string.IsNullOrWhiteSpace( senderGuid ) )
                    {
                        string accountSid = GetAttributeValue( "SID" );
                        string authToken = GetAttributeValue( "Token" );

                        if (string.IsNullOrWhiteSpace(accountSid) || string.IsNullOrWhiteSpace(authToken))
                        {
                            throw new Exception("Either SID or Token not provided");
                        }
                        var twilio = new TwilioRestClient( accountSid, authToken );
                        var historyService = new HistoryService( rockContext );

                        int personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id;
                        int communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id;
                        int communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id;
                        var sender = new PersonService( rockContext ).Get( senderGuid.AsGuid() );
                        var mergeFields = GlobalAttributesCache.GetMergeFields( null );
                        if ( sender != null )
                        {
                            mergeFields.Add( "Sender", sender );
                        }

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

                                    if ( phoneNumber != null )
                                    {
                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues( mergeFields );
                                        string message = communication.GetMediumDataValue( "NoReply_Message" );
                                        string footer = GetAttributeValue( "footer" );
                                        if ( communication.GetMediumDataValue( "NoReply_AppendUserInfo" ).AsBoolean() && !string.IsNullOrEmpty( footer ) )
                                        {
                                            message += "\n " + footer;
                                        }
                                        else
                                        {
                                            message += "\n This message was sent on behalf of {{ GlobalAttribute.OrganizationName }} from a no reply number.";
                                        }

                                        message = message.ReplaceWordChars();
                                        message = message.ResolveMergeFields( mergeObjects );

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

                                        var globalAttributes = GlobalAttributesCache.Read();
                                        if (globalAttributes == null)
                                        {
                                            throw  new Exception("Error getting Global Attributes");
                                        }
                                        string callbackUrl = globalAttributes.GetValue( "PublicApplicationRoot" ) + "Webhooks/Twilio.ashx";

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

                                        if (response != null)
                                        {
                                            recipient.Status = GetCommunicationRecipientStatus(response);

                                            recipient.TransportEntityTypeName = GetType().FullName;
                                            recipient.UniqueMessageId = response.Sid;

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

                                    }
                                    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;
                                    ExceptionLogService.LogException( ex, null );
                                }
                                rockContext.SaveChanges();
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
        /// <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.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" );
            }
        }
        /// <summary>
        /// Saves the person notes and history.
        /// </summary>
        /// <param name="registrationPersonFirstName">First name of the registration person.</param>
        /// <param name="registrationPersonLastName">Last name of the registration person.</param>
        /// <param name="currentPersonAliasId">The current person alias identifier.</param>
        /// <param name="previousRegistrantPersonIds">The previous registrant person ids.</param>
        public void SavePersonNotesAndHistory(string registrationPersonFirstName, string registrationPersonLastName, int?currentPersonAliasId, List <int> previousRegistrantPersonIds)
        {
            // Setup Note settings
            Registration  registration = this;
            NoteTypeCache noteType     = null;

            using (RockContext rockContext = new RockContext())
            {
                RegistrationInstance registrationInstance = registration.RegistrationInstance ?? new RegistrationInstanceService(rockContext).Get(registration.RegistrationInstanceId);
                RegistrationTemplate registrationTemplate = registrationInstance.RegistrationTemplate ?? new RegistrationTemplateService(rockContext).Get(registrationInstance.RegistrationTemplateId);

                if (registrationTemplate != null && registrationTemplate.AddPersonNote)
                {
                    noteType = NoteTypeCache.Get(Rock.SystemGuid.NoteType.PERSON_EVENT_REGISTRATION.AsGuid());
                    if (noteType != null)
                    {
                        var noteService        = new NoteService(rockContext);
                        var personAliasService = new PersonAliasService(rockContext);

                        Person registrar = null;
                        if (registration.PersonAliasId.HasValue)
                        {
                            registrar = personAliasService.GetPerson(registration.PersonAliasId.Value);
                        }

                        var registrantNames = new List <string>();

                        // Get each registrant
                        foreach (var registrantPersonAliasId in registration.Registrants
                                 .Where(r => r.PersonAliasId.HasValue)
                                 .Select(r => r.PersonAliasId.Value)
                                 .ToList())
                        {
                            var registrantPerson = personAliasService.GetPerson(registrantPersonAliasId);
                            if (registrantPerson != null && (previousRegistrantPersonIds == null || !previousRegistrantPersonIds.Contains(registrantPerson.Id)))
                            {
                                var noteText = new StringBuilder();
                                noteText.AppendFormat("Registered for {0}", registrationInstance.Name);

                                string registrarFullName = string.Empty;

                                if (registrar != null && registrar.Id != registrantPerson.Id)
                                {
                                    registrarFullName = string.Format(" by {0}", registrar.FullName);
                                    registrantNames.Add(registrantPerson.FullName);
                                }

                                if (registrar != null && (registrationPersonFirstName != registrar.NickName || registrationPersonLastName != registrar.LastName))
                                {
                                    registrarFullName = string.Format(" by {0}", registrationPersonFirstName + " " + registrationPersonLastName);
                                }

                                noteText.Append(registrarFullName);

                                if (noteText.Length > 0)
                                {
                                    var note = new Note();
                                    note.NoteTypeId    = noteType.Id;
                                    note.IsSystem      = false;
                                    note.IsAlert       = false;
                                    note.IsPrivateNote = false;
                                    note.EntityId      = registrantPerson.Id;
                                    note.Caption       = string.Empty;
                                    note.Text          = noteText.ToString();
                                    if (registrar == null)
                                    {
                                        note.CreatedByPersonAliasId = currentPersonAliasId;
                                    }
                                    else
                                    {
                                        note.CreatedByPersonAliasId = registrar.PrimaryAliasId;
                                    }

                                    noteService.Add(note);
                                }

                                var changes = new History.HistoryChangeList();
                                changes.AddChange(History.HistoryVerb.Registered, History.HistoryChangeType.Record, null);
                                HistoryService.SaveChanges(
                                    rockContext,
                                    typeof(Person),
                                    Rock.SystemGuid.Category.HISTORY_PERSON_REGISTRATION.AsGuid(),
                                    registrantPerson.Id,
                                    changes,
                                    registrationInstance.Name,
                                    typeof(Registration),
                                    registration.Id,
                                    false,
                                    currentPersonAliasId,
                                    rockContext.SourceOfChange);
                            }
                        }

                        if (registrar != null && registrantNames.Any())
                        {
                            string namesText = string.Empty;
                            if (registrantNames.Count >= 2)
                            {
                                int lessOne = registrantNames.Count - 1;
                                namesText = registrantNames.Take(lessOne).ToList().AsDelimited(", ") +
                                            " and " +
                                            registrantNames.Skip(lessOne).Take(1).First() + " ";
                            }
                            else
                            {
                                namesText = registrantNames.First() + " ";
                            }

                            var note = new Note();
                            note.NoteTypeId    = noteType.Id;
                            note.IsSystem      = false;
                            note.IsAlert       = false;
                            note.IsPrivateNote = false;
                            note.EntityId      = registrar.Id;
                            note.Caption       = string.Empty;
                            note.Text          = string.Format("Registered {0} for {1}", namesText, registrationInstance.Name);
                            noteService.Add(note);

                            var changes = new History.HistoryChangeList();
                            changes.AddChange(History.HistoryVerb.Registered, History.HistoryChangeType.Record, namesText);

                            HistoryService.SaveChanges(
                                rockContext,
                                typeof(Person),
                                Rock.SystemGuid.Category.HISTORY_PERSON_REGISTRATION.AsGuid(),
                                registrar.Id,
                                changes,
                                registrationInstance.Name,
                                typeof(Registration),
                                registration.Id,
                                false,
                                currentPersonAliasId,
                                rockContext.SourceOfChange);
                        }

                        rockContext.SaveChanges();
                    }
                }
            }
        }
Exemple #7
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.Recipients.Where( r => r.Status == Model.CommunicationRecipientStatus.Pending ).Any() &&
                ( !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 = recipientService.Get( communication.Id, CommunicationRecipientStatus.Pending ).FirstOrDefault();
                        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" );
                                    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 #8
0
        protected void btnNext_Click( object sender, EventArgs e )
        {
            if ( Page.IsValid )
            {
                if ( CurrentCategoryIndex < attributeControls.Count )
                {
                    CurrentCategoryIndex++;
                    ShowAttributeCategory( CurrentCategoryIndex );
                }
                else
                {
                    var familyMembers = GetControlData();
                    if ( familyMembers.Any() )
                    {

                        RockTransactionScope.WrapTransaction( () =>
                        {
                            using ( new UnitOfWorkScope() )
                            {
                                var familyGroupType = GroupTypeCache.GetFamilyGroupType();

                                var familyChanges = new List<string>();
                                var familyMemberChanges = new Dictionary<Guid, List<string>>();
                                var familyDemographicChanges = new Dictionary<Guid, List<string>>();

                                if ( familyGroupType != null )
                                {
                                    var groupService = new GroupService();

                                    var groupTypeRoleService = new GroupTypeRoleService();

                                    var familyGroup = new Group();
                                    familyGroup.GroupTypeId = familyGroupType.Id;
                                    
                                    familyChanges.Add("Created");
                                    
                                    familyGroup.Name = familyMembers.FirstOrDefault().Person.LastName + " Family";
                                    History.EvaluateChange( familyChanges, "Name", string.Empty, familyGroup.Name );

                                    int? campusId = cpCampus.SelectedValueAsInt();
                                    if (campusId.HasValue)
                                    {
                                        History.EvaluateChange( familyChanges, "Campus", string.Empty, CampusCache.Read( campusId.Value ).Name );
                                    }
                                    familyGroup.CampusId = campusId;

                                    foreach(var familyMember in familyMembers)
                                    {
                                        var person = familyMember.Person;
                                        if ( person != null )
                                        {
                                            familyGroup.Members.Add( familyMember );

                                            var demographicChanges = new List<string>();
                                            demographicChanges.Add( "Created" );
                                            History.EvaluateChange( demographicChanges, "Record Status", string.Empty,
                                                person.RecordStatusReasonValueId.HasValue ? DefinedValueCache.GetName( person.RecordStatusReasonValueId.Value ) : string.Empty );
                                            History.EvaluateChange( demographicChanges, "Title", string.Empty,
                                                person.TitleValueId.HasValue ? DefinedValueCache.GetName( person.TitleValueId ) : string.Empty );
                                            History.EvaluateChange( demographicChanges, "First Name", string.Empty, person.FirstName);
                                            History.EvaluateChange( demographicChanges, "Nick Name", string.Empty, person.NickName );
                                            History.EvaluateChange( demographicChanges, "Middle Name", string.Empty, person.MiddleName );
                                            History.EvaluateChange( demographicChanges, "Last Name", string.Empty, person.LastName );
                                            History.EvaluateChange( demographicChanges, "Gender", null, person.Gender );
                                            History.EvaluateChange( demographicChanges, "Birth Date", null, person.BirthDate );
                                            History.EvaluateChange( demographicChanges, "Connection Status", string.Empty,
                                                person.ConnectionStatusValueId.HasValue ? DefinedValueCache.GetName( person.ConnectionStatusValueId ) : string.Empty );
                                            History.EvaluateChange( demographicChanges, "Graduation Date", null, person.GraduationDate );
                                            familyDemographicChanges.Add( person.Guid, demographicChanges );

                                            var memberChanges = new List<string>();
                                            string roleName = familyGroupType.Roles[familyMember.GroupRoleId] ?? string.Empty;
                                            History.EvaluateChange( memberChanges, "Role", string.Empty, roleName );
                                            familyMemberChanges.Add( person.Guid, memberChanges );
                                        }
                                    }

                                    if ( !String.IsNullOrWhiteSpace( tbStreet1.Text ) ||
                                         !String.IsNullOrWhiteSpace( tbStreet2.Text ) ||
                                         !String.IsNullOrWhiteSpace( tbCity.Text ) ||
                                         !String.IsNullOrWhiteSpace( tbZip.Text ) )
                                    {
                                        string addressChangeField = "Address";

                                        var groupLocation = new GroupLocation();
                                        var location = new LocationService().Get(
                                            tbStreet1.Text, tbStreet2.Text, tbCity.Text, ddlState.SelectedValue, tbZip.Text );
                                        groupLocation.Location = location;

                                        Guid locationTypeGuid = Guid.Empty;
                                        if ( Guid.TryParse( GetAttributeValue( "LocationType" ), out locationTypeGuid ) )
                                        {
                                            var locationType = Rock.Web.Cache.DefinedValueCache.Read( locationTypeGuid );
                                            if ( locationType != null )
                                            {
                                                addressChangeField = string.Format("{0} Address", locationType.Name);
                                                groupLocation.GroupLocationTypeValueId = locationType.Id;
                                            }
                                        }

                                        familyGroup.GroupLocations.Add( groupLocation );

                                        History.EvaluateChange( familyChanges, addressChangeField, string.Empty, groupLocation.Location.ToString() );
                                    }


                                    groupService.Add( familyGroup, CurrentPersonId );
                                    groupService.Save( familyGroup, CurrentPersonId );

                                    var historyService = new HistoryService();
                                    historyService.SaveChanges( typeof( Group ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                        familyGroup.Id, familyChanges, CurrentPersonId );

                                    var personService = new PersonService();

                                    foreach ( var groupMember in familyMembers )
                                    {
                                        var person = personService.Get( groupMember.PersonId );
                                        if ( person != null )
                                        {
                                            var changes = familyDemographicChanges[person.Guid];
                                            if ( groupMember.GroupRoleId != _childRoleId )
                                            {
                                                person.GivingGroupId = familyGroup.Id;
                                                personService.Save( person, CurrentPersonId );
                                                History.EvaluateChange( changes, "Giving Group", string.Empty, familyGroup.Name );
                                            }

                                            foreach ( var attributeControl in attributeControls )
                                            {
                                                foreach ( var attribute in attributeControl.AttributeList )
                                                {
                                                    string attributeValue = person.GetAttributeValue( attribute.Key );
                                                    if ( !string.IsNullOrWhiteSpace( attributeValue ) )
                                                    {
                                                        Rock.Attribute.Helper.SaveAttributeValue( person, attribute, attributeValue, CurrentPersonId );
                                                        attributeValue = attribute.FieldType.Field.FormatValue( null, attributeValue, attribute.QualifierValues, false );
                                                        History.EvaluateChange( changes, attribute.Name, string.Empty, attributeValue );
                                                    }
                                                }
                                            }

                                            historyService.SaveChanges( typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(),
                                                person.Id, changes, CurrentPersonId );

                                            historyService.SaveChanges( typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                                person.Id, familyMemberChanges[person.Guid], familyGroup.Name, typeof( Group), familyGroup.Id, CurrentPersonId );
                                        }
                                    }
                                }
                            }
                        } );

                        Response.Redirect( string.Format( "~/Person/{0}", familyMembers[0].Person.Id ), false );
                    }

                }
            }

        }
Exemple #9
0
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            // if a Location is getting edited, validate and save it
            if ( gLocations.EditIndex >= 0 )
            {
                var row = gLocations.Rows[gLocations.EditIndex];
                AddressControl acAddress = row.FindControl( "acAddress" ) as AddressControl;
                if ( acAddress.IsValid )
                {
                    gLocations_RowUpdating( sender, new GridViewUpdateEventArgs( gLocations.EditIndex ) );
                }
                else
                {
                    // acAddress will render an error message
                    return;
                }
            }

            if ( !IsUserAuthorized( Rock.Security.Authorization.EDIT ) )
            {
                return;
            }

            // confirmation was disabled by btnSave on client-side.  So if returning without a redirect,
            // it should be enabled.  If returning with a redirect, the control won't be updated to reflect
            // confirmation being enabled, so it's ok to enable it here
            confirmExit.Enabled = true;

            if ( Page.IsValid )
            {
                confirmExit.Enabled = true;

                var rockContext = new RockContext();
                rockContext.WrapTransaction( () =>
                {
                    var groupService = new GroupService( rockContext );
                    var groupMemberService = new GroupMemberService( rockContext );
                    var personService = new PersonService( rockContext );
                    var historyService = new HistoryService( rockContext );

                    var groupChanges = new List<string>();

                    // SAVE GROUP
                    _group = groupService.Get( _group.Id );

                    History.EvaluateChange( groupChanges, "Group Name", _group.Name, tbGroupName.Text );
                    _group.Name = tbGroupName.Text;

                    int? campusId = cpCampus.SelectedValueAsInt();
                    if ( _group.CampusId != campusId )
                    {
                        History.EvaluateChange(
                            groupChanges,
                            "Campus",
                            _group.CampusId.HasValue ? CampusCache.Read( _group.CampusId.Value ).Name : string.Empty,
                            campusId.HasValue ? CampusCache.Read( campusId.Value ).Name : string.Empty );

                        _group.CampusId = campusId;
                    }

                    rockContext.SaveChanges();

                    // SAVE GROUP MEMBERS
                    int? recordStatusValueID = ddlRecordStatus.SelectedValueAsInt();
                    int? reasonValueId = ddlReason.SelectedValueAsInt();
                    var newGroups = new List<Group>();

                    foreach ( var groupMemberInfo in GroupMembers )
                    {
                        var memberChanges = new List<string>();
                        var demographicChanges = new List<string>();

                        var role = _groupType.Roles.Where( r => r.Guid.Equals( groupMemberInfo.RoleGuid ) ).FirstOrDefault();
                        if ( role == null )
                        {
                            role = _groupType.Roles.FirstOrDefault();
                        }

                        bool isAdult = role != null && role.Guid.Equals( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT );

                        // People added to group (new or from other group )
                        if ( !groupMemberInfo.ExistingGroupMember )
                        {
                            Person person = null;
                            if ( groupMemberInfo.Id == -1 )
                            {
                                // added new person
                                demographicChanges.Add( "Created" );

                                person = new Person();

                                person.TitleValueId = groupMemberInfo.TitleValueId;
                                person.FirstName = groupMemberInfo.FirstName;
                                person.NickName = groupMemberInfo.NickName;
                                person.LastName = groupMemberInfo.LastName;
                                person.SuffixValueId = groupMemberInfo.SuffixValueId;
                                person.Gender = groupMemberInfo.Gender;

                                DateTime? birthdate = groupMemberInfo.BirthDate;
                                if ( birthdate.HasValue )
                                {
                                    // If setting a future birthdate, subtract a century until birthdate is not greater than today.
                                    var today = RockDateTime.Today;
                                    while ( birthdate.Value.CompareTo( today ) > 0 )
                                    {
                                        birthdate = birthdate.Value.AddYears( -100 );
                                    }
                                }

                                person.SetBirthDate( birthdate );

                                person.MaritalStatusValueId = groupMemberInfo.MaritalStatusValueId;
                                person.GradeOffset = groupMemberInfo.GradeOffset;
                                person.ConnectionStatusValueId = groupMemberInfo.ConnectionStatusValueId;
                                if ( isAdult )
                                {
                                    person.GivingGroupId = _group.Id;
                                }

                                person.IsEmailActive = true;
                                person.EmailPreference = EmailPreference.EmailAllowed;
                                person.RecordTypeValueId = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON.AsGuid() ).Id;
                            }
                            else
                            {
                                person = personService.Get( groupMemberInfo.Id );
                            }

                            if ( person == null )
                            {
                                // shouldn't happen
                                return;
                            }

                            if ( _isFamilyGroupType )
                            {
                                if ( person.RecordStatusValueId != recordStatusValueID )
                                {
                                    History.EvaluateChange( demographicChanges, "Record Status", DefinedValueCache.GetName( person.RecordStatusValueId ), DefinedValueCache.GetName( recordStatusValueID ) );
                                    person.RecordStatusValueId = recordStatusValueID;
                                }

                                if ( person.RecordStatusValueId != recordStatusValueID )
                                {
                                    History.EvaluateChange( demographicChanges, "Record Status Reason", DefinedValueCache.GetName( person.RecordStatusReasonValueId ), DefinedValueCache.GetName( reasonValueId ) );
                                    person.RecordStatusReasonValueId = reasonValueId;
                                }
                            }

                            PersonService.AddPersonToGroup( person, person.Id == 0, _group.Id, role.Id, rockContext );
                        }
                        else
                        {
                            // existing group members
                            var groupMember = groupMemberService.Queryable( "Person", true ).Where( m =>
                                m.PersonId == groupMemberInfo.Id &&
                                m.Group.GroupTypeId == _groupType.Id &&
                                m.GroupId == _group.Id ).FirstOrDefault();

                            if ( groupMember != null )
                            {
                                if ( groupMemberInfo.Removed )
                                {
                                    if ( !groupMemberInfo.IsInOtherGroups )
                                    {
                                        var newFamilyChanges = new List<string>();

                                        // Family member was removed and should be created in their own new family
                                        var newGroup = new Group();
                                        newGroup.Name = groupMemberInfo.LastName + " " + _groupType.Name;
                                        History.EvaluateChange( newFamilyChanges, "Family", string.Empty, newGroup.Name );

                                        newGroup.GroupTypeId = _groupType.Id;

                                        if ( _group.CampusId.HasValue )
                                        {
                                            History.EvaluateChange( newFamilyChanges, "Campus", string.Empty, CampusCache.Read( _group.CampusId.Value ).Name );
                                        }

                                        newGroup.CampusId = _group.CampusId;

                                        groupService.Add( newGroup );
                                        rockContext.SaveChanges();

                                        // If person's previous giving group was this family, set it to their new family id
                                        if ( _isFamilyGroupType && groupMember.Person.GivingGroup != null && groupMember.Person.GivingGroupId == _group.Id )
                                        {
                                            History.EvaluateChange( demographicChanges, "Giving Group", groupMember.Person.GivingGroup.Name, _group.Name );
                                            groupMember.Person.GivingGroupId = newGroup.Id;
                                        }

                                        groupMember.Group = newGroup;
                                        rockContext.SaveChanges();

                                        var newMemberChanges = new List<string>();

                                        if ( _isFamilyGroupType )
                                        {
                                            History.EvaluateChange( newMemberChanges, "Role", string.Empty, groupMember.GroupRole.Name );

                                            HistoryService.SaveChanges(
                                                rockContext,
                                                typeof( Person ),
                                                Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                                groupMember.Person.Id,
                                                newFamilyChanges,
                                                newGroup.Name,
                                                typeof( Group ),
                                                newGroup.Id );
                                        }
                                        newGroups.Add( newGroup );

                                        History.EvaluateChange( memberChanges, "Role", groupMember.GroupRole.Name, string.Empty );
                                    }
                                    else
                                    {
                                        History.EvaluateChange( groupChanges, "Family", groupMember.Group.Name, string.Empty );

                                        groupMemberService.Delete( groupMember );
                                        rockContext.SaveChanges();
                                    }
                                }
                                else
                                {
                                    // Existing member was not remvoved
                                    if ( role != null )
                                    {
                                        History.EvaluateChange( memberChanges, "Role", groupMember.GroupRole != null ? groupMember.GroupRole.Name : string.Empty, role.Name );
                                        groupMember.GroupRoleId = role.Id;

                                        if ( _isFamilyGroupType )
                                        {
                                            if ( recordStatusValueID > 0 )
                                            {
                                                History.EvaluateChange( demographicChanges, "Record Status", DefinedValueCache.GetName( groupMember.Person.RecordStatusValueId ), DefinedValueCache.GetName( recordStatusValueID ) );
                                                groupMember.Person.RecordStatusValueId = recordStatusValueID;

                                                History.EvaluateChange( demographicChanges, "Record Status Reason", DefinedValueCache.GetName( groupMember.Person.RecordStatusReasonValueId ), DefinedValueCache.GetName( reasonValueId ) );
                                                groupMember.Person.RecordStatusReasonValueId = reasonValueId;
                                            }
                                        }

                                        rockContext.SaveChanges();
                                    }
                                }
                            }
                        }

                        // Remove anyone that was moved from another family
                        if ( groupMemberInfo.RemoveFromOtherGroups )
                        {
                            PersonService.RemovePersonFromOtherFamilies( _group.Id, groupMemberInfo.Id, rockContext );
                        }

                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), groupMemberInfo.Id, demographicChanges );

                        if ( _isFamilyGroupType )
                        {
                            HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(), groupMemberInfo.Id, memberChanges, _group.Name, typeof( Group ), _group.Id );
                        }
                    }

                    // SAVE LOCATIONS
                    var groupLocationService = new GroupLocationService( rockContext );

                    // delete any group locations that were removed
                    var remainingLocationIds = GroupAddresses.Where( a => a.Id > 0 ).Select( a => a.Id ).ToList();
                    foreach ( var removedLocation in groupLocationService.Queryable( "GroupLocationTypeValue,Location" )
                        .Where( l => l.GroupId == _group.Id &&
                            !remainingLocationIds.Contains( l.Id ) ) )
                    {
                        History.EvaluateChange( groupChanges,
                            ( removedLocation.GroupLocationTypeValue != null ? removedLocation.GroupLocationTypeValue.Value : "Unknown" ) + " Location",
                            removedLocation.Location.ToString(), string.Empty );
                        groupLocationService.Delete( removedLocation );
                    }

                    rockContext.SaveChanges();

                    foreach ( var groupAddressInfo in GroupAddresses.Where( a => a.Id >= 0 ) )
                    {
                        Location updatedAddress = null;
                        if ( groupAddressInfo.LocationIsDirty )
                        {
                            updatedAddress = new LocationService( rockContext ).Get( groupAddressInfo.Street1, groupAddressInfo.Street2, groupAddressInfo.City, groupAddressInfo.State, groupAddressInfo.PostalCode, groupAddressInfo.Country );
                        }

                        GroupLocation groupLocation = null;
                        if ( groupAddressInfo.Id > 0 )
                        {
                            groupLocation = groupLocationService.Get( groupAddressInfo.Id );
                        }

                        if ( groupLocation == null )
                        {
                            groupLocation = new GroupLocation();
                            groupLocation.GroupId = _group.Id;
                            groupLocationService.Add( groupLocation );
                        }

                        History.EvaluateChange(
                            groupChanges,
                            "Location Type",
                            groupLocation.GroupLocationTypeValueId.HasValue ? DefinedValueCache.Read( groupLocation.GroupLocationTypeValueId.Value ).Value : string.Empty,
                            groupAddressInfo.LocationTypeName );
                        groupLocation.GroupLocationTypeValueId = groupAddressInfo.LocationTypeId;

                        History.EvaluateChange(
                            groupChanges,
                            groupAddressInfo.LocationTypeName + " Is Mailing",
                            groupLocation.IsMailingLocation.ToString(),
                            groupAddressInfo.IsMailing.ToString() );

                        groupLocation.IsMailingLocation = groupAddressInfo.IsMailing;

                        History.EvaluateChange(
                            groupChanges,
                            groupAddressInfo.LocationTypeName + " Is Map Location",
                            groupLocation.IsMappedLocation.ToString(),
                            groupAddressInfo.IsLocation.ToString() );

                        groupLocation.IsMappedLocation = groupAddressInfo.IsLocation;

                        if ( updatedAddress != null )
                        {
                            History.EvaluateChange(
                                groupChanges,
                                groupAddressInfo.LocationTypeName + " Location",
                                groupLocation.Location != null ? groupLocation.Location.ToString() : string.Empty,
                                updatedAddress.ToString() );
                            groupLocation.Location = updatedAddress;
                        }

                        rockContext.SaveChanges();

                        // Add the same locations to any new families created by removing an existing family member
                        if ( newGroups.Any() )
                        {
                            // reload grouplocation for access to child properties
                            groupLocation = groupLocationService.Get( groupLocation.Id );
                            foreach ( var newGroup in newGroups )
                            {
                                var newGroupLocation = new GroupLocation();
                                newGroupLocation.GroupId = newGroup.Id;
                                newGroupLocation.LocationId = groupLocation.LocationId;
                                newGroupLocation.GroupLocationTypeValueId = groupLocation.GroupLocationTypeValueId;
                                newGroupLocation.IsMailingLocation = groupLocation.IsMailingLocation;
                                newGroupLocation.IsMappedLocation = groupLocation.IsMappedLocation;
                                groupLocationService.Add( newGroupLocation );
                            }

                            rockContext.SaveChanges();
                        }
                    }

                    _group.LoadAttributes();
                    Rock.Attribute.Helper.GetEditValues( phGroupAttributes, _group );
                    _group.SaveAttributeValues( rockContext );

                    if ( _isFamilyGroupType )
                    {
                        foreach ( var fm in _group.Members )
                        {
                            HistoryService.SaveChanges(
                                rockContext,
                                typeof( Person ),
                                Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                fm.PersonId,
                                groupChanges,
                                _group.Name,
                                typeof( Group ),
                                _group.Id );
                        }
                    }

                    Response.Redirect( string.Format( "~/Person/{0}", Person.Id ), false );

                } );
            }
        }
Exemple #10
0
        /// <summary>
        /// Process a refund for a transaction.
        /// </summary>
        /// <param name="transaction">The refund transaction.</param>
        /// <param name="amount">The amount.</param>
        /// <param name="reasonValueId">The reason value identifier.</param>
        /// <param name="summary">The summary.</param>
        /// <param name="process">if set to <c>true</c> [process].</param>
        /// <param name="batchNameSuffix">The batch name suffix.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        public FinancialTransaction ProcessRefund(FinancialTransaction transaction, decimal?amount, int?reasonValueId, string summary, bool process, string batchNameSuffix, out string errorMessage)
        {
            errorMessage = string.Empty;

            // Validate parameters
            if (transaction == null)
            {
                errorMessage = "A valid transaction is required";
                return(null);
            }

            if (transaction.Batch == null)
            {
                errorMessage = "Transaction must belong to a batch";
                return(null);
            }

            if (!amount.HasValue || amount.Value <= 0.0m)
            {
                amount = transaction.TotalAmount;
            }

            if (!amount.HasValue || amount.Value <= 0.0m)
            {
                errorMessage = string.Format("Amount must be greater than {0}", 0.0m.FormatAsCurrency());
                return(null);
            }


            FinancialTransaction refundTransaction = null;

            // If processing the refund through gateway, get the gateway component and process a "Credit" transaction.
            if (process)
            {
                if (transaction.FinancialGateway == null || transaction.TransactionCode.IsNullOrWhiteSpace())
                {
                    errorMessage = "When processing the refund through the Gateway, the transaction must have a valid Gateway and Transaction Code";
                    return(null);
                }

                var gatewayComponent = transaction.FinancialGateway?.GetGatewayComponent();
                if (gatewayComponent == null)
                {
                    errorMessage = "Could not get the Gateway component in order to process the refund";
                    return(null);
                }

                refundTransaction = gatewayComponent.Credit(transaction, amount.Value, summary, out errorMessage);
                if (refundTransaction == null)
                {
                    return(null);
                }
            }
            else
            {
                refundTransaction = new FinancialTransaction();
            }

            refundTransaction.AuthorizedPersonAliasId    = transaction.AuthorizedPersonAliasId;
            refundTransaction.TransactionDateTime        = RockDateTime.Now;
            refundTransaction.FinancialGatewayId         = transaction.FinancialGatewayId;
            refundTransaction.TransactionTypeValueId     = transaction.TransactionTypeValueId;
            refundTransaction.SourceTypeValueId          = transaction.SourceTypeValueId;
            refundTransaction.ForeignCurrencyCodeValueId = transaction.ForeignCurrencyCodeValueId;

            if (transaction.FinancialPaymentDetail != null)
            {
                refundTransaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                refundTransaction.FinancialPaymentDetail.AccountNumberMasked   = transaction.FinancialPaymentDetail.AccountNumberMasked;
                refundTransaction.FinancialPaymentDetail.BillingLocationId     = transaction.FinancialPaymentDetail.BillingLocationId;
                refundTransaction.FinancialPaymentDetail.CreditCardTypeValueId = transaction.FinancialPaymentDetail.CreditCardTypeValueId;
                refundTransaction.FinancialPaymentDetail.CurrencyTypeValueId   = transaction.FinancialPaymentDetail.CurrencyTypeValueId;
                refundTransaction.FinancialPaymentDetail.ExpirationMonth       = transaction.FinancialPaymentDetail.ExpirationMonth;
                refundTransaction.FinancialPaymentDetail.ExpirationYear        = transaction.FinancialPaymentDetail.ExpirationYear;
                refundTransaction.FinancialPaymentDetail.NameOnCard            = transaction.FinancialPaymentDetail.NameOnCard;
            }

            decimal remainingBalance        = amount.Value;
            decimal?foreignCurrencyAmount   = transaction.TransactionDetails.Select(d => d.ForeignCurrencyAmount).Sum();
            decimal remainingForeignBalance = foreignCurrencyAmount ?? 0.0m;

            /*
             * If the refund is for a currency other then the Organization's currency it is up to the
             * gateway to return the correct transaction details.
             */

            if (refundTransaction.TransactionDetails?.Any() != true)
            {
                foreach (var account in transaction.TransactionDetails.Where(a => a.Amount > 0))
                {
                    var transactionDetail = new FinancialTransactionDetail();
                    transactionDetail.AccountId    = account.AccountId;
                    transactionDetail.EntityId     = account.EntityId;
                    transactionDetail.EntityTypeId = account.EntityTypeId;
                    refundTransaction.TransactionDetails.Add(transactionDetail);

                    if (remainingBalance >= account.Amount)
                    {
                        transactionDetail.Amount = 0 - account.Amount;
                        remainingBalance        -= account.Amount;
                    }
                    else
                    {
                        transactionDetail.Amount = 0 - remainingBalance;
                        remainingBalance         = 0.0m;
                    }

                    if (account.ForeignCurrencyAmount.HasValue)
                    {
                        if (remainingForeignBalance >= account.ForeignCurrencyAmount.Value)
                        {
                            transactionDetail.ForeignCurrencyAmount = 0 - account.ForeignCurrencyAmount.Value;
                            remainingForeignBalance -= account.ForeignCurrencyAmount.Value;
                        }
                        else
                        {
                            transactionDetail.ForeignCurrencyAmount = 0 - remainingForeignBalance;
                            remainingForeignBalance = 0.0m;
                        }
                    }

                    if (remainingBalance <= 0.0m && remainingForeignBalance <= 0.0m)
                    {
                        break;
                    }
                }
            }

            if (remainingBalance > 0 && refundTransaction.TransactionDetails.Any())
            {
                refundTransaction.TransactionDetails.Last().Amount += remainingBalance;
            }

            var rockContext = this.Context as Rock.Data.RockContext;

            var registrationEntityType = EntityTypeCache.Get(typeof(Rock.Model.Registration));

            if (registrationEntityType != null)
            {
                foreach (var transactionDetail in refundTransaction.TransactionDetails
                         .Where(d =>
                                d.EntityTypeId.HasValue &&
                                d.EntityTypeId.Value == registrationEntityType.Id &&
                                d.EntityId.HasValue))
                {
                    var registrationChanges = new History.HistoryChangeList();
                    registrationChanges.AddChange(History.HistoryVerb.Process, History.HistoryChangeType.Record, $"{transactionDetail.Amount.FormatAsCurrency()} Refund");
                    HistoryService.SaveChanges(
                        rockContext,
                        typeof(Registration),
                        Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(),
                        transactionDetail.EntityId.Value,
                        registrationChanges
                        );
                }
            }

            refundTransaction.RefundDetails = new FinancialTransactionRefund();
            refundTransaction.RefundDetails.RefundReasonValueId   = reasonValueId;
            refundTransaction.RefundDetails.RefundReasonSummary   = summary;
            refundTransaction.RefundDetails.OriginalTransactionId = transaction.Id;

            string batchName = transaction.Batch.Name;

            if (batchNameSuffix.IsNotNullOrWhiteSpace() && !batchName.EndsWith(batchNameSuffix))
            {
                batchName += batchNameSuffix;
            }

            // Get the batch
            var      batchService = new FinancialBatchService(rockContext);
            TimeSpan timespan     = new TimeSpan();

            if (transaction.FinancialGateway != null)
            {
                timespan = transaction.FinancialGateway.GetBatchTimeOffset();
            }
            var batch = batchService.GetByNameAndDate(batchName, refundTransaction.TransactionDateTime.Value, timespan);

            // If this is a new Batch, SaveChanges so that we can get the Batch.Id
            if (batch.Id == 0)
            {
                rockContext.SaveChanges();
            }

            refundTransaction.BatchId = batch.Id;
            Add(refundTransaction);
            rockContext.SaveChanges();

            batchService.IncrementControlAmount(batch.Id, refundTransaction.TotalAmount, null);
            rockContext.SaveChanges();

            return(refundTransaction);
        }
Exemple #11
0
        /// <summary>
        /// Creates a new <see cref="Rock.Model.UserLogin" /> and saves it to the database.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="person">The person.</param>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="entityTypeId">The EntityTypeId of the <see cref="Rock.Model.EntityType"/> for the authentication service that this UserLogin user will use.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="isConfirmed">if set to <c>true</c> [is confirmed].</param>
        /// <param name="isRequirePasswordChange">if set to <c>true</c> [is require password change].</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentOutOfRangeException">username;Username already exists</exception>
        /// <exception cref="System.ArgumentException">
        /// entityTypeId
        /// or
        /// Invalid EntityTypeId, entity does not exist;entityTypeId
        /// or
        /// Invalid Person, person does not exist;person
        /// </exception>
        public static UserLogin Create(RockContext rockContext,
                                       Rock.Model.Person person,
                                       AuthenticationServiceType serviceType,
                                       int entityTypeId,
                                       string username,
                                       string password,
                                       bool isConfirmed,
                                       bool isRequirePasswordChange)
        {
            if (person != null)
            {
                var userLoginService = new UserLoginService(rockContext);

                var entityType = EntityTypeCache.Get(entityTypeId);
                if (entityType != null)
                {
                    UserLogin user = userLoginService.GetByUserName(username);
                    if (user != null)
                    {
                        throw new ArgumentOutOfRangeException("username", "Username already exists");
                    }

                    DateTime createDate = RockDateTime.Now;

                    user              = new UserLogin();
                    user.Guid         = Guid.NewGuid();
                    user.EntityTypeId = entityTypeId;
                    user.UserName     = username;
                    user.IsConfirmed  = isConfirmed;
                    user.LastPasswordChangedDateTime = createDate;
                    user.PersonId = person.Id;
                    user.IsPasswordChangeRequired = isRequirePasswordChange;

                    if (serviceType == AuthenticationServiceType.Internal)
                    {
                        var authenticationComponent = AuthenticationContainer.GetComponent(entityType.Name);
                        if (authenticationComponent == null || !authenticationComponent.IsActive)
                        {
                            throw new ArgumentException(string.Format("'{0}' service does not exist, or is not active", entityType.FriendlyName), "entityTypeId");
                        }

                        user.Password = authenticationComponent.EncodePassword(user, password);
                    }

                    userLoginService.Add(user);
                    rockContext.SaveChanges();

                    var historyCategory = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), rockContext);
                    if (historyCategory != null)
                    {
                        var changes = new History.HistoryChangeList();
                        History.EvaluateChange(changes, "User Login", string.Empty, username);
                        HistoryService.SaveChanges(rockContext, typeof(Person), historyCategory.Guid, person.Id, changes);
                    }

                    return(user);
                }
                else
                {
                    throw new ArgumentException("Invalid EntityTypeId, entity does not exist", "entityTypeId");
                }
            }
            else
            {
                throw new ArgumentException("Invalid Person, person does not exist", "person");
            }
        }
Exemple #12
0
        /// <summary>
        /// This method is called in the
        /// <see cref="M:Rock.Data.Model`1.PreSaveChanges(Rock.Data.DbContext,System.Data.Entity.Infrastructure.DbEntityEntry,System.Data.Entity.EntityState)" />
        /// method. Use it to populate <see cref="P:Rock.Data.Model`1.HistoryItems" /> if needed.
        /// These history items are queued to be written into the database post save (so that they
        /// are only written if the save actually occurs).
        /// </summary>
        /// <param name="dbContext">The database context.</param>
        /// <param name="entry">The entry.</param>
        /// <param name="state">The state.</param>
        protected override void BuildHistoryItems(Data.DbContext dbContext, DbEntityEntry entry, EntityState state)
        {
            var attributeCache = AttributeCache.Get(AttributeId);

            if (attributeCache?.EntityTypeId == null)
            {
                return;
            }

            var entityTypeId = attributeCache.EntityTypeId.Value;
            var entityId     = EntityId;

            if (!entityId.HasValue && (entry.State == EntityState.Modified || entry.State == EntityState.Deleted))
            {
                entityId = entry.OriginalValues["EntityId"].ToStringSafe().AsIntegerOrNull();
            }

            var caption = attributeCache.Name;

            // Check to see if this attribute is for a person or group, and if so, save to history table
            var personEntityTypeId = EntityTypeCache.Get(typeof(Person)).Id;

            var entityTypesToSaveToHistoryTable = new List <int> {
                personEntityTypeId,
                EntityTypeCache.Get(typeof(Group)).Id
            };

            var saveToHistoryTable = entityTypesToSaveToHistoryTable.Contains(entityTypeId);

            // If the value is not directly linked to a person or group, it still may be linked through an attribute matrix.
            // Matrix attribute changes are only logged here for modify. Add and delete are handled in the AttributeMatrixItem.
            if (!saveToHistoryTable && state == EntityState.Modified && IsLikelyWithinMatrix())
            {
                var rootMatrixAttributeValue = GetRootMatrixAttributeValue();

                if (rootMatrixAttributeValue == null)
                {
                    return;
                }

                var rootMatrixAttributeCache = AttributeCache.Get(rootMatrixAttributeValue.AttributeId);

                if (rootMatrixAttributeCache == null || !rootMatrixAttributeCache.EntityTypeId.HasValue)
                {
                    return;
                }

                saveToHistoryTable = entityTypesToSaveToHistoryTable.Contains(rootMatrixAttributeCache.EntityTypeId.Value);

                if (saveToHistoryTable)
                {
                    // Use the values from the root matrix attribute since this is the attribute that ties the
                    // values to a person or group and are thus more meaningful
                    entityTypeId = rootMatrixAttributeCache.EntityTypeId.Value;
                    entityId     = rootMatrixAttributeValue.EntityId;
                    caption      = rootMatrixAttributeCache.Name;
                }
            }

            if (!saveToHistoryTable || !entityId.HasValue)
            {
                return;
            }

            // We have determined to write to the History table. Now determine what changed.
            var oldValue = GetHistoryOldValue(entry);
            var newValue = GetHistoryNewValue(state);

            if (oldValue == newValue)
            {
                return;
            }

            // Evaluate the history change
            var formattedOldValue = GetHistoryFormattedValue(oldValue, attributeCache);
            var formattedNewValue = GetHistoryFormattedValue(newValue, attributeCache);
            var historyChangeList = new History.HistoryChangeList();

            History.EvaluateChange(historyChangeList, attributeCache.Name, formattedOldValue, formattedNewValue, attributeCache.FieldType.Field.IsSensitive());

            if (!historyChangeList.Any())
            {
                return;
            }

            var categoryGuid = entityTypeId == personEntityTypeId?
                               SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid() :
                                   SystemGuid.Category.HISTORY_GROUP_CHANGES.AsGuid();

            HistoryItems = HistoryService.GetChanges(
                entityTypeId == personEntityTypeId ? typeof(Person) : typeof(Group),
                categoryGuid,
                entityId.Value,
                historyChangeList,
                caption,
                typeof(Attribute),
                AttributeId,
                dbContext.GetCurrentPersonAlias()?.Id,
                dbContext.SourceOfChange);
        }
Exemple #13
0
        /// <summary>
        /// Gets the timeline HTML.
        /// </summary>
        /// <param name="timelineLavaTemplate">The timeline lava template.</param>
        /// <param name="primaryEntityType">Type of the primary entity.</param>
        /// <param name="entityId">The entity identifier.</param>
        /// <param name="secondaryEntityType">Type of the secondary entity.</param>
        /// <param name="additionalMergeFields">The additional merge fields.</param>
        /// <returns></returns>
        public string GetTimelineHtml(string timelineLavaTemplate, EntityTypeCache primaryEntityType, int entityId, EntityTypeCache secondaryEntityType, Dictionary <string, object> additionalMergeFields)
        {
            RockContext    rockContext    = this.Context as RockContext;
            HistoryService historyService = new HistoryService(rockContext);

            // change this to adjust the granularity of the GetHistorySummaryByDateTime
            TimeSpan dateSummaryGranularity = TimeSpan.FromDays(1);

            if (primaryEntityType == null)
            {
                return(null);
            }

            var entityTypeIdPrimary = primaryEntityType.Id;

            var primaryEntity = historyService.GetEntityQuery(entityTypeIdPrimary).FirstOrDefault(a => a.Id == entityId);
            var historyQry    = historyService.Queryable().Where(a => a.CreatedDateTime.HasValue);

            if (secondaryEntityType == null)
            {
                // get history records where the primaryentity is the Entity
                historyQry = historyQry.Where(a => a.EntityTypeId == entityTypeIdPrimary && a.EntityId == entityId);
            }
            else
            {
                // get history records where the primaryentity is the Entity OR the primaryEntity is the RelatedEntity and the Entity is the Secondary Entity
                // For example, for GroupHistory, Set PrimaryEntityType to Group and SecondaryEntityType to GroupMember, then get history where the Group is History.Entity or the Group is the RelatedEntity and GroupMember is the EntityType
                var entityTypeIdSecondary = secondaryEntityType.Id;
                historyQry = historyQry.Where(a =>
                                              (a.EntityTypeId == entityTypeIdPrimary && a.EntityId == entityId) ||
                                              (a.RelatedEntityTypeId == entityTypeIdPrimary && a.EntityTypeId == entityTypeIdSecondary && a.RelatedEntityId == entityId));
            }

            var historySummaryList       = historyService.GetHistorySummary(historyQry);
            var historySummaryByDateList = historyService.GetHistorySummaryByDateTime(historySummaryList, dateSummaryGranularity);

            historySummaryByDateList = historySummaryByDateList.OrderByDescending(a => a.SummaryDateTime).ToList();
            var historySummaryByDateByVerbList = historyService.GetHistorySummaryByDateTimeAndVerb(historySummaryByDateList);

            var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, null, new Rock.Lava.CommonMergeFieldsOptions {
                GetLegacyGlobalMergeFields = false
            });

            mergeFields.Add("PrimaryEntity", primaryEntity);
            mergeFields.Add("PrimaryEntityTypeName", primaryEntityType.FriendlyName);
            if (secondaryEntityType != null)
            {
                mergeFields.Add("SecondaryEntityTypeName", secondaryEntityType.FriendlyName);
            }

            mergeFields.Add("HistorySummaryByDateByVerbList", historySummaryByDateByVerbList);
            if (additionalMergeFields != null)
            {
                foreach (var additionalMergeField in additionalMergeFields)
                {
                    mergeFields.AddOrIgnore(additionalMergeField.Key, additionalMergeField.Value);
                }
            }
            string timelineHtml = timelineLavaTemplate.ResolveMergeFields(mergeFields);

            return(timelineHtml);
        }
        /// <summary>
        /// This method is called in the
        /// <see cref="M:Rock.Data.Model`1.PreSaveChanges(Rock.Data.DbContext,System.Data.Entity.Infrastructure.DbEntityEntry,System.Data.Entity.EntityState)" />
        /// method. Use it to populate <see cref="P:Rock.Data.Model`1.HistoryItems" /> if needed.
        /// These history items are queued to be written into the database post save (so that they
        /// are only written if the save actually occurs).
        /// </summary>
        /// <param name="dbContext">The database context.</param>
        /// <param name="entry">The entry.</param>
        /// <param name="state">The state.</param>
        protected override void BuildHistoryItems(Data.DbContext dbContext, DbEntityEntry entry, EntityState state)
        {
            // Sometimes, especially if the model is being deleted, some properties might not be
            // populated, but we can query to try to get their original value. We need to use a new
            // rock context to get the actual value from the DB
            var rockContext   = new RockContext();
            var service       = new FinancialPersonSavedAccountService(rockContext);
            var originalModel = service.Queryable("PersonAlias, FinancialPaymentDetail")
                                .FirstOrDefault(fpsa => fpsa.Id == Id);

            // Use the original value for the person alias or the new value if that is not set
            var personId = (originalModel?.PersonAlias ?? PersonAlias)?.PersonId;

            if (!personId.HasValue)
            {
                // If this model is new, it won't have any virtual properties hydrated or an original
                // record in the database
                if (PersonAliasId.HasValue)
                {
                    var personAliasService = new PersonAliasService(rockContext);
                    var personAlias        = personAliasService.Get(PersonAliasId.Value);
                    personId = personAlias?.PersonId;
                }

                // We can't log history if we don't know who the saved account belongs to
                if (!personId.HasValue)
                {
                    return;
                }
            }

            History.HistoryVerb verb;

            switch (state)
            {
            case EntityState.Added:
                verb = History.HistoryVerb.Add;
                break;

            case EntityState.Deleted:
                verb = History.HistoryVerb.Delete;
                break;

            default:
                // As of now, there is no requirement to log other events
                return;
            }

            var historyChangeList = new History.HistoryChangeList();

            historyChangeList.AddChange(verb, History.HistoryChangeType.Record, "Financial Person Saved Account");

            HistoryItems = HistoryService.GetChanges(
                typeof(Person),
                Rock.SystemGuid.Category.HISTORY_PERSON.AsGuid(),
                personId.Value,
                historyChangeList,
                GetNameForHistory(originalModel?.FinancialPaymentDetail ?? FinancialPaymentDetail),
                typeof(FinancialPersonSavedAccount),
                Id,
                dbContext.GetCurrentPersonAlias()?.Id,
                dbContext.SourceOfChange);
        }
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            // confirmation was disabled by btnSave on client-side.  So if returning without a redirect,
            // it should be enabled.  If returning with a redirect, the control won't be updated to reflect
            // confirmation being enabled, so it's ok to enable it here
            confirmExit.Enabled = true;

            if ( Page.IsValid )
            {
                confirmExit.Enabled = true;

                RockTransactionScope.WrapTransaction( () =>
                {
                    var rockContext = new RockContext();
                    var familyService = new GroupService( rockContext );
                    var familyMemberService = new GroupMemberService( rockContext );
                    var personService = new PersonService( rockContext );
                    var historyService = new HistoryService( rockContext );

                    var familyChanges = new List<string>();

                    // SAVE FAMILY
                    _family = familyService.Get( _family.Id );

                    History.EvaluateChange( familyChanges, "Family Name", _family.Name, tbFamilyName.Text );
                    _family.Name = tbFamilyName.Text;

                    int? campusId = cpCampus.SelectedValueAsInt();
                    if ( _family.CampusId != campusId )
                    {
                        History.EvaluateChange( familyChanges, "Campus",
                            _family.CampusId.HasValue ? CampusCache.Read( _family.CampusId.Value ).Name : string.Empty,
                            campusId.HasValue ? CampusCache.Read( campusId.Value ).Name : string.Empty );
                        _family.CampusId = campusId;
                    }

                    var familyGroupTypeId = _family.GroupTypeId;

                    rockContext.SaveChanges();

                    // SAVE FAMILY MEMBERS
                    int? recordStatusValueID = ddlRecordStatus.SelectedValueAsInt();
                    int? reasonValueId = ddlReason.SelectedValueAsInt();
                    var newFamilies = new List<Group>();

                    foreach ( var familyMember in FamilyMembers )
                    {
                        var memberChanges = new List<string>();
                        var demographicChanges = new List<string>();

                        var role = familyRoles.Where( r => r.Guid.Equals( familyMember.RoleGuid ) ).FirstOrDefault();
                        if ( role == null )
                        {
                            role = familyRoles.FirstOrDefault();
                        }

                        bool isChild = role != null && role.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD ) );

                        // People added to family (new or from other family)
                        if ( !familyMember.ExistingFamilyMember )
                        {
                            var groupMember = new GroupMember();

                            if ( familyMember.Id == -1 )
                            {
                                // added new person
                                demographicChanges.Add( "Created" );

                                var person = new Person();
                                person.FirstName = familyMember.FirstName;
                                person.NickName = familyMember.NickName;
                                History.EvaluateChange( demographicChanges, "First Name", string.Empty, person.FirstName );

                                person.LastName = familyMember.LastName;
                                History.EvaluateChange( demographicChanges, "Last Name", string.Empty, person.LastName );

                                person.Gender = familyMember.Gender;
                                History.EvaluateChange( demographicChanges, "Gender", null, person.Gender );

                                person.BirthDate = familyMember.BirthDate;
                                History.EvaluateChange( demographicChanges, "Birth Date", null, person.BirthDate );

                                if ( !isChild )
                                {
                                    person.GivingGroupId = _family.Id;
                                    History.EvaluateChange( demographicChanges, "Giving Group", string.Empty, _family.Name );
                                }

                                person.EmailPreference = EmailPreference.EmailAllowed;

                                groupMember.Person = person;
                            }
                            else
                            {
                                // added from other family
                                groupMember.Person = personService.Get( familyMember.Id );
                            }

                            if ( recordStatusValueID > 0 )
                            {
                                History.EvaluateChange( demographicChanges, "Record Status", DefinedValueCache.GetName( groupMember.Person.RecordStatusValueId ), DefinedValueCache.GetName( recordStatusValueID ) );
                                groupMember.Person.RecordStatusValueId = recordStatusValueID;

                                History.EvaluateChange( demographicChanges, "Record Status Reason", DefinedValueCache.GetName( groupMember.Person.RecordStatusReasonValueId ), DefinedValueCache.GetName( reasonValueId ) );
                                groupMember.Person.RecordStatusReasonValueId = reasonValueId;
                            }

                            groupMember.GroupId = _family.Id;
                            if ( role != null )
                            {
                                History.EvaluateChange( memberChanges, "Role", string.Empty, role.Name );
                                groupMember.GroupRoleId = role.Id;
                            }

                            if ( groupMember.Person != null )
                            {
                                familyMemberService.Add( groupMember );
                                rockContext.SaveChanges();
                                familyMember.Id = groupMember.Person.Id;
                            }

                        }
                        else
                        {
                            // existing family members
                            var groupMember = familyMemberService.Queryable( "Person" ).Where( m =>
                                m.PersonId == familyMember.Id &&
                                m.Group.GroupTypeId == familyGroupTypeId &&
                                m.GroupId == _family.Id ).FirstOrDefault();

                            if ( groupMember != null )
                            {
                                if ( familyMember.Removed )
                                {
                                    var newFamilyChanges = new List<string>();

                                    // Family member was removed and should be created in their own new family
                                    var newFamily = new Group();
                                    newFamily.Name = familyMember.LastName + " Family";
                                    History.EvaluateChange( newFamilyChanges, "Family", string.Empty, newFamily.Name );

                                    newFamily.GroupTypeId = familyGroupTypeId;

                                    if ( _family.CampusId.HasValue )
                                    {
                                        History.EvaluateChange( newFamilyChanges, "Campus", string.Empty, CampusCache.Read( _family.CampusId.Value ).Name );
                                    }
                                    newFamily.CampusId = _family.CampusId;

                                    familyService.Add( newFamily );
                                    rockContext.SaveChanges();

                                    // If person's previous giving group was this family, set it to their new family id
                                    if ( groupMember.Person.GivingGroup != null && groupMember.Person.GivingGroupId == _family.Id )
                                    {
                                        History.EvaluateChange( demographicChanges, "Giving Group", groupMember.Person.GivingGroup.Name, _family.Name );
                                        groupMember.Person.GivingGroupId = newFamily.Id;
                                    }

                                    groupMember.Group = newFamily;
                                    rockContext.SaveChanges();

                                    var newMemberChanges = new List<string>();
                                    History.EvaluateChange( newMemberChanges, "Role", string.Empty, groupMember.GroupRole.Name );

                                    HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                        groupMember.Person.Id, newFamilyChanges, newFamily.Name, typeof( Group ), newFamily.Id );

                                    newFamilies.Add( newFamily );

                                    History.EvaluateChange( memberChanges, "Role", groupMember.GroupRole.Name, string.Empty );
                                }
                                else
                                {
                                    // Existing member was not remvoved
                                    if ( role != null )
                                    {
                                        History.EvaluateChange( memberChanges, "Role",
                                            groupMember.GroupRole != null ? groupMember.GroupRole.Name : string.Empty, role.Name );
                                        groupMember.GroupRoleId = role.Id;

                                        if ( recordStatusValueID > 0 )
                                        {
                                            History.EvaluateChange( demographicChanges, "Record Status", DefinedValueCache.GetName( groupMember.Person.RecordStatusValueId ), DefinedValueCache.GetName( recordStatusValueID ) );
                                            groupMember.Person.RecordStatusValueId = recordStatusValueID;

                                            History.EvaluateChange( demographicChanges, "Record Status Reason", DefinedValueCache.GetName( groupMember.Person.RecordStatusReasonValueId ), DefinedValueCache.GetName( reasonValueId ) );
                                            groupMember.Person.RecordStatusReasonValueId = reasonValueId;
                                        }

                                        rockContext.SaveChanges();
                                    }
                                }
                            }
                        }

                        // Remove anyone that was moved from another family
                        if ( familyMember.RemoveFromOtherFamilies )
                        {
                            var otherFamilies = familyMemberService.Queryable()
                                .Where( m =>
                                    m.PersonId == familyMember.Id &&
                                    m.Group.GroupTypeId == familyGroupTypeId &&
                                    m.GroupId != _family.Id )
                                .ToList();

                            foreach ( var otherFamilyMember in otherFamilies )
                            {
                                var fm = familyMemberService.Get( otherFamilyMember.Id );

                                // If the person's giving group id was the family they are being removed from, update it to this new family's id
                                if ( fm.Person.GivingGroupId == fm.GroupId )
                                {
                                    var person = personService.Get( fm.PersonId );

                                    History.EvaluateChange( demographicChanges, "Giving Group", person.GivingGroup.Name, _family.Name );
                                    person.GivingGroupId = _family.Id;

                                    rockContext.SaveChanges();
                                }

                                var oldMemberChanges = new List<string>();
                                History.EvaluateChange( oldMemberChanges, "Role", fm.GroupRole.Name, string.Empty );
                                History.EvaluateChange( oldMemberChanges, "Family", fm.Group.Name, string.Empty );
                                HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                    fm.Person.Id, oldMemberChanges, fm.Group.Name, typeof( Group ), fm.Group.Id );

                                familyMemberService.Delete( fm );
                                rockContext.SaveChanges();

                                var f = familyService.Queryable()
                                    .Where( g =>
                                        g.Id == otherFamilyMember.GroupId &&
                                        !g.Members.Any() )
                                    .FirstOrDefault();
                                if ( f != null )
                                {
                                    familyService.Delete( f );
                                    rockContext.SaveChanges();
                                }

                            }
                        }

                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(),
                            familyMember.Id, demographicChanges );

                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                            familyMember.Id, memberChanges, _family.Name, typeof( Group ), _family.Id );
                    }

                    // SAVE LOCATIONS
                    var groupLocationService = new GroupLocationService( rockContext );

                    // delete any group locations that were removed
                    var remainingLocationIds = FamilyAddresses.Where( a => a.Id > 0 ).Select( a => a.Id ).ToList();
                    foreach ( var removedLocation in groupLocationService.Queryable( "GroupLocationTypeValue,Location" )
                        .Where( l => l.GroupId == _family.Id &&
                            !remainingLocationIds.Contains( l.Id ) ) )
                    {
                        History.EvaluateChange( familyChanges, removedLocation.GroupLocationTypeValue.Name + " Location",
                            removedLocation.Location.ToString(), string.Empty );
                        groupLocationService.Delete( removedLocation );
                    }
                    rockContext.SaveChanges();

                    foreach ( var familyAddress in FamilyAddresses )
                    {
                        Location updatedAddress = null;
                        if ( familyAddress.LocationIsDirty )
                        {
                            updatedAddress = new LocationService( rockContext ).Get(
                                familyAddress.Street1, familyAddress.Street2, familyAddress.City,
                                familyAddress.State, familyAddress.Zip );
                        }

                        GroupLocation groupLocation = null;
                        if ( familyAddress.Id > 0 )
                        {
                            groupLocation = groupLocationService.Get( familyAddress.Id );
                        }
                        if ( groupLocation == null )
                        {
                            groupLocation = new GroupLocation();
                            groupLocation.GroupId = _family.Id;
                            groupLocationService.Add( groupLocation );
                        }

                        History.EvaluateChange( familyChanges, "Location Type",
                            groupLocation.GroupLocationTypeValueId.HasValue ? DefinedValueCache.Read( groupLocation.GroupLocationTypeValueId.Value ).Name : string.Empty,
                            familyAddress.LocationTypeName );
                        groupLocation.GroupLocationTypeValueId = familyAddress.LocationTypeId;

                        History.EvaluateChange( familyChanges, familyAddress.LocationTypeName + " Is Mailing",
                            groupLocation.IsMailingLocation.ToString(), familyAddress.IsMailing.ToString() );
                        groupLocation.IsMailingLocation = familyAddress.IsMailing;

                        History.EvaluateChange( familyChanges, familyAddress.LocationTypeName + " Is Map Location",
                            groupLocation.IsMappedLocation.ToString(), familyAddress.IsLocation.ToString() );
                        groupLocation.IsMappedLocation = familyAddress.IsLocation;

                        if ( updatedAddress != null )
                        {
                            History.EvaluateChange( familyChanges, familyAddress.LocationTypeName + " Location",
                                groupLocation.Location != null ? groupLocation.Location.ToString() : "", updatedAddress.ToString() );
                            groupLocation.Location = updatedAddress;
                        }

                        rockContext.SaveChanges();

                        // Add the same locations to any new families created by removing an existing family member
                        if ( newFamilies.Any() )
                        {
                            //reload grouplocation for access to child properties
                            groupLocation = groupLocationService.Get( groupLocation.Id );
                            foreach ( var newFamily in newFamilies )
                            {
                                var newFamilyLocation = new GroupLocation();
                                newFamilyLocation.GroupId = newFamily.Id;
                                newFamilyLocation.LocationId = groupLocation.LocationId;
                                newFamilyLocation.GroupLocationTypeValueId = groupLocation.GroupLocationTypeValueId;
                                newFamilyLocation.IsMailingLocation = groupLocation.IsMailingLocation;
                                newFamilyLocation.IsMappedLocation = groupLocation.IsMappedLocation;
                                groupLocationService.Add( newFamilyLocation );
                            }

                            rockContext.SaveChanges();
                        }
                    }

                    foreach ( var fm in _family.Members )
                    {
                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                            fm.PersonId, familyChanges, _family.Name, typeof( Group ), _family.Id );
                    }

                    _family = familyService.Get( _family.Id );
                    if ( _family.Members.Any( m => m.PersonId == Person.Id ) )
                    {
                        Response.Redirect( string.Format( "~/Person/{0}", Person.Id ), false );
                    }
                    else
                    {
                        var fm = _family.Members
                            .Where( m =>
                                m.GroupRole.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ) &&
                                m.Person.Gender == Gender.Male )
                            .OrderByDescending( m => m.Person.Age )
                            .FirstOrDefault();
                        if ( fm == null )
                        {
                            fm = _family.Members
                                .Where( m =>
                                    m.GroupRole.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ) )
                                .OrderByDescending( m => m.Person.Age )
                                .FirstOrDefault();
                        }
                        if ( fm == null )
                        {
                            fm = _family.Members
                                .OrderByDescending( m => m.Person.Age )
                                .FirstOrDefault();
                        }
                        if ( fm != null )
                        {
                            Response.Redirect( string.Format( "~/Person/{0}", fm.PersonId ), false );
                        }
                        else
                        {
                            Response.Redirect( "~", false );
                        }
                    }

                } );
            }
        }
        /// <summary>
        /// Updates the last login.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        public static void UpdateLastLogin( string userName )
        {
            using ( var rockContext = new RockContext() )
            {
                var userLoginService = new UserLoginService( rockContext );
                var historyService = new HistoryService( rockContext );

                var personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id;
                var activityCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), rockContext ).Id;

                if ( !string.IsNullOrWhiteSpace( userName ) && !userName.StartsWith( "rckipid=" ) )
                {
                    var userLogin = userLoginService.GetByUserName( userName );
                    if ( userLogin != null )
                    {
                        userLogin.LastLoginDateTime = RockDateTime.Now;

                        if ( userLogin.PersonId.HasValue )
                        {
                            var summary = new System.Text.StringBuilder();
                            summary.AppendFormat( "User logged in with <span class='field-name'>{0}</span> username", userLogin.UserName );
                            if ( HttpContext.Current != null && HttpContext.Current.Request != null )
                            {
                                summary.AppendFormat( ", to <span class='field-value'>{0}</span>, from <span class='field-value'>{1}</span>",
                                    HttpContext.Current.Request.Url.AbsoluteUri, HttpContext.Current.Request.UserHostAddress );
                            }
                            summary.Append( "." );

                            historyService.Add( new History
                            {
                                EntityTypeId = personEntityTypeId,
                                CategoryId = activityCategoryId,
                                EntityId = userLogin.PersonId.Value,
                                Summary = summary.ToString()
                            } );
                        }
                        rockContext.SaveChanges();
                    }
                }
            }
        }
Exemple #17
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 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;

                    using ( 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
                                {
                                    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( globalConfigValues );

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

                                        // 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 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 );

                                        // 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 );
                                        }

                                        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 = "Exception: " + ex.Message;
                                    }
                                }

                                rockContext.SaveChanges();
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
Exemple #18
0
        /// <summary>
        /// Method that will be called on an entity immediately before the item is saved by context.  Takes
        /// care of logging any particular change history for user login.
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="entry"></param>
        public override void PreSaveChanges(Rock.Data.DbContext dbContext, DbEntityEntry entry)
        {
            var rockContext = ( RockContext )dbContext;

            HistoryChanges = new History.HistoryChangeList();

            switch (entry.State)
            {
            case EntityState.Added:
            {
                // Get the authentication provider entity type
                var entityType = EntityTypeCache.Get(this.EntityTypeId ?? 0);
                var change     = HistoryChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Authentication Provider").SetNewValue(entityType?.FriendlyName);

                // Don't log Pin Authentication user names.
                var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false;

                if (isUserNameSensitive)
                {
                    change.SetCaption("User Account");
                }

                History.EvaluateChange(HistoryChanges, "User Login", string.Empty, UserName, isUserNameSensitive);
                History.EvaluateChange(HistoryChanges, "Is Confirmed", null, IsConfirmed);
                History.EvaluateChange(HistoryChanges, "Is Password Change Required", null, IsPasswordChangeRequired);
                History.EvaluateChange(HistoryChanges, "Is Locked Out", null, IsLockedOut);

                break;
            }

            case EntityState.Modified:
            {
                var entityType = EntityTypeCache.Get(this.EntityTypeId ?? 0);

                // Don't log Pin Authentication user names.
                var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false;

                History.EvaluateChange(HistoryChanges, "User Login", entry.OriginalValues["UserName"].ToStringSafe(), UserName, isUserNameSensitive);
                History.EvaluateChange(HistoryChanges, "Is Confirmed", entry.OriginalValues["IsConfirmed"].ToStringSafe().AsBooleanOrNull(), IsConfirmed);
                History.EvaluateChange(HistoryChanges, "Is Password Change Required", entry.OriginalValues["IsPasswordChangeRequired"].ToStringSafe().AsBooleanOrNull(), IsPasswordChangeRequired);
                History.EvaluateChange(HistoryChanges, "Is Locked Out", entry.OriginalValues["IsLockedOut"].ToStringSafe().AsBooleanOrNull(), IsLockedOut);
                History.EvaluateChange(HistoryChanges, "Password", entry.OriginalValues["Password"].ToStringSafe(), Password, true);

                // Did the provider type change?
                int?origEntityTypeId = entry.OriginalValues["EntityTypeId"].ToStringSafe().AsIntegerOrNull();
                int?entityTypeId     = EntityType != null ? EntityType.Id : EntityTypeId;
                if (!entityTypeId.Equals(origEntityTypeId))
                {
                    var origProviderType = EntityTypeCache.Get(origEntityTypeId ?? 0)?.FriendlyName;
                    var providerType     = EntityTypeCache.Get(this.EntityTypeId ?? 0)?.FriendlyName;
                    History.EvaluateChange(HistoryChanges, "User Login", origProviderType, providerType);
                }

                // Change the caption if this is a sensitive user account
                if (HistoryChanges.Count > 0 && isUserNameSensitive)
                {
                    var change = HistoryChanges.FirstOrDefault();
                    change.SetCaption("User Account");
                }

                break;
            }

            case EntityState.Deleted:
            {
                // By this point EF has stripped out some of the data we need to save history
                // Reload the data using a new context.
                RockContext newRockContext = new RockContext();
                var         userLogin      = new UserLoginService(newRockContext).Get(this.Id);
                if (userLogin != null && userLogin.PersonId != null)
                {
                    try
                    {
                        var entityType          = EntityTypeCache.Get(userLogin.EntityTypeId ?? 0);
                        var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false;

                        if (!isUserNameSensitive)
                        {
                            HistoryChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "User Login").SetOldValue(userLogin.UserName);
                            HistoryService.SaveChanges(newRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), userLogin.PersonId.Value, HistoryChanges, UserName, typeof(UserLogin), this.Id, true, userLogin.ModifiedByPersonAliasId, null);
                        }
                        else
                        {
                            HistoryChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Authentication Provider").SetOldValue(entityType?.FriendlyName).SetCaption("User Account");
                            HistoryService.SaveChanges(newRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), userLogin.PersonId.Value, HistoryChanges, entityType?.FriendlyName, typeof(UserLogin), this.Id, true, userLogin.ModifiedByPersonAliasId, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        // Just log the problem and move on...
                        ExceptionLogService.LogException(ex);
                    }
                }

                HistoryChanges.Clear();
                return;
            }
            }

            base.PreSaveChanges(dbContext, entry);
        }