/// <summary> /// Handles the Click event of the btnSaveRequestNote 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 btnSaveRequestNote_Click( object sender, EventArgs e ) { int? setId = PageParameter( "Set" ).AsIntegerOrNull(); if ( setId.HasValue ) { var rockContext = new RockContext(); var entitySet = new EntitySetService( rockContext ).Get( setId.Value ); entitySet.Note = tbEntitySetNote.Text; rockContext.SaveChanges(); nbNoteSavedSuccess.Visible = true; tbEntitySetNote.Visible = false; btnSaveRequestNote.Visible = false; } }
/// <summary> /// Handles the Delete event of the gList control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gList_Delete( object sender, RowEventArgs e ) { var rockContext = new RockContext(); var entitySetService = new EntitySetService( rockContext ); EntitySet entitySet = entitySetService.Get( e.RowKeyId ); if ( entitySet != null ) { string errorMessage; if ( !entitySetService.CanDelete( entitySet, out errorMessage ) ) { mdGridWarning.Show( errorMessage, ModalAlertType.Information ); return; } // mark it as expired and RockCleanup will delete it later entitySet.ExpireDateTime = RockDateTime.Now.AddMinutes( -1 ); entitySet.EntitySetPurposeValueId = null; rockContext.SaveChanges(); } BindGrid(); }
/// <summary> /// creates or updates the entity set on the basis of campaign connection configuration, and returns the Id of the entitySetId /// </summary> /// <param name="campaignConfiguration">The campaign configuration.</param> /// <returns></returns> public static int GetEntitySet(CampaignItem campaignConfiguration) { var rockContext = new RockContext(); var connectionOpportunityService = new ConnectionOpportunityService(rockContext); var connectionRequestService = new ConnectionRequestService(rockContext); var entitySetService = new Rock.Model.EntitySetService(rockContext); var connectionOpportunity = connectionOpportunityService.Get(campaignConfiguration.OpportunityGuid); // list of person on the basis of Dataview result and optout group. var filteredPersonIds = GetFilteredPersonIds(campaignConfiguration, rockContext); // get the last connection datetime. var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignConfiguration.DaysBetweenConnection); // if DaysBetweenConnection is 0 then check for connection request for any time period. if (campaignConfiguration.DaysBetweenConnection == default(int)) { lastConnectionDateTime = DateTime.MinValue; } // list of person that has active connection request OR has connection closed in the past number of days between connection. var excludedPersonIds = connectionRequestService .Queryable() .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && ( a.ConnectionState == ConnectionState.Active || a.ConnectionState == ConnectionState.FutureFollowUp || ((a.ConnectionState == ConnectionState.Connected || a.ConnectionState == ConnectionState.Inactive) && a.ModifiedDateTime > lastConnectionDateTime))) .Select(a => a.PersonAlias.PersonId) .ToList(); // filtered list of person removing all the personIds found in excludedPersonIds List filteredPersonIds = filteredPersonIds.Where(a => !excludedPersonIds.Contains(a)).ToList(); // get the ordered list of personIds based on the oldest previous connection request and connection opportunity /* 2020-05-06 MDP * If there are many filteredPersonIds, we'll get a SQL Exception, so let's get *all* the Connected connection Requests first, * and then use C# to filter. */ var orderedLastCompletedRequestForPerson = connectionRequestService .Queryable() .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && a.ConnectionState == ConnectionState.Connected) .GroupBy(a => a.PersonAlias.PersonId) .Select(a => new { PersonId = a.Key, LastConnectionDateTime = a.OrderByDescending(b => b.ModifiedDateTime).Select(b => b.ModifiedDateTime).FirstOrDefault() }) .OrderBy(a => a.LastConnectionDateTime) .Select(a => a.PersonId).ToList(); // Use C# to filter persons so we can avoid a SQL Exception orderedLastCompletedRequestForPerson = orderedLastCompletedRequestForPerson.Where(a => filteredPersonIds.Contains(a)).ToList(); var random = new Random(); //// get the final ordered list of personIds based on the oldest previous connection request and //// connection opportunity otherwise order randomly for the person who don't have any previous connection request. var orderedPersonIds = filteredPersonIds .OrderBy(a => { var index = orderedLastCompletedRequestForPerson.IndexOf(a); if (index == -1) { return(random.Next(orderedLastCompletedRequestForPerson.Count, int.MaxValue)); } else { return(index); } }).ToList(); EntitySet entitySet = null; if (campaignConfiguration.EntitySetId != default(int)) { entitySet = entitySetService.Get(campaignConfiguration.EntitySetId); } List <Rock.Model.EntitySetItem> entitySetItems = new List <Rock.Model.EntitySetItem>(); var personEntityTypeId = EntityTypeCache.Get <Rock.Model.Person>().Id; if (entitySet == null || entitySet.EntityTypeId != personEntityTypeId) { entitySet = new Rock.Model.EntitySet(); entitySet.EntityTypeId = personEntityTypeId; entitySet.ExpireDateTime = null; entitySetService.Add(entitySet); } else { var entitySetItemQry = new EntitySetItemService(rockContext) .Queryable().AsNoTracking() .Where(i => i.EntitySetId == entitySet.Id); rockContext.BulkDelete(entitySetItemQry); } // Update the EntitySet name entitySet.Name = campaignConfiguration.Name; var orderIndex = 0; foreach (var personId in orderedPersonIds) { try { var item = new Rock.Model.EntitySetItem(); item.Order = orderIndex++; item.EntityId = personId; entitySetItems.Add(item); } catch { // ignore } } rockContext.SaveChanges(); entitySetItems.ForEach(a => { a.EntitySetId = entitySet.Id; }); rockContext.BulkInsert(entitySetItems); return(entitySet.Id); }
/// <summary> /// Gets the merge object list for the current EntitySet /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="fetchCount">The fetch count.</param> /// <returns></returns> private List<object> GetMergeObjectList( RockContext rockContext, int? fetchCount = null ) { int entitySetId = hfEntitySetId.Value.AsInteger(); var entitySetService = new EntitySetService( rockContext ); var entitySet = entitySetService.Get( entitySetId ); Dictionary<int, object> mergeObjectsDictionary = new Dictionary<int, object>(); // If this EntitySet contains IEntity Items, add those first if ( entitySet.EntityTypeId.HasValue ) { var qryEntity = entitySetService.GetEntityQuery( entitySetId ); if ( fetchCount.HasValue ) { qryEntity = qryEntity.Take( fetchCount.Value ); } var entityTypeCache = EntityTypeCache.Read( entitySet.EntityTypeId.Value ); bool isPersonEntityType = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.PERSON.AsGuid(); bool isGroupMemberEntityType = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid(); bool combineFamilyMembers = cbCombineFamilyMembers.Visible && cbCombineFamilyMembers.Checked; if ( ( isGroupMemberEntityType || isPersonEntityType ) && combineFamilyMembers ) { IQueryable<IEntity> qryPersons; if ( isGroupMemberEntityType ) { qryPersons = qryEntity.OfType<GroupMember>().Select( a => a.Person ).Distinct(); } else { qryPersons = qryEntity; } Guid familyGroupType = Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid(); var qryFamilyGroupMembers = new GroupMemberService( rockContext ).Queryable() .Where( a => a.Group.GroupType.Guid == familyGroupType ) .Where( a => qryPersons.Any( aa => aa.Id == a.PersonId ) ); var qryCombined = qryFamilyGroupMembers.Join( qryPersons, m => m.PersonId, p => p.Id, ( m, p ) => new { GroupMember = m, Person = p } ) .GroupBy( a => a.GroupMember.GroupId ) .Select( x => new { GroupId = x.Key, Persons = x.Select( xx => xx.Person ).Distinct() } ); foreach ( var combinedFamilyItem in qryCombined ) { object mergeObject; string commaPersonIds = combinedFamilyItem.Persons.Select( a => a.Id ).Distinct().ToList().AsDelimited( "," ); var primaryGroupPerson = combinedFamilyItem.Persons.FirstOrDefault() as Person; if ( mergeObjectsDictionary.ContainsKey( primaryGroupPerson.Id ) ) { foreach ( var person in combinedFamilyItem.Persons ) { if ( !mergeObjectsDictionary.ContainsKey( person.Id ) ) { primaryGroupPerson = person as Person; break; } } } // if we are combining from a GroupMemberEntityType list add the GroupMember attributes of the primary person in the combined list if ( isGroupMemberEntityType ) { var groupMember = qryEntity.OfType<GroupMember>().Where( a => a.PersonId == primaryGroupPerson.Id ).FirstOrDefault(); primaryGroupPerson.AdditionalLavaFields = primaryGroupPerson.AdditionalLavaFields ?? new Dictionary<string, object>(); if ( groupMember != null ) { primaryGroupPerson.AdditionalLavaFields.Add( "GroupMember", groupMember ); } } if ( combinedFamilyItem.Persons.Count() > 1 ) { var combinedPerson = primaryGroupPerson.ToJson().FromJsonOrNull<MergeTemplateCombinedPerson>(); var familyTitle = RockUdfHelper.ufnCrm_GetFamilyTitle( rockContext, null, combinedFamilyItem.GroupId, commaPersonIds, true ); combinedPerson.FullName = familyTitle; var firstNameList = combinedFamilyItem.Persons.Select( a => ( a as Person ).FirstName ).ToList(); var nickNameList = combinedFamilyItem.Persons.Select( a => ( a as Person ).NickName ).ToList(); combinedPerson.FirstName = firstNameList.AsDelimited( ", ", " & " ); combinedPerson.NickName = nickNameList.AsDelimited( ", ", " & " ); combinedPerson.LastName = primaryGroupPerson.LastName; combinedPerson.SuffixValueId = null; combinedPerson.SuffixValue = null; mergeObject = combinedPerson; } else { mergeObject = primaryGroupPerson; } mergeObjectsDictionary.AddOrIgnore( primaryGroupPerson.Id, mergeObject ); } } else if ( isGroupMemberEntityType ) { foreach ( var groupMember in qryEntity.AsNoTracking().OfType<GroupMember>() ) { var person = groupMember.Person; person.AdditionalLavaFields = new Dictionary<string, object>(); person.AdditionalLavaFields.Add( "GroupMember", groupMember ); mergeObjectsDictionary.AddOrIgnore( groupMember.PersonId, person ); } } else { foreach ( var item in qryEntity.AsNoTracking() ) { mergeObjectsDictionary.AddOrIgnore( item.Id, item ); } } } var entitySetItemService = new EntitySetItemService( rockContext ); string[] emptyJson = new string[] { string.Empty, "{}" }; var entitySetItemMergeValuesQry = entitySetItemService.GetByEntitySetId( entitySetId, true ).Where( a => !emptyJson.Contains( a.AdditionalMergeValuesJson ) ); if ( fetchCount.HasValue ) { entitySetItemMergeValuesQry = entitySetItemMergeValuesQry.Take( fetchCount.Value ); } // the entityId to use for NonEntity objects int nonEntityId = 1; // now, add the additional MergeValues regardless of if the EntitySet contains IEntity items or just Non-IEntity items foreach ( var additionalMergeValuesItem in entitySetItemMergeValuesQry.AsNoTracking() ) { object mergeObject; int entityId; if ( additionalMergeValuesItem.EntityId > 0 ) { entityId = additionalMergeValuesItem.EntityId; } else { // not pointing to an actual EntityId, so use the nonEntityId for ti entityId = nonEntityId++; } if ( mergeObjectsDictionary.ContainsKey( entityId ) ) { mergeObject = mergeObjectsDictionary[entityId]; } else { if ( entitySet.EntityTypeId.HasValue ) { // if already have real entities in our list, don't add additional items to the mergeObjectsDictionary continue; } // non-Entity merge object, so just use Dictionary mergeObject = new Dictionary<string, object>(); mergeObjectsDictionary.AddOrIgnore( entityId, mergeObject ); } foreach ( var additionalMergeValue in additionalMergeValuesItem.AdditionalMergeValues ) { if ( mergeObject is IEntity ) { // add the additional fields to AdditionalLavaFields IEntity mergeEntity = ( mergeObject as IEntity ); mergeEntity.AdditionalLavaFields = mergeEntity.AdditionalLavaFields ?? new Dictionary<string, object>(); object mergeValueObject = additionalMergeValue.Value; mergeEntity.AdditionalLavaFields.AddOrIgnore( additionalMergeValue.Key, mergeValueObject ); } else if ( mergeObject is IDictionary<string, object> ) { // anonymous object with no fields yet IDictionary<string, object> nonEntityObject = mergeObject as IDictionary<string, object>; nonEntityObject.AddOrIgnore( additionalMergeValue.Key, additionalMergeValue.Value ); } else { throw new Exception( string.Format( "Unexpected MergeObject Type: {0}", mergeObject ) ); } } } var result = mergeObjectsDictionary.Select( a => a.Value ); if ( fetchCount.HasValue ) { // make sure the result is limited to fetchCount (even though the above queries are also limited to fetch count) result = result.Take( fetchCount.Value ); } return result.ToList(); }
/// <summary> /// Shows the merge for entity set identifier. /// </summary> /// <param name="entitySetId">The entity set identifier.</param> protected void ShowMergeForEntitySetId( int entitySetId ) { hfEntitySetId.Value = entitySetId.ToString(); var rockContext = new RockContext(); var entitySetService = new EntitySetService( rockContext ); var entitySetItemsService = new EntitySetItemService( rockContext ); var entitySet = entitySetService.Get( entitySetId ); if ( entitySet == null ) { nbWarningMessage.Text = "Merge Records not found"; nbWarningMessage.Title = "Warning"; nbWarningMessage.NotificationBoxType = NotificationBoxType.Warning; pnlEntry.Visible = false; return; } if ( entitySet.EntityTypeId.HasValue ) { bool isPersonEntitySet = entitySet.EntityTypeId.Value == EntityTypeCache.GetId<Rock.Model.Person>(); bool isGroupMemberEntitySet = entitySet.EntityTypeId.Value == EntityTypeCache.GetId<Rock.Model.GroupMember>(); cbCombineFamilyMembers.Visible = isPersonEntitySet || isGroupMemberEntitySet; } else { cbCombineFamilyMembers.Visible = false; } int itemsCount = entitySetItemsService.Queryable().Where( a => a.EntitySetId == entitySetId ).Count(); nbNumberOfRecords.Text = string.Format( "There are {0} {1} to merge", itemsCount, "row".PluralizeIf( itemsCount != 1 ) ); }
/// <summary> /// Handles the Click event of the btnShowDataPreview 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 btnShowDataPreview_Click( object sender, EventArgs e ) { if ( pnlPreview.Visible ) { pnlPreview.Visible = false; return; } var rockContext = new RockContext(); int entitySetId = hfEntitySetId.Value.AsInteger(); var entitySetService = new EntitySetService( rockContext ); var entitySet = entitySetService.Get( entitySetId ); if ( entitySet.EntityTypeId.HasValue ) { var qry = entitySetService.GetEntityQuery( entitySetId ).Take( 15 ); EntityTypeCache itemEntityType = EntityTypeCache.Read( entitySet.EntityTypeId ?? 0 ); gPreview.CreatePreviewColumns( itemEntityType.GetEntityType() ); gPreview.DataSource = qry.ToList(); gPreview.DataBind(); } else { var entitySetItemService = new EntitySetItemService( rockContext ); var qry = entitySetItemService.GetByEntitySetId( entitySetId, true ).Take( 15 ); var list = qry.ToList().Select( a => a.AdditionalMergeValuesJson.FromJsonOrNull<Dictionary<string, object>>() ).ToList(); if ( list.Any() ) { gPreview.Columns.Clear(); foreach ( var s in list[0] ) { var gridField = Grid.GetGridField( s.Value != null ? s.Value.GetType() : typeof( string ) ); gridField.HeaderText = s.Key.SplitCase(); gridField.DataField = s.Key; gPreview.Columns.Add( gridField ); } gPreview.DataSource = qry.ToList().Select( a => a.AdditionalMergeValuesJson.FromJsonOrNull<object>() ).ToList(); gPreview.DataBind(); } } pnlPreview.Visible = true; }
/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { RockContext rockContext = new RockContext(); var entitySetService = new EntitySetService( rockContext ); var entitySetPurposeGuid = Rock.SystemGuid.DefinedValue.ENTITY_SET_PURPOSE_PERSON_MERGE_REQUEST.AsGuid(); var currentDateTime = RockDateTime.Now; var entitySetQry = entitySetService.Queryable() .Where( a => a.EntitySetPurposeValue.Guid == entitySetPurposeGuid ) .Where( s => !s.ExpireDateTime.HasValue || s.ExpireDateTime.Value > currentDateTime ); SortProperty sortProperty = gList.SortProperty; var qryPersonEntities = entitySetService.GetEntityItems<Person>(); var joinQry = entitySetQry.GroupJoin( qryPersonEntities, n => n.Id, o => o.EntitySetId, ( a, b ) => new { a.Id, a.ModifiedDateTime, a.Note, a.CreatedByPersonAlias, MergeRecords = b.Select( x => x.Item ) } ); if ( sortProperty != null ) { joinQry = joinQry.Sort( sortProperty ); } else { joinQry = joinQry.OrderBy( s => s.ModifiedDateTime ); } gList.SetLinqDataSource( joinQry ); gList.DataBind(); }
/// <summary> /// Loads the view details. /// </summary> private void LoadViewDetails() { if ( Page.IsPostBack ) { nbMergeRequestSuccess.Visible = false; nbMergeRequestAlreadySubmitted.Visible = false; } else { nbNotAuthorized.Visible = true; int? setId = PageParameter( "Set" ).AsIntegerOrNull(); if ( setId.HasValue ) { // if the user only has View auth to the page, mark the EntitySet as a Person Merge Request and let them edit the EntitySet note var rockContext = new RockContext(); var entitySetService = new EntitySetService( rockContext ); var entitySet = entitySetService.Get( setId.Value ); if ( entitySet != null ) { tbEntitySetNote.Text = entitySet.Note; var definedValuePurpose = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.ENTITY_SET_PURPOSE_PERSON_MERGE_REQUEST.AsGuid() ); if ( definedValuePurpose != null ) { nbNotAuthorized.Visible = false; tbEntitySetNote.Visible = true; btnSaveRequestNote.Visible = true; if ( entitySet.EntitySetPurposeValueId != definedValuePurpose.Id && entitySet.ExpireDateTime != null ) { nbMergeRequestSuccess.Visible = true; entitySet.EntitySetPurposeValueId = definedValuePurpose.Id; entitySet.ExpireDateTime = null; rockContext.SaveChanges(); } else { nbMergeRequestAlreadySubmitted.Visible = true; } } } } } }
/// <summary> /// Handles the Click event of the lbMerge 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 lbMerge_Click( object sender, EventArgs e ) { if ( MergeData.People.Count < 2 ) { nbPeople.Visible = true; return; } bool reconfirmRequired = ( MergeData.People.Select( p => p.Email ).Distinct().Count() > 1 && MergeData.People.Where( p => p.HasLogins ).Any() ); GetValuesSelection(); int? primaryPersonId = null; var oldPhotos = new List<int>(); var rockContext = new RockContext(); rockContext.WrapTransaction( () => { var personService = new PersonService( rockContext ); var userLoginService = new UserLoginService( rockContext ); var groupService = new GroupService( rockContext ); var groupMemberService = new GroupMemberService( rockContext ); var binaryFileService = new BinaryFileService( rockContext ); var phoneNumberService = new PhoneNumberService( rockContext ); var taggedItemService = new TaggedItemService( rockContext ); Person primaryPerson = personService.Get( MergeData.PrimaryPersonId ?? 0 ); if ( primaryPerson != null ) { primaryPersonId = primaryPerson.Id; var changes = new List<string>(); foreach ( var p in MergeData.People.Where( p => p.Id != primaryPerson.Id ) ) { changes.Add( string.Format( "Merged <span class='field-value'>{0} [ID: {1}]</span> with this record.", p.FullName, p.Id ) ); } // Photo Id int? newPhotoId = MergeData.GetSelectedValue( MergeData.GetProperty( "Photo" ) ).Value.AsIntegerOrNull(); if ( !primaryPerson.PhotoId.Equals( newPhotoId ) ) { changes.Add( "Modified the photo." ); primaryPerson.PhotoId = newPhotoId; } primaryPerson.TitleValueId = GetNewIntValue( "Title", changes ); primaryPerson.FirstName = GetNewStringValue( "FirstName", changes ); primaryPerson.NickName = GetNewStringValue( "NickName", changes ); primaryPerson.MiddleName = GetNewStringValue( "MiddleName", changes ); primaryPerson.LastName = GetNewStringValue( "LastName", changes ); primaryPerson.SuffixValueId = GetNewIntValue( "Suffix", changes ); primaryPerson.RecordTypeValueId = GetNewIntValue( "RecordType", changes ); primaryPerson.RecordStatusValueId = GetNewIntValue( "RecordStatus", changes ); primaryPerson.RecordStatusReasonValueId = GetNewIntValue( "RecordStatusReason", changes ); primaryPerson.ConnectionStatusValueId = GetNewIntValue( "ConnectionStatus", changes ); primaryPerson.IsDeceased = GetNewBoolValue( "Deceased", changes ) ?? false; primaryPerson.Gender = (Gender)GetNewEnumValue( "Gender", typeof( Gender ), changes ); primaryPerson.MaritalStatusValueId = GetNewIntValue( "MaritalStatus", changes ); primaryPerson.SetBirthDate( GetNewDateTimeValue( "BirthDate", changes ) ); primaryPerson.AnniversaryDate = GetNewDateTimeValue( "AnniversaryDate", changes ); primaryPerson.GraduationYear = GetNewIntValue( "GraduationYear", changes ); primaryPerson.Email = GetNewStringValue( "Email", changes ); primaryPerson.IsEmailActive = GetNewBoolValue( "EmailActive", changes ) ?? true; primaryPerson.EmailNote = GetNewStringValue( "EmailNote", changes ); primaryPerson.EmailPreference = (EmailPreference)GetNewEnumValue( "EmailPreference", typeof( EmailPreference ), changes ); primaryPerson.SystemNote = GetNewStringValue( "InactiveReasonNote", changes ); primaryPerson.SystemNote = GetNewStringValue( "SystemNote", changes ); // Update phone numbers var phoneTypes = DefinedTypeCache.Read( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE.AsGuid() ).DefinedValues; foreach ( var phoneType in phoneTypes ) { var phoneNumber = primaryPerson.PhoneNumbers.Where( p => p.NumberTypeValueId == phoneType.Id ).FirstOrDefault(); string oldValue = phoneNumber != null ? phoneNumber.Number : string.Empty; string key = "phone_" + phoneType.Id.ToString(); string newValue = GetNewStringValue( key, changes ); bool phoneNumberDeleted = false; if ( !oldValue.Equals( newValue, StringComparison.OrdinalIgnoreCase ) ) { // New phone doesn't match old if ( !string.IsNullOrWhiteSpace( newValue ) ) { // New value exists if ( phoneNumber == null ) { // Old value didn't exist... create new phone record phoneNumber = new PhoneNumber { NumberTypeValueId = phoneType.Id }; primaryPerson.PhoneNumbers.Add( phoneNumber ); } // Update phone number phoneNumber.Number = newValue; } else { // New value doesn't exist if ( phoneNumber != null ) { // old value existed.. delete it primaryPerson.PhoneNumbers.Remove( phoneNumber ); phoneNumberService.Delete( phoneNumber ); phoneNumberDeleted = true; } } } // check to see if IsMessagingEnabled is true for any of the merged people for this number/numbertype if ( phoneNumber != null && !phoneNumberDeleted && !phoneNumber.IsMessagingEnabled ) { var personIds = MergeData.People.Select( a => a.Id ).ToList(); var isMessagingEnabled = phoneNumberService.Queryable().Where( a => personIds.Contains( a.PersonId ) && a.Number == phoneNumber.Number && a.NumberTypeValueId == phoneNumber.NumberTypeValueId ).Any( a => a.IsMessagingEnabled ); if ( isMessagingEnabled ) { phoneNumber.IsMessagingEnabled = true; } } } // Save the new record rockContext.SaveChanges(); // Update the attributes primaryPerson.LoadAttributes( rockContext ); foreach ( var property in MergeData.Properties.Where( p => p.Key.StartsWith( "attr_" ) ) ) { string attributeKey = property.Key.Substring( 5 ); string oldValue = primaryPerson.GetAttributeValue( attributeKey ) ?? string.Empty; string newValue = GetNewStringValue( property.Key, changes ) ?? string.Empty; if ( !oldValue.Equals( newValue ) ) { var attribute = primaryPerson.Attributes[attributeKey]; Rock.Attribute.Helper.SaveAttributeValue( primaryPerson, attribute, newValue, rockContext ); } } HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), primaryPerson.Id, changes ); // Delete the unselected photos string photoKeeper = primaryPerson.PhotoId.HasValue ? primaryPerson.PhotoId.Value.ToString() : string.Empty; foreach ( var photoValue in MergeData.Properties .Where( p => p.Key == "Photo" ) .SelectMany( p => p.Values ) .Where( v => v.Value != "" && v.Value != photoKeeper ) .Select( v => v.Value ) ) { int photoId = 0; if ( int.TryParse( photoValue, out photoId ) ) { var photo = binaryFileService.Get( photoId ); if ( photo != null ) { string errorMessages; if ( binaryFileService.CanDelete( photo, out errorMessages ) ) { binaryFileService.Delete( photo ); } } } } rockContext.SaveChanges(); // Delete merged person's family records and any families that would be empty after merge foreach ( var p in MergeData.People.Where( p => p.Id != primaryPersonId.Value ) ) { // Delete the merged person's phone numbers (we've already updated the primary persons values) foreach ( var phoneNumber in phoneNumberService.GetByPersonId( p.Id ) ) { phoneNumberService.Delete( phoneNumber ); } // If there was more than one email address and user has logins, then set any of the local // logins ( database & AD ) to require a reconfirmation if ( reconfirmRequired ) { foreach ( var login in userLoginService.GetByPersonId( p.Id ) ) { var component = Rock.Security.AuthenticationContainer.GetComponent( login.EntityType.Name ); if ( component != null && !component.RequiresRemoteAuthentication ) { login.IsConfirmed = false; } } } rockContext.SaveChanges(); // Delete the merged person's other family member records and the family if they were the only one in the family Guid familyGuid = Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid(); foreach ( var familyMember in groupMemberService.Queryable().Where( m => m.PersonId == p.Id && m.Group.GroupType.Guid == familyGuid ) ) { groupMemberService.Delete( familyMember ); rockContext.SaveChanges(); // Get the family var family = groupService.Queryable( "Members" ).Where( f => f.Id == familyMember.GroupId ).FirstOrDefault(); if ( !family.Members.Any() ) { // If there are not any other family members, delete the family record. // If theres any people that have this group as a giving group, set it to null (the person being merged should be the only one) foreach ( Person gp in personService.Queryable().Where( g => g.GivingGroupId == family.Id ) ) { gp.GivingGroupId = null; } // save to the database prior to doing groupService.Delete since .Delete quietly might not delete if thinks the Family is used for a GivingGroupId rockContext.SaveChanges(); // Delete the family string errorMessage; if ( groupService.CanDelete( family, out errorMessage ) ) { var oldFamilyChanges = new List<string>(); History.EvaluateChange( oldFamilyChanges, "Family", family.Name, string.Empty ); HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(), primaryPersonId.Value, oldFamilyChanges, family.Name, typeof( Group ), family.Id ); groupService.Delete( family ); rockContext.SaveChanges(); } } } } // Flush any security roles that the merged person's other records were a part of foreach ( var p in MergeData.People.Where( p => p.Id != primaryPersonId.Value ) ) { foreach ( var groupMember in groupMemberService.Queryable().Where( m => m.PersonId == p.Id ) ) { Group group = new GroupService( rockContext ).Get( groupMember.GroupId ); if ( group.IsSecurityRole || group.GroupType.Guid.Equals( Rock.SystemGuid.GroupType.GROUPTYPE_SECURITY_ROLE.AsGuid() ) ) { Rock.Security.Role.Flush( group.Id ); Rock.Security.Authorization.Flush(); } } } // now that the Merge is complete, the EntitySet can be marked to be deleted by the RockCleanup job var entitySetService = new EntitySetService( rockContext ); var entitySet = entitySetService.Get( MergeData.EntitySetId ); if ( entitySet != null ) { entitySet.ExpireDateTime = RockDateTime.Now.AddMinutes(-1); entitySet.EntitySetPurposeValueId = null; rockContext.SaveChanges(); } } } ); foreach ( var p in MergeData.People.Where( p => p.Id != primaryPersonId.Value ) ) { // Run merge proc to merge all associated data var parms = new Dictionary<string, object>(); parms.Add( "OldId", p.Id ); parms.Add( "NewId", primaryPersonId.Value ); DbService.ExecuteCommand( "spCrm_PersonMerge", CommandType.StoredProcedure, parms ); } NavigateToLinkedPage( "PersonDetailPage", "PersonId", primaryPersonId.Value ); }
/// <summary> /// Cleans up expired entity sets. /// </summary> /// <param name="dataMap">The data map.</param> private int CleanupExpiredEntitySets( JobDataMap dataMap ) { var entitySetRockContext = new Rock.Data.RockContext(); var currentDateTime = RockDateTime.Now; var entitySetService = new EntitySetService( entitySetRockContext ); var qry = entitySetService.Queryable().Where( a => a.ExpireDateTime.HasValue && a.ExpireDateTime < currentDateTime ); int totalRowsDeleted = 0; foreach ( var entitySet in qry.ToList() ) { string deleteWarning; if ( entitySetService.CanDelete( entitySet, out deleteWarning ) ) { // delete in chunks (see http://dba.stackexchange.com/questions/1750/methods-of-speeding-up-a-huge-delete-from-table-with-no-clauses) bool keepDeleting = true; while ( keepDeleting ) { var dbTransaction = entitySetRockContext.Database.BeginTransaction(); try { string sqlCommand = @"DELETE TOP (1000) FROM [EntitySetItem] WHERE [EntitySetId] = @entitySetId"; int rowsDeleted = entitySetRockContext.Database.ExecuteSqlCommand( sqlCommand, new SqlParameter( "entitySetId", entitySet.Id ) ); keepDeleting = rowsDeleted > 0; totalRowsDeleted += rowsDeleted; } finally { dbTransaction.Commit(); } } entitySetService.Delete( entitySet ); entitySetRockContext.SaveChanges(); } } return totalRowsDeleted; }
/// <summary> /// Handles the Click event of the btnProcessWaitlist control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void btnProcessWaitlist_Click( object sender, EventArgs e ) { // create entity set with selected individuals var keys = gWaitList.SelectedKeys.ToList(); if ( keys.Any() ) { var entitySet = new Rock.Model.EntitySet(); entitySet.EntityTypeId = Rock.Web.Cache.EntityTypeCache.Read<Rock.Model.RegistrationRegistrant>().Id; entitySet.ExpireDateTime = RockDateTime.Now.AddMinutes( 20 ); foreach ( var key in keys ) { try { var item = new Rock.Model.EntitySetItem(); item.EntityId = (int)key; entitySet.Items.Add( item ); } catch { // ignore } } if ( entitySet.Items.Any() ) { var rockContext = new RockContext(); var service = new Rock.Model.EntitySetService( rockContext ); service.Add( entitySet ); rockContext.SaveChanges(); // redirect to the waitlist page Dictionary<string, string> queryParms = new Dictionary<string, string>(); queryParms.Add( "WaitListSetId", entitySet.Id.ToString() ); NavigateToLinkedPage( "WaitListProcessPage", queryParms ); } } }