/// <summary> /// Job that will sync groups. /// /// Called by the <see cref="IScheduler" /> when a /// <see cref="ITrigger" /> fires that is associated with /// the <see cref="IJob" />. /// </summary> public virtual void Execute(IJobExecutionContext context) { // Get the job setting(s) JobDataMap dataMap = context.JobDetail.JobDataMap; bool requirePasswordReset = dataMap.GetBoolean("RequirePasswordReset"); var commandTimeout = dataMap.GetString("CommandTimeout").AsIntegerOrNull() ?? 180; // Counters for displaying results int groupsSynced = 0; int groupsChanged = 0; string groupName = string.Empty; string dataViewName = string.Empty; var errors = new List <string>(); try { // get groups set to sync var activeSyncList = new List <GroupSyncInfo>(); using (var rockContext = new RockContext()) { // Get groups that are not archived and are still active. activeSyncList = new GroupSyncService(rockContext) .Queryable() .AsNoTracking() .AreNotArchived() .AreActive() .NeedToBeSynced() .Select(x => new GroupSyncInfo { SyncId = x.Id, GroupName = x.Group.Name }) .ToList(); } foreach (var syncInfo in activeSyncList) { int syncId = syncInfo.SyncId; bool hasSyncChanged = false; context.UpdateLastStatusMessage($"Syncing group {syncInfo.GroupName}"); // Use a fresh rockContext per sync so that ChangeTracker doesn't get bogged down using (var rockContext = new RockContext()) { // increase the timeout just in case the data view source is slow rockContext.Database.CommandTimeout = commandTimeout; rockContext.SourceOfChange = "Group Sync"; // Get the Sync var sync = new GroupSyncService(rockContext) .Queryable() .Include(a => a.Group) .Include(a => a.SyncDataView) .AsNoTracking() .FirstOrDefault(s => s.Id == syncId); if (sync == null || sync.SyncDataView.EntityTypeId != EntityTypeCache.Get(typeof(Person)).Id) { // invalid sync or invalid SyncDataView continue; } List <string> syncErrors = new List <string>(); dataViewName = sync.SyncDataView.Name; groupName = sync.Group.Name; Stopwatch stopwatch = Stopwatch.StartNew(); // Get the person id's from the data view (source) var dataViewQry = sync.SyncDataView.GetQuery(null, rockContext, commandTimeout, out syncErrors); var sourcePersonIds = dataViewQry.Select(q => q.Id).ToList(); stopwatch.Stop(); DataViewService.AddRunDataViewTransaction(sync.SyncDataView.Id, Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds)); // If any error occurred trying get the 'where expression' from the sync-data-view, // just skip trying to sync that particular group's Sync Data View for now. if (syncErrors.Count > 0) { errors.AddRange(syncErrors); ExceptionLogService.LogException(new Exception(string.Format("An error occurred while trying to GroupSync group '{0}' and data view '{1}' so the sync was skipped. Error: {2}", groupName, dataViewName, String.Join(",", syncErrors)))); continue; } // Get the person id's in the group (target) for the role being synced. // Note: targetPersonIds must include archived group members // so we don't try to delete anyone who's already archived, and // it must include deceased members so we can remove them if they // are no longer in the data view. var existingGroupMemberPersonList = new GroupMemberService(rockContext) .Queryable(true, true).AsNoTracking() .Where(gm => gm.GroupId == sync.GroupId) .Where(gm => gm.GroupRoleId == sync.GroupTypeRoleId) .Select(gm => new { PersonId = gm.PersonId, IsArchived = gm.IsArchived }) .ToList(); var targetPersonIdsToDelete = existingGroupMemberPersonList.Where(t => !sourcePersonIds.Contains(t.PersonId) && t.IsArchived != true).ToList(); if (targetPersonIdsToDelete.Any()) { context.UpdateLastStatusMessage($"Deleting {targetPersonIdsToDelete.Count()} group records in {syncInfo.GroupName} that are no longer in the sync data view"); } int deletedCount = 0; // Delete people from the group/role that are no longer in the data view -- // but not the ones that are already archived. foreach (var targetPerson in targetPersonIdsToDelete) { deletedCount++; if (deletedCount % 100 == 0) { context.UpdateLastStatusMessage($"Deleted {deletedCount} of {targetPersonIdsToDelete.Count()} group member records for group {syncInfo.GroupName}"); } try { // Use a new context to limit the amount of change-tracking required using (var groupMemberContext = new RockContext()) { // Delete the records for that person's group and role. // NOTE: just in case there are duplicate records, delete all group member records for that person and role var groupMemberService = new GroupMemberService(groupMemberContext); foreach (var groupMember in groupMemberService .Queryable(true, true) .Where(m => m.GroupId == sync.GroupId && m.GroupRoleId == sync.GroupTypeRoleId && m.PersonId == targetPerson.PersonId) .ToList()) { groupMemberService.Delete(groupMember); } groupMemberContext.SaveChanges(); // If the Group has an exit email, and person has an email address, send them the exit email if (sync.ExitSystemCommunication != null) { var person = new PersonService(groupMemberContext).Get(targetPerson.PersonId); if (person.CanReceiveEmail(false)) { // Send the exit email var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Group", sync.Group); mergeFields.Add("Person", person); var emailMessage = new RockEmailMessage(sync.ExitSystemCommunication); emailMessage.AddRecipient(new RockEmailMessageRecipient(person, mergeFields)); var emailErrors = new List <string>(); emailMessage.Send(out emailErrors); errors.AddRange(emailErrors); } } } } catch (Exception ex) { ExceptionLogService.LogException(ex); continue; } hasSyncChanged = true; } // Now find all the people in the source list who are NOT already in the target list (as Unarchived) var targetPersonIdsToAdd = sourcePersonIds.Where(s => !existingGroupMemberPersonList.Any(t => t.PersonId == s && t.IsArchived == false)).ToList(); // Make a list of PersonIds that have an Archived group member record // if this person isn't already a member of the list as an Unarchived member, we can Restore the group member for that PersonId instead var archivedTargetPersonIds = existingGroupMemberPersonList.Where(t => t.IsArchived == true).Select(a => a.PersonId).ToList(); context.UpdateLastStatusMessage($"Adding {targetPersonIdsToAdd.Count()} group member records for group {syncInfo.GroupName}"); int addedCount = 0; int notAddedCount = 0; foreach (var personId in targetPersonIdsToAdd) { if ((addedCount + notAddedCount) % 100 == 0) { string notAddedMessage = string.Empty; if (notAddedCount > 0) { notAddedMessage = $"{Environment.NewLine} There are {notAddedCount} members that could not be added due to group requirements."; } context.UpdateLastStatusMessage($"Added {addedCount} of {targetPersonIdsToAdd.Count()} group member records for group {syncInfo.GroupName}. {notAddedMessage}"); } try { // Use a new context to limit the amount of change-tracking required using (var groupMemberContext = new RockContext()) { var groupMemberService = new GroupMemberService(groupMemberContext); var groupService = new GroupService(groupMemberContext); // If this person is currently archived... if (archivedTargetPersonIds.Contains(personId)) { // ...then we'll just restore them; GroupMember archivedGroupMember = groupService.GetArchivedGroupMember(sync.Group, personId, sync.GroupTypeRoleId); if (archivedGroupMember == null) { // shouldn't happen, but just in case continue; } archivedGroupMember.GroupMemberStatus = GroupMemberStatus.Active; if (archivedGroupMember.IsValidGroupMember(groupMemberContext)) { addedCount++; groupMemberService.Restore(archivedGroupMember); groupMemberContext.SaveChanges(); } else { notAddedCount++; // Validation errors will get added to the ValidationResults collection. Add those results to the log and then move on to the next person. var ex = new GroupMemberValidationException(string.Join(",", archivedGroupMember.ValidationResults.Select(r => r.ErrorMessage).ToArray())); ExceptionLogService.LogException(ex); continue; } } else { // ...otherwise we will add a new person to the group with the role specified in the sync. var newGroupMember = new GroupMember { Id = 0 }; newGroupMember.PersonId = personId; newGroupMember.GroupId = sync.GroupId; newGroupMember.GroupMemberStatus = GroupMemberStatus.Active; newGroupMember.GroupRoleId = sync.GroupTypeRoleId; if (newGroupMember.IsValidGroupMember(groupMemberContext)) { addedCount++; groupMemberService.Add(newGroupMember); groupMemberContext.SaveChanges(); } else { notAddedCount++; // Validation errors will get added to the ValidationResults collection. Add those results to the log and then move on to the next person. var ex = new GroupMemberValidationException(string.Join(",", newGroupMember.ValidationResults.Select(r => r.ErrorMessage).ToArray())); ExceptionLogService.LogException(ex); continue; } } // If the Group has a welcome email, and person has an email address, send them the welcome email and possibly create a login if (sync.WelcomeSystemCommunication != null) { var person = new PersonService(groupMemberContext).Get(personId); if (person.CanReceiveEmail(false)) { // If the group is configured to add a user account for anyone added to the group, and person does not yet have an // account, add one for them. string newPassword = string.Empty; bool createLogin = sync.AddUserAccountsDuringSync; // Only create a login if requested, no logins exist and we have enough information to generate a user name. if (createLogin && !person.Users.Any() && !string.IsNullOrWhiteSpace(person.NickName) && !string.IsNullOrWhiteSpace(person.LastName)) { newPassword = System.Web.Security.Membership.GeneratePassword(9, 1); string username = Rock.Security.Authentication.Database.GenerateUsername(person.NickName, person.LastName); UserLogin login = UserLoginService.Create( groupMemberContext, person, AuthenticationServiceType.Internal, EntityTypeCache.Get(Rock.SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid()).Id, username, newPassword, true, requirePasswordReset); } // Send the welcome email var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Group", sync.Group); mergeFields.Add("Person", person); mergeFields.Add("NewPassword", newPassword); mergeFields.Add("CreateLogin", createLogin); var emailMessage = new RockEmailMessage(sync.WelcomeSystemCommunication); emailMessage.AddRecipient(new RockEmailMessageRecipient(person, mergeFields)); var emailErrors = new List <string>(); emailMessage.Send(out emailErrors); errors.AddRange(emailErrors); } } } } catch (Exception ex) { ExceptionLogService.LogException(ex); continue; } hasSyncChanged = true; } // Increment Groups Changed Counter (if people were deleted or added to the group) if (hasSyncChanged) { groupsChanged++; } // Increment the Groups Synced Counter groupsSynced++; } // Update last refresh datetime in different context to avoid side-effects. using (var rockContext = new RockContext()) { var sync = new GroupSyncService(rockContext) .Queryable() .FirstOrDefault(s => s.Id == syncId); sync.LastRefreshDateTime = RockDateTime.Now; rockContext.SaveChanges(); } } // Format the result message var resultMessage = string.Empty; if (groupsSynced == 0) { resultMessage = "No groups to sync"; } else if (groupsSynced == 1) { resultMessage = "1 group was synced"; } else { resultMessage = string.Format("{0} groups were synced", groupsSynced); } resultMessage += string.Format(" and {0} groups were changed", groupsChanged); if (errors.Any()) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.Append("Errors: "); errors.ForEach(e => { sb.AppendLine(); sb.Append(e); }); string errorMessage = sb.ToString(); resultMessage += errorMessage; throw new Exception(errorMessage); } context.Result = resultMessage; } catch (System.Exception ex) { HttpContext context2 = HttpContext.Current; ExceptionLogService.LogException(ex, context2); throw; } }
/// <summary> /// Job that will sync groups. /// /// Called by the <see cref="IScheduler" /> when a /// <see cref="ITrigger" /> fires that is associated with /// the <see cref="IJob" />. /// </summary> public virtual void Execute(IJobExecutionContext context) { // Get the job setting(s) JobDataMap dataMap = context.JobDetail.JobDataMap; bool requirePasswordReset = dataMap.GetBoolean("RequirePasswordReset"); var commandTimeout = dataMap.GetString("CommandTimeout").AsIntegerOrNull() ?? 180; // Counters for displaying results int groupsSynced = 0; int groupsChanged = 0; string groupName = string.Empty; string dataViewName = string.Empty; var errors = new List <string>(); try { // get groups set to sync var activeSyncIds = new List <int>(); using (var rockContext = new RockContext()) { // Get groups that are not archived and are still active. activeSyncIds = new GroupSyncService(rockContext) .Queryable().AsNoTracking() .Where(x => !x.Group.IsArchived && x.Group.IsActive) .Select(x => x.Id) .ToList(); } foreach (var syncId in activeSyncIds) { bool hasSyncChanged = false; // Use a fresh rockContext per sync so that ChangeTracker doesn't get bogged down using (var rockContext = new RockContext()) { // increase the timeout just in case the data view source is slow rockContext.Database.CommandTimeout = commandTimeout; rockContext.SourceOfChange = "Group Sync"; // Get the Sync var sync = new GroupSyncService(rockContext) .Queryable().AsNoTracking() .FirstOrDefault(s => s.Id == syncId); // Ensure that the group's Sync Data View is a person data view if (sync != null && sync.SyncDataView.EntityTypeId == EntityTypeCache.Get(typeof(Person)).Id) { List <string> syncErrors = new List <string>(); dataViewName = sync.SyncDataView.Name; groupName = sync.Group.Name; // Get the person id's from the data view (source) var personService = new PersonService(rockContext); var sourcePersonIds = sync.SyncDataView.GetQuery(null, rockContext, commandTimeout, out syncErrors) .Select(q => q.Id).ToList(); // If any error occurred trying get the 'where expression' from the sync-data-view, // just skip trying to sync that particular group's Sync Data View for now. if (syncErrors.Count > 0) { errors.AddRange(syncErrors); ExceptionLogService.LogException(new Exception(string.Format("An error occurred while trying to GroupSync group '{0}' and data view '{1}' so the sync was skipped. Error: {2}", groupName, dataViewName, String.Join(",", syncErrors)))); continue; } // Get the person id's in the group (target) for the role being synced. // Note: targetPersonIds must include archived group members // so we don't try to delete anyone who's already archived, and // it must include deceased members so we can remove them if they // are no longer in the data view. var targetPersonIds = new GroupMemberService(rockContext) .Queryable(true, true).AsNoTracking() .Where(gm => gm.GroupId == sync.GroupId) .Where(gm => gm.GroupRoleId == sync.GroupTypeRoleId) .Select(gm => new { PersonId = gm.PersonId, IsArchived = gm.IsArchived }) .ToList(); // Delete people from the group/role that are no longer in the data view -- // but not the ones that are already archived. foreach (var targetPerson in targetPersonIds.Where(t => !sourcePersonIds.Contains(t.PersonId) && t.IsArchived != true)) { try { // Use a new context to limit the amount of change-tracking required using (var groupMemberContext = new RockContext()) { // Delete the records for that person's group and role var groupMemberService = new GroupMemberService(groupMemberContext); foreach (var groupMember in groupMemberService .Queryable(true, true) .Where(m => m.GroupId == sync.GroupId && m.GroupRoleId == sync.GroupTypeRoleId && m.PersonId == targetPerson.PersonId) .ToList()) { groupMemberService.Delete(groupMember); } groupMemberContext.SaveChanges(); // If the Group has an exit email, and person has an email address, send them the exit email if (sync.ExitSystemEmail != null) { var person = new PersonService(groupMemberContext).Get(targetPerson.PersonId); if (person.Email.IsNotNullOrWhiteSpace()) { // Send the exit email var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Group", sync.Group); mergeFields.Add("Person", person); var emailMessage = new RockEmailMessage(sync.ExitSystemEmail); emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields)); var emailErrors = new List <string>(); emailMessage.Send(out emailErrors); errors.AddRange(emailErrors); } } } } catch (Exception ex) { ExceptionLogService.LogException(ex); continue; } hasSyncChanged = true; } // Now find all the people in the source list who are NOT already in the target list // or in the target list as archived (so we can restore them). foreach (var personId in sourcePersonIds.Where(s => !targetPersonIds.Any(t => t.PersonId == s) || targetPersonIds.Any(t => t.PersonId == s && t.IsArchived))) { try { // Use a new context to limit the amount of change-tracking required using (var groupMemberContext = new RockContext()) { var groupMemberService = new GroupMemberService(groupMemberContext); // If this person is currently archived... if (targetPersonIds.Any(t => t.PersonId == personId && t.IsArchived == true)) { // ...then we'll just restore them; // NOTE: AddOrRestoreGroupMember will find the exact group member record and // sets their IsArchived back to false. var newGroupMember = groupMemberService.AddOrRestoreGroupMember(sync.Group, personId, sync.GroupTypeRoleId); newGroupMember.GroupMemberStatus = GroupMemberStatus.Active; groupMemberContext.SaveChanges(); } else { // ...otherwise we will add a new person to the group with the role specified in the sync. var newGroupMember = new GroupMember { Id = 0 }; newGroupMember.PersonId = personId; newGroupMember.GroupId = sync.GroupId; newGroupMember.GroupMemberStatus = GroupMemberStatus.Active; newGroupMember.GroupRoleId = sync.GroupTypeRoleId; if (newGroupMember.IsValidGroupMember(groupMemberContext)) { groupMemberService.Add(newGroupMember); groupMemberContext.SaveChanges(); } else { // Validation errors will get added to the ValidationResults collection. Add those results to the log and then move on to the next person. var ex = new GroupMemberValidationException(string.Join(",", newGroupMember.ValidationResults.Select(r => r.ErrorMessage).ToArray())); ExceptionLogService.LogException(ex); continue; } } // If the Group has a welcome email, and person has an email address, send them the welcome email and possibly create a login if (sync.WelcomeSystemEmail != null) { var person = new PersonService(groupMemberContext).Get(personId); if (person.Email.IsNotNullOrWhiteSpace()) { // If the group is configured to add a user account for anyone added to the group, and person does not yet have an // account, add one for them. string newPassword = string.Empty; bool createLogin = sync.AddUserAccountsDuringSync; // Only create a login if requested, no logins exist and we have enough information to generate a user name. if (createLogin && !person.Users.Any() && !string.IsNullOrWhiteSpace(person.NickName) && !string.IsNullOrWhiteSpace(person.LastName)) { newPassword = System.Web.Security.Membership.GeneratePassword(9, 1); string username = Rock.Security.Authentication.Database.GenerateUsername(person.NickName, person.LastName); UserLogin login = UserLoginService.Create( groupMemberContext, person, AuthenticationServiceType.Internal, EntityTypeCache.Get(Rock.SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid()).Id, username, newPassword, true, requirePasswordReset); } // Send the welcome email var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Group", sync.Group); mergeFields.Add("Person", person); mergeFields.Add("NewPassword", newPassword); mergeFields.Add("CreateLogin", createLogin); var emailMessage = new RockEmailMessage(sync.WelcomeSystemEmail); emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields)); var emailErrors = new List <string>(); emailMessage.Send(out emailErrors); errors.AddRange(emailErrors); } } } } catch (Exception ex) { ExceptionLogService.LogException(ex); continue; } hasSyncChanged = true; } // Increment Groups Changed Counter (if people were deleted or added to the group) if (hasSyncChanged) { groupsChanged++; } // Increment the Groups Synced Counter groupsSynced++; } } } // Format the result message var resultMessage = string.Empty; if (groupsSynced == 0) { resultMessage = "No groups to sync"; } else if (groupsSynced == 1) { resultMessage = "1 group was synced"; } else { resultMessage = string.Format("{0} groups were synced", groupsSynced); } resultMessage += string.Format(" and {0} groups were changed", groupsChanged); if (errors.Any()) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.Append("Errors: "); errors.ForEach(e => { sb.AppendLine(); sb.Append(e); }); string errorMessage = sb.ToString(); resultMessage += errorMessage; throw new Exception(errorMessage); } context.Result = resultMessage; } catch (System.Exception ex) { HttpContext context2 = HttpContext.Current; ExceptionLogService.LogException(ex, context2); throw; } }
/// <summary> /// Saves the changes. /// </summary> /// <param name="item">The item.</param> protected void SaveChanges(RepeaterItem item) { var hfGroupId = item.FindControl("hfGroupId") as HiddenField; var cbCommunicationListIsSubscribed = item.FindControl("cbCommunicationListIsSubscribed") as RockCheckBox; var tglCommunicationPreference = item.FindControl("tglCommunicationPreference") as Toggle; var nbGroupNotification = item.FindControl("nbGroupNotification") as NotificationBox; nbGroupNotification.Visible = false; using (var rockContext = new RockContext()) { int groupId = hfGroupId.Value.AsInteger(); var groupMemberService = new GroupMemberService(rockContext); var group = new GroupService(rockContext).Get(groupId); var groupMemberRecordsForPerson = groupMemberService.Queryable().Where(a => a.GroupId == groupId && a.PersonId == this.CurrentPersonId).ToList(); if (groupMemberRecordsForPerson.Any()) { // normally there would be at most 1 group member record for the person, but just in case, mark them all foreach (var groupMember in groupMemberRecordsForPerson) { if (cbCommunicationListIsSubscribed.Checked) { if (groupMember.GroupMemberStatus == GroupMemberStatus.Inactive) { groupMember.GroupMemberStatus = GroupMemberStatus.Active; if (groupMember.Note == "Unsubscribed") { groupMember.Note = string.Empty; } } } else { if (groupMember.GroupMemberStatus == GroupMemberStatus.Active) { groupMember.GroupMemberStatus = GroupMemberStatus.Inactive; if (groupMember.Note.IsNullOrWhiteSpace()) { groupMember.Note = "Unsubscribed"; } } } groupMember.LoadAttributes(); CommunicationType communicationType = tglCommunicationPreference.Checked ? CommunicationType.Email : CommunicationType.SMS; groupMember.SetAttributeValue("PreferredCommunicationMedium", communicationType.ConvertToInt().ToString()); groupMember.SaveAttributeValue("PreferredCommunicationMedium", rockContext); } } else { // they are not currently in the Group if (cbCommunicationListIsSubscribed.Checked) { var groupMember = new GroupMember(); groupMember.PersonId = this.CurrentPersonId.Value; groupMember.GroupId = group.Id; int?defaultGroupRoleId = GroupTypeCache.Get(group.GroupTypeId).DefaultGroupRoleId; if (defaultGroupRoleId.HasValue) { groupMember.GroupRoleId = defaultGroupRoleId.Value; } else { nbGroupNotification.Text = "Unable to add to group."; nbGroupNotification.Details = "Group has no default group role"; nbGroupNotification.NotificationBoxType = NotificationBoxType.Danger; nbGroupNotification.Visible = true; } groupMember.GroupMemberStatus = GroupMemberStatus.Active; groupMember.LoadAttributes(); CommunicationType communicationType = tglCommunicationPreference.Checked ? CommunicationType.Email : CommunicationType.SMS; groupMember.SetAttributeValue("PreferredCommunicationMedium", communicationType.ConvertToInt().ToString()); if (groupMember.IsValidGroupMember(rockContext)) { groupMemberService.Add(groupMember); rockContext.SaveChanges(); groupMember.SaveAttributeValue("PreferredCommunicationMedium", rockContext); } else { // if the group member couldn't be added (for example, one of the group membership rules didn't pass), add the validation messages to the errormessages nbGroupNotification.Text = "Unable to add to group."; nbGroupNotification.Details = groupMember.ValidationResults.Select(a => a.ErrorMessage).ToList().AsDelimited("<br />"); nbGroupNotification.NotificationBoxType = NotificationBoxType.Danger; nbGroupNotification.Visible = true; } } } rockContext.SaveChanges(); } }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages) { errorMessages = new List <string>(); // Determine which group to add the person to Group group = null; int? groupRoleId = null; var groupAndRoleValues = (GetAttributeValue(action, "GroupAndRole") ?? string.Empty).Split('|'); if (groupAndRoleValues.Count() > 1) { var groupGuid = groupAndRoleValues[1].AsGuidOrNull(); if (groupGuid.HasValue) { group = new GroupService(rockContext).Get(groupGuid.Value); if (groupAndRoleValues.Count() > 2) { var groupTypeRoleGuid = groupAndRoleValues[2].AsGuidOrNull(); if (groupTypeRoleGuid.HasValue) { var groupRole = new GroupTypeRoleService(rockContext).Get(groupTypeRoleGuid.Value); if (groupRole != null) { groupRoleId = groupRole.Id; } } } if (!groupRoleId.HasValue && group != null) { // use the group's grouptype's default group role if a group role wasn't specified groupRoleId = group.GroupType.DefaultGroupRoleId; } } } if (group == null) { errorMessages.Add("No group was provided"); } if (!groupRoleId.HasValue) { errorMessages.Add("No group role was provided and group doesn't have a default group role"); } // determine the person that will be added to the group Person person = null; // get the Attribute.Guid for this workflow's Person Attribute so that we can lookup the value var guidPersonAttribute = GetAttributeValue(action, "Person").AsGuidOrNull(); if (guidPersonAttribute.HasValue) { var attributePerson = AttributeCache.Read(guidPersonAttribute.Value, rockContext); if (attributePerson != null) { string attributePersonValue = action.GetWorklowAttributeValue(guidPersonAttribute.Value); if (!string.IsNullOrWhiteSpace(attributePersonValue)) { if (attributePerson.FieldType.Class == typeof(Rock.Field.Types.PersonFieldType).FullName) { Guid personAliasGuid = attributePersonValue.AsGuid(); if (!personAliasGuid.IsEmpty()) { person = new PersonAliasService(rockContext).Queryable() .Where(a => a.Guid.Equals(personAliasGuid)) .Select(a => a.Person) .FirstOrDefault(); } } else { errorMessages.Add("The attribute used to provide the person was not of type 'Person'."); } } } } if (person == null) { errorMessages.Add(string.Format("Person could not be found for selected value ('{0}')!", guidPersonAttribute.ToString())); } // Add Person to Group if (!errorMessages.Any()) { var groupMemberService = new GroupMemberService(rockContext); var groupMember = new GroupMember(); groupMember.PersonId = person.Id; groupMember.GroupId = group.Id; groupMember.GroupRoleId = groupRoleId.Value; groupMember.GroupMemberStatus = this.GetAttributeValue(action, "GroupMemberStatus").ConvertToEnum <GroupMemberStatus>(GroupMemberStatus.Active); if (groupMember.IsValidGroupMember(rockContext)) { groupMemberService.Add(groupMember); rockContext.SaveChanges(); if (group.IsSecurityRole || group.GroupType.Guid.Equals(Rock.SystemGuid.GroupType.GROUPTYPE_SECURITY_ROLE.AsGuid())) { Rock.Security.Role.Flush(group.Id); } } else { // if the group member couldn't be added (for example, one of the group membership rules didn't pass), add the validation messages to the errormessages errorMessages.AddRange(groupMember.ValidationResults.Select(a => a.ErrorMessage)); } } errorMessages.ForEach(m => action.AddLogEntry(m, true)); return(true); }
public void UpdateSubscription(Guid communicationListGuid, bool subscribed) { using (var rockContext = new RockContext()) { var groupMemberService = new GroupMemberService(rockContext); var group = new GroupService(rockContext).Get(communicationListGuid); var groupMemberRecordsForPerson = groupMemberService.Queryable() .Where(a => a.GroupId == group.Id && a.PersonId == RequestContext.CurrentPerson.Id) .ToList(); if (groupMemberRecordsForPerson.Any()) { // normally there would be at most 1 group member record for the person, but just in case, mark them all foreach (var groupMember in groupMemberRecordsForPerson) { if (subscribed) { if (groupMember.GroupMemberStatus == GroupMemberStatus.Inactive) { groupMember.GroupMemberStatus = GroupMemberStatus.Active; if (groupMember.Note == "Unsubscribed") { groupMember.Note = string.Empty; } } } else { if (groupMember.GroupMemberStatus == GroupMemberStatus.Active) { groupMember.GroupMemberStatus = GroupMemberStatus.Inactive; if (groupMember.Note.IsNullOrWhiteSpace()) { groupMember.Note = "Unsubscribed"; } } } // TODO: Change this to null. groupMember.CommunicationPreference = CommunicationType.Email; } } else if (subscribed) { var groupMember = new GroupMember { PersonId = RequestContext.CurrentPerson.Id, GroupId = group.Id }; int?defaultGroupRoleId = GroupTypeCache.Get(group.GroupTypeId).DefaultGroupRoleId; if (defaultGroupRoleId.HasValue) { groupMember.GroupRoleId = defaultGroupRoleId.Value; } groupMember.GroupMemberStatus = GroupMemberStatus.Active; if (groupMember.IsValidGroupMember(rockContext)) { groupMemberService.Add(groupMember); rockContext.SaveChanges(); } } rockContext.SaveChanges(); } }