public static LogException ( |
||
ex | A |
|
context | The |
|
pageId | int | A |
siteId | int | A |
personAlias | PersonAlias | The person alias. |
Résultat | void |
/// <summary> /// Gets the Linq expression for the DataViewFilter. /// </summary> /// <param name="filteredEntityType">The object type of the filtered entity.</param> /// <param name="serviceInstance">A <see cref="System.Object"/> that contains the service reference.</param> /// <param name="parameter">A <see cref="System.Linq.Expressions.ParameterExpression"/> containing the parameter for the expression.</param> /// <param name="errorMessages">A <see cref="System.Collections.Generic.List{String}"/> that contains any error/exception messages that are returned.</param> /// <returns></returns> public virtual Expression GetExpression(Type filteredEntityType, IService serviceInstance, ParameterExpression parameter, List <string> errorMessages) { switch (ExpressionType) { case FilterExpressionType.Filter: if (this.EntityTypeId.HasValue) { var entityType = Rock.Web.Cache.EntityTypeCache.Read(this.EntityTypeId.Value); if (entityType != null) { var component = Rock.Reporting.DataFilterContainer.GetComponent(entityType.Name); if (component != null) { try { return(component.GetExpression(filteredEntityType, serviceInstance, parameter, this.Selection)); } catch (SystemException ex) { ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); errorMessages.Add(string.Format("{0}: {1}", component.FormatSelection(filteredEntityType, this.Selection), ex.Message)); } } } } return(null); case FilterExpressionType.GroupAll: case FilterExpressionType.GroupAnyFalse: Expression andExp = null; foreach (var filter in this.ChildFilters) { Expression exp = filter.GetExpression(filteredEntityType, serviceInstance, parameter, errorMessages); if (exp != null) { if (andExp == null) { andExp = exp; } else { andExp = Expression.AndAlso(andExp, exp); } } } if (ExpressionType == FilterExpressionType.GroupAnyFalse && andExp != null) { // If only one of the conditions must be false, invert the expression so that it becomes the logical equivalent of "NOT ALL". andExp = Expression.Not(andExp); } return(andExp); case FilterExpressionType.GroupAny: case FilterExpressionType.GroupAllFalse: Expression orExp = null; foreach (var filter in this.ChildFilters) { Expression exp = filter.GetExpression(filteredEntityType, serviceInstance, parameter, errorMessages); if (exp != null) { if (orExp == null) { orExp = exp; } else { orExp = Expression.OrElse(orExp, exp); } } } if (ExpressionType == FilterExpressionType.GroupAllFalse && orExp != null) { // If all of the conditions must be false, invert the expression so that it becomes the logical equivalent of "NOT ANY". orExp = Expression.Not(orExp); } return(orExp); } return(null); }
/// <summary> /// Called before the save operation is executed. /// </summary> protected override void PreSave() { var rockContext = ( RockContext )this.RockContext; string errorMessage; if (State != EntityContextState.Deleted && Entity.IsArchived == false && Entity.GroupMemberStatus != GroupMemberStatus.Inactive) { if (!Entity.ValidateGroupMembership(rockContext, out errorMessage)) { var ex = new GroupMemberValidationException(errorMessage); ExceptionLogService.LogException(ex); throw ex; } } int?oldPersonId = null; int?newPersonId = null; int?oldGroupId = null; int?newGroupId = null; switch (State) { case EntityContextState.Added: { oldPersonId = null; newPersonId = Entity.PersonId; oldGroupId = null; newGroupId = Entity.GroupId; if (!Entity.DateTimeAdded.HasValue) { Entity.DateTimeAdded = RockDateTime.Now; } // if this is a new record, but is saved with IsActive=False, set the InactiveDateTime if it isn't set already if (Entity.GroupMemberStatus == GroupMemberStatus.Inactive) { Entity.InactiveDateTime = Entity.InactiveDateTime ?? RockDateTime.Now; } break; } case EntityContextState.Modified: { oldPersonId = OriginalValues[nameof(GroupMember.PersonId)].ToStringSafe().AsIntegerOrNull(); newPersonId = Entity.PersonId; oldGroupId = OriginalValues[nameof(GroupMember.GroupId)].ToStringSafe().AsIntegerOrNull(); newGroupId = Entity.GroupId; var originalStatus = OriginalValues[nameof(GroupMember.GroupMemberStatus)].ToStringSafe().ConvertToEnum <GroupMemberStatus>(); // IsActive was modified, set the InactiveDateTime if it changed to Inactive, or set it to NULL if it changed to Active if (originalStatus != Entity.GroupMemberStatus) { if (Entity.GroupMemberStatus == GroupMemberStatus.Inactive) { // if the caller didn't already set InactiveDateTime, set it to now Entity.InactiveDateTime = Entity.InactiveDateTime ?? RockDateTime.Now; } else { Entity.InactiveDateTime = null; } } break; } case EntityContextState.Deleted: { oldPersonId = Entity.PersonId; newPersonId = null; oldGroupId = Entity.GroupId; newGroupId = null; break; } } Group group = Entity.Group; if (group == null) { group = new GroupService(rockContext).Get(Entity.GroupId); } if (group != null) { string oldGroupName = group.Name; if (oldGroupId.HasValue && oldGroupId.Value != group.Id) { var oldGroup = new GroupService(rockContext).Get(oldGroupId.Value); if (oldGroup != null) { oldGroupName = oldGroup.Name; } } HistoryChanges = new List <HistoryItem>(); if (newPersonId.HasValue) { HistoryChanges.Add(new HistoryItem() { PersonId = newPersonId.Value, Caption = group.Name, GroupId = group.Id, Group = group }); } if (oldPersonId.HasValue) { HistoryChanges.Add(new HistoryItem() { PersonId = oldPersonId.Value, Caption = oldGroupName, GroupId = oldGroupId }); } if (newPersonId.HasValue && newGroupId.HasValue && (!oldPersonId.HasValue || oldPersonId.Value != newPersonId.Value || !oldGroupId.HasValue || oldGroupId.Value != newGroupId.Value)) { // New Person in group var historyItem = HistoryChanges.First(h => h.PersonId == newPersonId.Value && h.GroupId == newGroupId.Value); historyItem.PersonHistoryChangeList.AddChange(History.HistoryVerb.AddedToGroup, History.HistoryChangeType.Record, $"'{group.Name}' Group"); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Role", ( int? )null, Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Note", string.Empty, Entity.Note); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Status", null, Entity.GroupMemberStatus); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Communication Preference", null, Entity.CommunicationPreference); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Guest Count", ( int? )null, Entity.GuestCount); var addedMemberPerson = Entity.Person ?? new PersonService(rockContext).Get(Entity.PersonId); // add the Person's Name as ValueName and Caption (just in case the groupmember record is deleted later) historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.AddedToGroup, History.HistoryChangeType.Record, $"{addedMemberPerson?.FullName}").SetCaption($"{addedMemberPerson?.FullName}"); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Role", ( int? )null, Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Note", string.Empty, Entity.Note); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Status", null, Entity.GroupMemberStatus); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Communication Preference", null, Entity.CommunicationPreference); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Guest Count", ( int? )null, Entity.GuestCount); } if (newPersonId.HasValue && oldPersonId.HasValue && oldPersonId.Value == newPersonId.Value && newGroupId.HasValue && oldGroupId.HasValue && oldGroupId.Value == newGroupId.Value) { // Updated same person in group var historyItem = HistoryChanges.First(h => h.PersonId == newPersonId.Value && h.GroupId == newGroupId.Value); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Role", OriginalValues["GroupRoleId"].ToStringSafe().AsIntegerOrNull(), Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Note", OriginalValues["Note"].ToStringSafe(), Entity.Note); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Status", OriginalValues["GroupMemberStatus"].ToStringSafe().ConvertToEnum <GroupMemberStatus>(), Entity.GroupMemberStatus); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Communication Preference", OriginalValues["CommunicationPreference"].ToStringSafe().ConvertToEnum <CommunicationType>(), Entity.CommunicationPreference); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Guest Count", OriginalValues["GuestCount"].ToStringSafe().AsIntegerOrNull(), Entity.GuestCount); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Archived", OriginalValues["IsArchived"].ToStringSafe().AsBoolean(), Entity.IsArchived); // If the groupmember was Archived, make sure it is the first GroupMember History change (since they get summarized when doing a HistoryLog and Timeline bool origIsArchived = OriginalValues[nameof(GroupMember.IsArchived)].ToStringSafe().AsBoolean(); if (origIsArchived != Entity.IsArchived) { var memberPerson = Entity.Person ?? new PersonService(rockContext).Get(Entity.PersonId); if (Entity.IsArchived == true) { // GroupMember changed to Archived historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.RemovedFromGroup, History.HistoryChangeType.Record, $"{memberPerson?.FullName}").SetCaption($"{memberPerson?.FullName}"); } else { // GroupMember changed to Not archived historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.AddedToGroup, History.HistoryChangeType.Record, $"{memberPerson?.FullName}").SetCaption($"{memberPerson?.FullName}"); } } History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Role", OriginalValues[nameof(GroupMember.GroupRoleId)].ToStringSafe().AsIntegerOrNull(), Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Note", OriginalValues[nameof(GroupMember.Note)].ToStringSafe(), Entity.Note); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Status", OriginalValues[nameof(GroupMember.GroupMemberStatus)].ToStringSafe().ConvertToEnum <GroupMemberStatus>(), Entity.GroupMemberStatus); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Communication Preference", OriginalValues[nameof(GroupMember.CommunicationPreference)].ToStringSafe().ConvertToEnum <CommunicationType>(), Entity.CommunicationPreference); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Guest Count", OriginalValues[nameof(GroupMember.GuestCount)].ToStringSafe().AsIntegerOrNull(), Entity.GuestCount); } if (oldPersonId.HasValue && oldGroupId.HasValue && (!newPersonId.HasValue || newPersonId.Value != oldPersonId.Value || !newGroupId.HasValue || newGroupId.Value != oldGroupId.Value)) { // Removed a person/groupmember in group var historyItem = HistoryChanges.First(h => h.PersonId == oldPersonId.Value && h.GroupId == oldGroupId.Value); historyItem.PersonHistoryChangeList.AddChange(History.HistoryVerb.RemovedFromGroup, History.HistoryChangeType.Record, $"{oldGroupName} Group"); var deletedMemberPerson = Entity.Person ?? new PersonService(rockContext).Get(Entity.PersonId); historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.RemovedFromGroup, History.HistoryChangeType.Record, $"{deletedMemberPerson?.FullName}").SetCaption($"{deletedMemberPerson?.FullName}"); } // process universal search indexing if required var groupType = GroupTypeCache.Get(group.GroupTypeId); if (groupType != null && groupType.IsIndexEnabled) { var processEntityTypeIndexMsg = new ProcessEntityTypeIndex.Message { EntityTypeId = groupType.Id, EntityId = group.Id }; processEntityTypeIndexMsg.Send(); } } _preSaveChangesOldGroupId = oldGroupId; base.PreSave(); }
/// <summary> /// Ensures that each Metric that has EnableAnalytics has a SQL View for it, and also deletes any AnalyticsFactMetric** views that no longer have metric (based on Metric.Name) /// </summary> public void EnsureMetricAnalyticsViews() { string analyticMetricViewsPrefix = "AnalyticsFactMetric"; string getAnalyticMetricViewsSQL = string.Format( @"SELECT OBJECT_NAME(sm.object_id) [view_name] ,sm.DEFINITION [view_definition] FROM sys.sql_modules AS sm JOIN sys.objects AS o ON sm.object_id = o.object_id WHERE o.type = 'V' AND OBJECT_NAME(sm.object_id) LIKE '{0}%'", analyticMetricViewsPrefix); var dataTable = DbService.GetDataTable(getAnalyticMetricViewsSQL, System.Data.CommandType.Text, null); var databaseAnalyticMetricViews = dataTable.Rows.OfType <DataRow>() .Select(row => new { ViewName = row["view_name"] as string, ViewDefinition = row["view_definition"] as string }).ToList(); var metricsWithAnalyticsEnabled = this.Queryable().Where(a => a.EnableAnalytics).Include(a => a.MetricPartitions).AsNoTracking().ToList(); var metricViewNames = metricsWithAnalyticsEnabled.Select(a => $"{analyticMetricViewsPrefix}{a.Title.RemoveSpecialCharacters()}").ToList(); var orphanedDatabaseViews = databaseAnalyticMetricViews.Where(a => !metricViewNames.Contains(a.ViewName)).ToList(); // DROP any Metric Analytic Views that are orphaned. In other words, there are views named 'AnalyticsFactMetric***' that don't have a metric. // This could happen if Metric.EnableAnalytics changed from True to False, Metric Title changed, or if a Metric was deleted. foreach (var orphanedView in orphanedDatabaseViews) { this.Context.Database.ExecuteSqlCommand($"DROP VIEW [{orphanedView.ViewName}]"); } // Make sure that each Metric with EnableAnalytics=True has a SQL View and that the View Definition is correct foreach (var metric in metricsWithAnalyticsEnabled) { string metricViewName = $"{analyticMetricViewsPrefix}{metric.Title.RemoveSpecialCharacters()}"; var metricEntityPartitions = metric.MetricPartitions.Where(a => a.EntityTypeId.HasValue).OrderBy(a => a.Order).ThenBy(a => a.Label).Select(a => new { a.Label, a.EntityTypeId }); var viewPartitionSELECTClauses = metricEntityPartitions.Select(a => $" ,pvt.[{a.EntityTypeId}] as [{a.Label}Id]").ToList().AsDelimited("\n"); List <string> partitionEntityLookupSELECTs = new List <string>(); List <string> partitionEntityLookupJOINs = new List <string>(); foreach (var metricPartition in metricEntityPartitions) { var metricPartitionEntityType = EntityTypeCache.Get(metricPartition.EntityTypeId.Value); if (metricPartitionEntityType != null) { var tableAttribute = metricPartitionEntityType.GetEntityType().GetCustomAttribute <TableAttribute>(); if (tableAttribute != null) { if (metricPartitionEntityType.Id == EntityTypeCache.GetId <DefinedValue>()) { partitionEntityLookupSELECTs.Add($"j{metricPartition.EntityTypeId}.Value [{metricPartition.Label.RemoveSpecialCharacters()}Name]"); } else if (metricPartitionEntityType.GetEntityType().GetProperty("Name") != null) { partitionEntityLookupSELECTs.Add($"j{metricPartition.EntityTypeId}.Name [{metricPartition.Label.RemoveSpecialCharacters()}Name]"); } partitionEntityLookupJOINs.Add($"LEFT JOIN [{tableAttribute.Name}] j{metricPartition.EntityTypeId} ON p.{metricPartition.Label.RemoveSpecialCharacters()}Id = j{metricPartition.EntityTypeId}.Id"); } } } var viewPIVOTInClauses = metricEntityPartitions.Select(a => $" [{a.EntityTypeId}]").ToList().AsDelimited(",\n"); if (string.IsNullOrEmpty(viewPIVOTInClauses)) { // This metric only has the default partition, and with no EntityTypeId, so put in a dummy Pivot Clause viewPIVOTInClauses = "[0]"; } var viewJoinsSELECT = partitionEntityLookupSELECTs.Select(a => $" ,{a}").ToList().AsDelimited("\n"); var viewJoinsFROM = partitionEntityLookupJOINs.AsDelimited("\n"); var viewDefinition = $@" /* <auto-generated> This view was generated by the Rock's MetricService.EnsureMetricAnalyticsViews() which gets called when a Metric is saved. Changes to this view definition will be lost when the view is regenerated. NOTE: Any Views with the prefix '{analyticMetricViewsPrefix}' are assumed to be Code Generated and may be deleted if there isn't a Metric associated with it </auto-generated> <doc> <summary> This VIEW helps present the data for the {metric.Title} metric. </summary> </doc> */ CREATE VIEW [{metricViewName}] AS SELECT p.* {viewJoinsSELECT} FROM ( SELECT pvt.Id ,cast(pvt.MetricValueDateTime AS DATE) AS [MetricValueDateTime] ,pvt.YValue {viewPartitionSELECTClauses} FROM ( SELECT mv.Id ,mv.YValue ,mv.MetricValueDateTime ,mvp.EntityId ,mp.EntityTypeId FROM MetricValue mv JOIN MetricValuePartition mvp ON mvp.MetricValueId = mv.Id JOIN MetricPartition mp ON mvp.MetricPartitionId = mp.Id WHERE mv.MetricId = {metric.Id} ) src pivot(min(EntityId) FOR EntityTypeId IN ({viewPIVOTInClauses})) pvt ) p {viewJoinsFROM} "; var databaseViewDefinition = databaseAnalyticMetricViews.Where(a => a.ViewName == metricViewName).FirstOrDefault(); try { if (databaseViewDefinition != null) { if (databaseViewDefinition.ViewDefinition != viewDefinition) { // view already exists, but something has changed, so drop and recreate it this.Context.Database.ExecuteSqlCommand($"DROP VIEW [{metricViewName}]"); this.Context.Database.ExecuteSqlCommand(viewDefinition); } } else { this.Context.Database.ExecuteSqlCommand(viewDefinition); } } catch (Exception ex) { // silently log the exception ExceptionLogService.LogException(new Exception("Error creating Analytics view for " + metric.Title, ex), System.Web.HttpContext.Current); } } }
/// <summary> /// Returns a list of each person and their GroupRequiremnt status for this group requirement /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="personQry">The person qry.</param> /// <param name="groupId">The group identifier.</param> /// <param name="groupRoleId">The group role identifier.</param> /// <returns></returns> /// <exception cref="System.Exception">No dataview assigned to Group Requirement Type: " + this.GroupRequirementType.Name</exception> public IEnumerable <PersonGroupRequirementStatus> PersonQueryableMeetsGroupRequirement(RockContext rockContext, IQueryable <Person> personQry, int groupId, int?groupRoleId) { if ((this.GroupRoleId != null) && (groupRoleId != null) && (this.GroupRoleId != groupRoleId)) { // if this GroupRequirement is for a specific role, the groupRole we are checking for is something different var result = personQry.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.Id, GroupRequirement = this, MeetsGroupRequirement = MeetsGroupRequirement.NotApplicable }); return(result); } if (this.GroupRequirementType.RequirementCheckType == RequirementCheckType.Dataview) { if (this.GroupRequirementType.DataViewId.HasValue) { var errorMessages = new List <string>(); var personService = new PersonService(rockContext); var paramExpression = personService.ParameterExpression; var dataViewWhereExpression = this.GroupRequirementType.DataView.GetExpression(personService, paramExpression, out errorMessages); var dataViewQry = personService.Get(paramExpression, dataViewWhereExpression); IQueryable <Person> warningDataViewQry = null; if (this.GroupRequirementType.WarningDataViewId.HasValue) { var warningDataViewWhereExpression = this.GroupRequirementType.WarningDataView.GetExpression(personService, paramExpression, out errorMessages); warningDataViewQry = personService.Get(paramExpression, warningDataViewWhereExpression); } if (dataViewQry != null) { var personWithRequirements = from p in personQry join d in dataViewQry on p equals d into oj from d in oj.DefaultIfEmpty() select new { PersonId = p.Id, Included = d != null, WarningIncluded = false }; // if a Warning Database was specified, set the WarningIncluded flag to true if they are included in the Warning Dataview if (warningDataViewQry != null) { personWithRequirements = personWithRequirements.Select(a => new { a.PersonId, a.Included, WarningIncluded = warningDataViewQry.Any(w => w.Id == a.PersonId) }); } var result = personWithRequirements.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.PersonId, GroupRequirement = this, MeetsGroupRequirement = a.Included ? (a.WarningIncluded ? MeetsGroupRequirement.MeetsWithWarning : MeetsGroupRequirement.Meets) : MeetsGroupRequirement.NotMet }); return(result); } } else { throw new Exception("No dataview assigned to Group Requirement Type: " + this.GroupRequirementType.Name); } } else if (this.GroupRequirementType.RequirementCheckType == RequirementCheckType.Sql) { // if requirement set on GroupType, this.Group is null var targetGroup = this.Group ?? new GroupService(rockContext).Get(groupId); string formattedSql = this.GroupRequirementType.SqlExpression.ResolveMergeFields(this.GroupRequirementType.GetMergeObjects(targetGroup)); string warningFormattedSql = this.GroupRequirementType.WarningSqlExpression.ResolveMergeFields(this.GroupRequirementType.GetMergeObjects(targetGroup)); try { var tableResult = DbService.GetDataTable(formattedSql, System.Data.CommandType.Text, null); if (tableResult.Columns.Count > 0) { IEnumerable <int> personIds = tableResult.Rows.OfType <System.Data.DataRow>().Select(r => Convert.ToInt32(r[0])); IEnumerable <int> warningPersonIds = null; // if a Warning SQL was specified, get a list of PersonIds that should have a warning with their status if (!string.IsNullOrWhiteSpace(warningFormattedSql)) { var warningTableResult = DbService.GetDataTable(warningFormattedSql, System.Data.CommandType.Text, null); if (warningTableResult.Columns.Count > 0) { warningPersonIds = warningTableResult.Rows.OfType <System.Data.DataRow>().Select(r => Convert.ToInt32(r[0])); } } var result = personQry.Select(a => a.Id).ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = personIds.Contains(a) ? ((warningPersonIds != null && warningPersonIds.Contains(a)) ? MeetsGroupRequirement.MeetsWithWarning : MeetsGroupRequirement.Meets ) : MeetsGroupRequirement.NotMet, }); return(result); } } catch (Exception ex) { // Exception occurred (probably due to bad SQL) ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); var result = personQry.Select(a => a.Id).ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = MeetsGroupRequirement.Error }); return(result); } } else { // manual var groupMemberRequirementQry = new GroupMemberRequirementService(rockContext).Queryable().Where(a => a.GroupMember.GroupId == groupId && a.GroupRequirementId == this.Id && a.RequirementMetDateTime.HasValue); var result = personQry.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.Id, GroupRequirement = this, MeetsGroupRequirement = groupMemberRequirementQry.Any(r => r.GroupMember.PersonId == a.Id) ? MeetsGroupRequirement.Meets : MeetsGroupRequirement.NotMet }); return(result); } // shouldn't happen return(null); }
/// <summary> /// Called after the save operation has been executed /// </summary> /// <remarks> /// This method is only called if <see cref="M:Rock.Data.EntitySaveHook`1.PreSave" /> returns /// without error. /// </remarks> protected override void PostSave() { var rockContext = ( RockContext )this.RockContext; if (HistoryChanges != null) { foreach (var historyItem in HistoryChanges) { int personId = historyItem.PersonId > 0 ? historyItem.PersonId : Entity.PersonId; // if GroupId is 0, it is probably a Group that wasn't saved yet, so get the GroupId from historyItem.Group.Id instead if (historyItem.GroupId == 0) { historyItem.GroupId = historyItem.Group?.Id; } var changes = HistoryService.GetChanges( typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_GROUP_MEMBERSHIP.AsGuid(), personId, historyItem.PersonHistoryChangeList, historyItem.Caption, typeof(Group), historyItem.GroupId, Entity.ModifiedByPersonAliasId, rockContext.SourceOfChange); if (changes.Any()) { Task.Run(async() => { // Wait 1 second to allow all post save actions to complete await Task.Delay(1000); try { using (var insertRockContext = new RockContext()) { insertRockContext.BulkInsert(changes); } } catch (SystemException ex) { ExceptionLogService.LogException(ex, null); } }); } var groupMemberChanges = HistoryService.GetChanges( typeof(GroupMember), Rock.SystemGuid.Category.HISTORY_GROUP_CHANGES.AsGuid(), Entity.Id, historyItem.GroupMemberHistoryChangeList, historyItem.Caption, typeof(Group), historyItem.GroupId, Entity.ModifiedByPersonAliasId, rockContext.SourceOfChange); if (groupMemberChanges.Any()) { Task.Run(async() => { // Wait 1 second to allow all post save actions to complete await Task.Delay(1000); try { using (var insertRockContext = new RockContext()) { insertRockContext.BulkInsert(groupMemberChanges); } } catch (SystemException ex) { ExceptionLogService.LogException(ex, null); } }); } } } base.PostSave(); // if this is a GroupMember record on a Family, ensure that AgeClassification, PrimaryFamily, // GivingLeadId, and GroupSalution is updated // NOTE: This is also done on Person.PostSaveChanges in case Birthdate changes var groupTypeFamilyRoleIds = GroupTypeCache.GetFamilyGroupType()?.Roles?.Select(a => a.Id).ToList(); if (groupTypeFamilyRoleIds?.Any() == true) { if (groupTypeFamilyRoleIds.Contains(Entity.GroupRoleId)) { PersonService.UpdatePersonAgeClassification(Entity.PersonId, rockContext); PersonService.UpdatePrimaryFamily(Entity.PersonId, rockContext); PersonService.UpdateGivingLeaderId(Entity.PersonId, rockContext); GroupService.UpdateGroupSalutations(Entity.GroupId, rockContext); if (_preSaveChangesOldGroupId.HasValue && _preSaveChangesOldGroupId.Value != Entity.GroupId) { // if person was moved to a different family, the old family will need its GroupSalutations updated GroupService.UpdateGroupSalutations(_preSaveChangesOldGroupId.Value, rockContext); } } } if (State == EntityContextState.Added || State == EntityContextState.Modified) { if (Entity.Group != null && Entity.Person != null) { if (Entity.Group?.IsSecurityRoleOrSecurityGroupType() == true) { /* 09/27/2021 MDP * * If this GroupMember record results in making this Person having a higher AccountProtectionProfile level, * update the Person's AccountProtectionProfile. * Note: If this GroupMember record could result in making this Person having a *lower* AccountProtectionProfile level, * don't lower the AccountProtectionProfile here, because other rules have to be considered before * lowering the AccountProtectionProfile level. So we'll let the RockCleanup job take care of making sure the * AccountProtectionProfile is updated after factoring in all the rules. * */ if (Entity.Group.ElevatedSecurityLevel >= Utility.Enums.ElevatedSecurityLevel.Extreme && Entity.Person.AccountProtectionProfile < Utility.Enums.AccountProtectionProfile.Extreme) { Entity.Person.AccountProtectionProfile = Utility.Enums.AccountProtectionProfile.Extreme; rockContext.SaveChanges(); } else if (Entity.Group.ElevatedSecurityLevel >= Utility.Enums.ElevatedSecurityLevel.High && Entity.Person.AccountProtectionProfile < Utility.Enums.AccountProtectionProfile.High) { Entity.Person.AccountProtectionProfile = Utility.Enums.AccountProtectionProfile.High; rockContext.SaveChanges(); } } } } SendUpdateGroupMemberMessage(); }
/// <summary> /// Registers any entity-based block types that are not currently registered in Rock. /// </summary> /// <param name="refreshAll">if set to <c>true</c> will refresh name, category, and description for all block types (not just the new ones)</param> private static void RegisterEntityBlockTypes(bool refreshAll = false) { var rockBlockTypes = Reflection.FindTypes(typeof(Blocks.IRockBlockType)); List <Type> registeredTypes; using (var rockContext = new RockContext()) { registeredTypes = new BlockTypeService(rockContext) .Queryable().AsNoTracking() .Where(b => b.EntityTypeId.HasValue && !string.IsNullOrEmpty(b.EntityType.AssemblyName)) .ToList() .Select(b => Type.GetType(b.EntityType.AssemblyName, false)) .Where(b => b != null) .ToList(); } // Get the Block Entity Type int?blockEntityTypeId = EntityTypeCache.Get(typeof(Block)).Id; // for each BlockType foreach (var type in rockBlockTypes.Values) { if (refreshAll || !registeredTypes.Any(t => t == type)) { // Attempt to load the control try { using (var rockContext = new RockContext()) { var entityTypeId = EntityTypeCache.Get(type, true, rockContext).Id; var blockTypeService = new BlockTypeService(rockContext); var blockType = blockTypeService.Queryable() .FirstOrDefault(b => b.EntityTypeId == entityTypeId); if (blockType == null) { // Create new BlockType record and save it blockType = new BlockType(); blockType.EntityTypeId = entityTypeId; blockTypeService.Add(blockType); } // Update Name, Category, and Description based on block's attribute definitions blockType.Name = Reflection.GetDisplayName(type) ?? string.Empty; if (string.IsNullOrWhiteSpace(blockType.Name)) { blockType.Name = type.FullName; } if (blockType.Name.Length > 100) { blockType.Name = blockType.Name.Truncate(100); } blockType.Category = Rock.Reflection.GetCategory(type) ?? string.Empty; blockType.Description = Rock.Reflection.GetDescription(type) ?? string.Empty; rockContext.SaveChanges(); // Update the attributes used by the block Rock.Attribute.Helper.UpdateAttributes(type, blockEntityTypeId, "BlockTypeId", blockType.Id.ToString(), rockContext); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"RegisterEntityBlockTypes failed for {type.FullName} with exception: {ex.Message}"); ExceptionLogService.LogException(new Exception(string.Format("Problem processing block with path '{0}'.", type.FullName), ex), null); } } } }
/// <summary> /// Registers any block types that are not currently registered in Rock. /// </summary> /// <param name="physWebAppPath">A <see cref="System.String" /> containing the physical path to Rock on the server.</param> /// <param name="page">The <see cref="System.Web.UI.Page" />.</param> /// <param name="refreshAll">if set to <c>true</c> will refresh name, category, and description for all block types (not just the new ones)</param> public static void RegisterBlockTypes(string physWebAppPath, System.Web.UI.Page page, bool refreshAll = false) { // Dictionary for block types. Key is path, value is friendly name var list = new Dictionary <string, string>(); RegisterEntityBlockTypes(refreshAll); // Find all the blocks in the Blocks folder... FindAllBlocksInPath(physWebAppPath, list, "Blocks"); // Now do the exact same thing for the Plugins folder... FindAllBlocksInPath(physWebAppPath, list, "Plugins"); // Get a list of the BlockTypes already registered (via the path) var registeredPaths = new List <string>(); using (var rockContext = new RockContext()) { registeredPaths = new BlockTypeService(rockContext) .Queryable().AsNoTracking() .Where(b => !string.IsNullOrEmpty(b.Path)) .Select(b => b.Path) .ToList(); } // Get the Block Entity Type int?blockEntityTypeId = EntityTypeCache.Get(typeof(Block)).Id; // for each BlockType foreach (string path in list.Keys) { if (refreshAll || !registeredPaths.Any(b => b.Equals(path, StringComparison.OrdinalIgnoreCase))) { // Attempt to load the control try { var blockCompiledType = System.Web.Compilation.BuildManager.GetCompiledType(path); if (blockCompiledType != null && typeof(Web.UI.RockBlock).IsAssignableFrom(blockCompiledType)) { using (var rockContext = new RockContext()) { var blockTypeService = new BlockTypeService(rockContext); var blockType = blockTypeService.Queryable() .FirstOrDefault(b => b.Path == path); if (blockType == null) { // Create new BlockType record and save it blockType = new BlockType(); blockType.Path = path; blockTypeService.Add(blockType); } Type controlType = blockCompiledType; // Update Name, Category, and Description based on block's attribute definitions blockType.Name = Reflection.GetDisplayName(controlType) ?? string.Empty; if (string.IsNullOrWhiteSpace(blockType.Name)) { // Parse the relative path to get the name var nameParts = list[path].Split('/'); for (int i = 0; i < nameParts.Length; i++) { if (i == nameParts.Length - 1) { nameParts[i] = Path.GetFileNameWithoutExtension(nameParts[i]); } nameParts[i] = nameParts[i].SplitCase(); } blockType.Name = string.Join(" > ", nameParts); } if (blockType.Name.Length > 100) { blockType.Name = blockType.Name.Truncate(100); } blockType.Category = Rock.Reflection.GetCategory(controlType) ?? string.Empty; blockType.Description = Rock.Reflection.GetDescription(controlType) ?? string.Empty; rockContext.SaveChanges(); // Update the attributes used by the block Rock.Attribute.Helper.UpdateAttributes(controlType, blockEntityTypeId, "BlockTypeId", blockType.Id.ToString(), rockContext); } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"RegisterBlockTypes failed for {path} with exception: {ex.Message}"); ExceptionLogService.LogException(new Exception(string.Format("Problem processing block with path '{0}'.", path), ex), null); } } } }
protected override void PreSave() { if (Entry.State == EntityContextState.Deleted) { if (Entity.StorageProvider != null) { Entity.BinaryFileTypeId = Entry.OriginalValues[nameof(Entity.BinaryFileTypeId)].ToString().AsInteger(); try { Entity.StorageProvider.DeleteContent(Entity); } catch (Exception ex) { // If an exception occurred while trying to delete provider's file, log the exception, but continue with the delete. ExceptionLogService.LogException(ex); } Entity.BinaryFileTypeId = null; } } else { if (Entity.BinaryFileType == null && Entity.BinaryFileTypeId.HasValue) { Entity.BinaryFileType = new BinaryFileTypeService(( RockContext )DbContext).Get(Entity.BinaryFileTypeId.Value); } if (Entity.MimeType.StartsWith("image/")) { try { using (Bitmap bm = new Bitmap(Entity.ContentStream)) { if (bm != null) { Entity.Width = bm.Width; Entity.Height = bm.Height; } } Entity.ContentStream.Seek(0, SeekOrigin.Begin); if (!Entity.IsTemporary) { var BinaryFileType = Entity.BinaryFileType; if (BinaryFileType.MaxHeight.HasValue && BinaryFileType.MaxHeight != 0 && BinaryFileType.MaxWidth.HasValue && BinaryFileType.MaxWidth != 0) { ResizeSettings settings = new ResizeSettings(); MemoryStream resizedStream = new MemoryStream(); if (BinaryFileType.MaxWidth.Value < Entity.Width || BinaryFileType.MaxHeight < Entity.Height) { settings.Add("mode", "max"); if (BinaryFileType.MaxHeight < Entity.Height && BinaryFileType.MaxWidth < Entity.Width) { if (BinaryFileType.MaxHeight >= BinaryFileType.MaxWidth) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } if (BinaryFileType.MaxHeight <= BinaryFileType.MaxWidth) { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } } else if (BinaryFileType.MaxHeight < Entity.Height) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } else { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } ImageBuilder.Current.Build(Entity.ContentStream, resizedStream, settings); Entity.ContentStream = resizedStream; using (Bitmap bm = new Bitmap(Entity.ContentStream)) { if (bm != null) { Entity.Width = bm.Width; Entity.Height = bm.Height; } } } } } } catch (Exception) { } // if the file is an invalid photo keep moving } if (Entry.State == EntityContextState.Added) { // when a file is saved (unless it is getting Deleted/Saved), it should use the StoredEntityType that is associated with the BinaryFileType if (Entity.BinaryFileType != null) { // Persist the storage type Entity.StorageEntityTypeId = Entity.BinaryFileType.StorageEntityTypeId; // Persist the storage type's settings specific to this binary file type var settings = new Dictionary <string, string>(); if (Entity.BinaryFileType.Attributes == null) { Entity.BinaryFileType.LoadAttributes(); } foreach (var attributeValue in Entity.BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } Entity.StorageEntitySettings = settings.ToJson(); if (Entity.StorageProvider != null) { // save the file to the provider's new storage medium, and if the medium returns a filesize, save that value. long?outFileSize = null; Entity.StorageProvider.SaveContent(Entity, out outFileSize); if (outFileSize.HasValue) { Entity.FileSize = outFileSize; } Entity.Path = Entity.StorageProvider.GetPath(Entity); } } } else if (Entry.State == EntityContextState.Modified) { // when a file is saved (unless it is getting Deleted/Added), // it should use the StorageEntityType that is associated with the BinaryFileType if (Entity.BinaryFileType != null) { // if the storage provider changed, or any of its settings specific // to the binary file type changed, delete the original provider's content if (Entity.StorageEntityTypeId.HasValue && Entity.BinaryFileType.StorageEntityTypeId.HasValue) { var settings = new Dictionary <string, string>(); if (Entity.BinaryFileType.Attributes == null) { Entity.BinaryFileType.LoadAttributes(); } foreach (var attributeValue in Entity.BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } string settingsJson = settings.ToJson(); if (Entity.StorageProvider != null && ( Entity.StorageEntityTypeId.Value != Entity.BinaryFileType.StorageEntityTypeId.Value || Entity.StorageEntitySettings != settingsJson)) { var ms = new MemoryStream(); Entity.ContentStream.Position = 0; Entity.ContentStream.CopyTo(ms); Entity.ContentStream.Dispose(); // Delete the current provider's storage Entity.StorageProvider.DeleteContent(Entity); // Set the new storage provider with its settings Entity.StorageEntityTypeId = Entity.BinaryFileType.StorageEntityTypeId; Entity.StorageEntitySettings = settingsJson; Entity.ContentStream = new MemoryStream(); ms.Position = 0; ms.CopyTo(Entity.ContentStream); Entity.ContentStream.Position = 0; Entity.FileSize = Entity.ContentStream.Length; } } } if (Entity.ContentIsDirty && Entity.StorageProvider != null) { /* * SK - 12/11/2021 * Path should always be reset in case when there is any change in Storage Provider from previous value. Otherwise new storage provider may still be refering the older path. */ Entity.Path = null; long?fileSize = null; Entity.StorageProvider.SaveContent(Entity, out fileSize); Entity.FileSize = fileSize; Entity.Path = Entity.StorageProvider.GetPath(Entity); } } } base.PreSave(); }
/// <summary> /// Pres the save. /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry">The entry.</param> public override void PreSaveChanges(DbContext dbContext, System.Data.Entity.Infrastructure.DbEntityEntry entry) { if (entry.State == System.Data.Entity.EntityState.Deleted) { if (StorageProvider != null) { this.BinaryFileTypeId = entry.OriginalValues["BinaryFileTypeId"].ToString().AsInteger(); try { StorageProvider.DeleteContent(this); } catch (Exception ex) { // If an exception occurred while trying to delete provider's file, log the exception, but continue with the delete. ExceptionLogService.LogException(ex); } this.BinaryFileTypeId = null; } } else { if (BinaryFileType == null && BinaryFileTypeId.HasValue) { BinaryFileType = new BinaryFileTypeService(( RockContext )dbContext).Get(BinaryFileTypeId.Value); } if (this.MimeType.StartsWith("image/")) { try { using (Bitmap bm = new Bitmap(this.ContentStream)) { if (bm != null) { this.Width = bm.Width; this.Height = bm.Height; } } ContentStream.Seek(0, SeekOrigin.Begin); if (!IsTemporary) { if (BinaryFileType.MaxHeight.HasValue && BinaryFileType.MaxHeight != 0 && BinaryFileType.MaxWidth.HasValue && BinaryFileType.MaxWidth != 0) { ResizeSettings settings = new ResizeSettings(); MemoryStream resizedStream = new MemoryStream(); if (BinaryFileType.MaxWidth.Value < Width || BinaryFileType.MaxHeight < Height) { settings.Add("mode", "max"); if (BinaryFileType.MaxHeight < Height && BinaryFileType.MaxWidth < Width) { if (BinaryFileType.MaxHeight >= BinaryFileType.MaxWidth) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } if (BinaryFileType.MaxHeight <= BinaryFileType.MaxWidth) { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } } else if (BinaryFileType.MaxHeight < Height) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } else { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } ImageBuilder.Current.Build(this.ContentStream, resizedStream, settings); ContentStream = resizedStream; using (Bitmap bm = new Bitmap(this.ContentStream)) { if (bm != null) { this.Width = bm.Width; this.Height = bm.Height; } } } } } } catch (Exception) { } // if the file is an invalid photo keep moving } if (entry.State == System.Data.Entity.EntityState.Added) { // when a file is saved (unless it is getting Deleted/Saved), it should use the StoredEntityType that is associated with the BinaryFileType if (BinaryFileType != null) { // Persist the storage type StorageEntityTypeId = BinaryFileType.StorageEntityTypeId; // Persist the storage type's settings specific to this binary file type var settings = new Dictionary <string, string>(); if (BinaryFileType.Attributes == null) { BinaryFileType.LoadAttributes(); } foreach (var attributeValue in BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } StorageEntitySettings = settings.ToJson(); if (StorageProvider != null) { // save the file to the provider's new storage medium, and if the medium returns a filesize, save that value. long?outFileSize = null; StorageProvider.SaveContent(this, out outFileSize); if (outFileSize.HasValue) { FileSize = outFileSize; } Path = StorageProvider.GetPath(this); } } } else if (entry.State == System.Data.Entity.EntityState.Modified) { // when a file is saved (unless it is getting Deleted/Added), // it should use the StorageEntityType that is associated with the BinaryFileType if (BinaryFileType != null) { // if the storage provider changed, or any of its settings specific // to the binary file type changed, delete the original provider's content if (StorageEntityTypeId.HasValue && BinaryFileType.StorageEntityTypeId.HasValue) { var settings = new Dictionary <string, string>(); if (BinaryFileType.Attributes == null) { BinaryFileType.LoadAttributes(); } foreach (var attributeValue in BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } string settingsJson = settings.ToJson(); if (StorageProvider != null && ( StorageEntityTypeId.Value != BinaryFileType.StorageEntityTypeId.Value || StorageEntitySettings != settingsJson)) { var ms = new MemoryStream(); ContentStream.Position = 0; ContentStream.CopyTo(ms); ContentStream.Dispose(); // Delete the current provider's storage StorageProvider.DeleteContent(this); // Set the new storage provider with its settings StorageEntityTypeId = BinaryFileType.StorageEntityTypeId; StorageEntitySettings = settingsJson; ContentStream = new MemoryStream(); ms.Position = 0; ms.CopyTo(ContentStream); ContentStream.Position = 0; FileSize = ContentStream.Length; } } } if (_contentIsDirty && StorageProvider != null) { long?fileSize = null; StorageProvider.SaveContent(this, out fileSize); FileSize = fileSize; Path = StorageProvider.GetPath(this); } } } base.PreSaveChanges(dbContext, entry); }
/// <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); }