/// <summary>
 /// Updates any Cache Objects that are associated with this entity
 /// </summary>
 /// <param name="entityState">State of the entity.</param>
 /// <param name="dbContext">The database context.</param>
 public void UpdateCache( EntityState entityState, Data.DbContext dbContext )
 {
     var currentPersonAliasId = dbContext.GetCurrentPersonAlias()?.Id;
     if ( this.PersonAliasId == currentPersonAliasId )
     {
         // If the current person is the one modifying this (it probably is), update the Session
         // Data so that the PersonalLinks block knows to update the localStorage of PersonalLinks.
         // Note the PersonalLinkSectionOrder is not shared, so we don't need to update SharedPersonalLinkSectionCache.
         PersonalLinkService.PersonalLinksHelper.FlushPersonalLinksSessionDataLastModifiedDateTime();
     }
 }
Esempio n. 2
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)
        {
            // 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);
        }
Esempio n. 3
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)
        {
            /*
             * 12/18/2019 BJW
             *
             * We want to log the history of attribute values within a person matrix. Most of this logging occurs from
             * the attribute value model. However, when a matrix item (row in the table) is deleted, the pre-save event
             * of the attribute values is not called. Therefore, the delete event needs to be logged here. Additionally,
             * when the matrix item is added, the history is much cleaner when added here so that all the values of the
             * row are consolidated to one history item.  Modified state is not possible to log here because the
             * matrix item is not actually modified when its attributes change.
             *
             * Task: https://app.asana.com/0/1120115219297347/1136643182208595/f
             */

            if (state != EntityState.Deleted && state != EntityState.Added)
            {
                return;
            }

            var rockContext = new RockContext();
            var matrixId    = AttributeMatrixId != default ?
                              AttributeMatrixId :
                              entry.OriginalValues["AttributeMatrixId"].ToStringSafe().AsIntegerOrNull();

            var matrix = AttributeMatrix;

            if (matrix == null && matrixId.HasValue)
            {
                var matrixService = new AttributeMatrixService(rockContext);
                matrix = matrixService.Queryable().AsNoTracking().FirstOrDefault(am => am.Id == matrixId);
            }

            if (matrix == null)
            {
                return;
            }

            // The root attribute matrix attribute value is linked to the matrix by the guid as the attribute value
            var matrixGuidString      = matrix.Guid.ToString();
            var personEntityTypeId    = EntityTypeCache.Get(typeof(Person)).Id;
            var attributeValueService = new AttributeValueService(rockContext);
            var rootAttributeValue    = attributeValueService.Queryable().AsNoTracking().FirstOrDefault(av =>
                                                                                                        av.Value.Equals(matrixGuidString, System.StringComparison.OrdinalIgnoreCase) &&
                                                                                                        av.Attribute.EntityTypeId == personEntityTypeId
                                                                                                        );

            if (rootAttributeValue?.EntityId == null)
            {
                return;
            }

            var rootAttributeCache = AttributeCache.Get(rootAttributeValue.AttributeId);

            if (rootAttributeCache == null)
            {
                return;
            }

            // Evaluate the history changes
            var historyChangeList = new History.HistoryChangeList();

            if (AttributeValues == null || !AttributeValues.Any())
            {
                this.LoadAttributes();
            }

            var isDelete = state == EntityState.Deleted;

            foreach (var attributeValue in AttributeValues.Values)
            {
                var attributeCache    = AttributeCache.Get(attributeValue.AttributeId);
                var formattedOldValue = isDelete ? GetHistoryFormattedValue(attributeValue.Value, attributeCache) : string.Empty;
                var formattedNewValue = isDelete ? string.Empty : GetHistoryFormattedValue(attributeValue.Value, attributeCache);
                History.EvaluateChange(historyChangeList, attributeCache.Name, formattedOldValue, formattedNewValue, attributeCache.FieldType.Field.IsSensitive());
            }

            if (!historyChangeList.Any())
            {
                historyChangeList.AddChange(
                    isDelete ? History.HistoryVerb.Delete : History.HistoryVerb.Add,
                    History.HistoryChangeType.Record,
                    $"{rootAttributeCache.Name} Item");
            }

            HistoryItems = HistoryService.GetChanges(
                typeof(Person),
                SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(),
                rootAttributeValue.EntityId.Value,
                historyChangeList,
                rootAttributeCache.Name,
                typeof(Attribute),
                rootAttributeCache.Id,
                dbContext.GetCurrentPersonAlias()?.Id,
                dbContext.SourceOfChange);
        }
Esempio n. 4
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)
        {
            // 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 PersonSearchKeyService(rockContext);
            var originalModel = service.Queryable("PersonAlias")
                                .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;

            case EntityState.Modified:
                verb = History.HistoryVerb.Modify;
                break;

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

            var caption = verb == History.HistoryVerb.Modify ?
                          "Person Search Key" :
                          GetCaptionForHistory(originalModel?.SearchValue ?? SearchValue, originalModel?.SearchTypeValueId ?? SearchTypeValueId);

            var historyChangeList = new History.HistoryChangeList();

            if (verb != History.HistoryVerb.Modify)
            {
                historyChangeList.AddChange(verb, History.HistoryChangeType.Record, "Person Search Key");
            }
            else
            {
                History.EvaluateChange(historyChangeList, $"SearchValue", entry.OriginalValues["SearchValue"].ToStringSafe(), SearchValue, false);

                var originalSearchType = DefinedValueCache.Get(entry.OriginalValues["SearchTypeValueId"].ToStringSafe().AsInteger());
                var currentSearchType  = DefinedValueCache.Get(SearchTypeValueId);
                History.EvaluateChange(historyChangeList, $"SearchType", originalSearchType?.Value, currentSearchType?.Value, false);
            }

            HistoryItems = HistoryService.GetChanges(
                typeof(Person),
                Rock.SystemGuid.Category.HISTORY_PERSON.AsGuid(),
                personId.Value,
                historyChangeList,
                caption,
                typeof(PersonSearchKey),
                Id,
                dbContext.GetCurrentPersonAlias()?.Id,
                dbContext.SourceOfChange);
        }
Esempio n. 5
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);
        }