Exemple #1
0
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid()
        {
            var rockContext = new RockContext();

            int groupId           = hfGroupId.Value.AsInteger();
            var groupMembersQuery = new GroupMemberService(rockContext).Queryable().Where(a => a.GroupId == groupId);
            var group             = new GroupService(rockContext).Get(groupId);

            group.LoadAttributes(rockContext);
            var defaultIndividualFundRaisingGoal = group.GetAttributeValue("IndividualFundraisingGoal").AsDecimalOrNull();

            groupMembersQuery = groupMembersQuery.Sort(gGroupMembers.SortProperty ?? new SortProperty {
                Property = "Person.LastName, Person.NickName"
            });

            var entityTypeIdGroupMember = EntityTypeCache.GetId <Rock.Model.GroupMember>();

            var groupMemberList = groupMembersQuery.ToList().Select(a =>
            {
                var groupMember = a;
                groupMember.LoadAttributes(rockContext);

                var contributionTotal = new FinancialTransactionDetailService(rockContext).Queryable()
                                        .Where(d => d.EntityTypeId == entityTypeIdGroupMember &&
                                               d.EntityId == groupMember.Id)
                                        .Sum(d => (decimal?)d.Amount) ?? 0.00M;

                var individualFundraisingGoal          = groupMember.GetAttributeValue("IndividualFundraisingGoal").AsDecimalOrNull();
                bool disablePublicContributionRequests = groupMember.GetAttributeValue("DisablePublicContributionRequests").AsBoolean();
                if (!individualFundraisingGoal.HasValue)
                {
                    individualFundraisingGoal = group.GetAttributeValue("IndividualFundraisingGoal").AsDecimalOrNull();
                }

                var fundingRemaining = individualFundraisingGoal - contributionTotal;
                if (disablePublicContributionRequests)
                {
                    fundingRemaining = null;
                }
                else if (fundingRemaining < 0)
                {
                    fundingRemaining = 0.00M;
                }

                return(new
                {
                    groupMember.Id,
                    PersonId = groupMember.PersonId,
                    DateTimeAdded = groupMember.DateTimeAdded,
                    groupMember.Person.FullName,
                    groupMember.Person.Gender,
                    FundingRemaining = fundingRemaining,
                    GroupRoleName = a.GroupRole.Name
                });
            }).ToList();

            gGroupMembers.DataSource = groupMemberList;
            gGroupMembers.DataBind();
        }
        /// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="serviceInstance">The service instance.</param>
        /// <param name="parameterExpression">The parameter expression.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override Expression GetExpression(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, string selection)
        {
            if (selection.IsNotNullOrWhiteSpace())
            {
                var ebPersonFieldType = FieldTypeCache.Get(EBGuid.FieldType.EVENTBRITE_PERSON.AsGuid());
                var ebPersonAttribute = new AttributeService(( RockContext )serviceInstance.Context).GetByFieldTypeId(ebPersonFieldType.Id).FirstOrDefault();

                if (ebPersonAttribute != null)
                {
                    var qry = new GroupMemberService(( RockContext )serviceInstance.Context).Queryable()
                              .WhereAttributeValue(( RockContext )serviceInstance.Context, a => a.Attribute.Key == ebPersonAttribute.Key && a.Value != null && a.Value != "" && a.Value.Contains("^"));

                    var groupMemberIds = new List <int>();
                    foreach (var groupMember in qry.ToList())
                    {
                        if (groupMember.Attributes == null)
                        {
                            groupMember.LoadAttributes();
                        }
                        var attributeVal = groupMember.GetAttributeValue(ebPersonAttribute.Key);
                        if (attributeVal.IsNotNullOrWhiteSpace())
                        {
                            var containsValue = attributeVal.Split(new char[] { '^' })[1].Split(new string[] { "||" }, StringSplitOptions.RemoveEmptyEntries).Contains(selection);
                            if (containsValue)
                            {
                                groupMemberIds.Add(groupMember.Id);
                            }
                        }
                    }
                    qry = qry.Where(gm => groupMemberIds.Contains(gm.Id));

                    Expression extractedFilterExpression = FilterExpressionExtractor.Extract <Rock.Model.GroupMember>(qry, parameterExpression, "gm");

                    return(extractedFilterExpression);
                }
            }

            return(null);
        }
        /// <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)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            try
            {
                int notificationsSent   = 0;
                int errorsEncountered   = 0;
                int pendingMembersCount = 0;

                // get groups set to sync
                RockContext rockContext = new RockContext();

                Guid?groupTypeGuid       = dataMap.GetString("GroupType").AsGuidOrNull();
                Guid?systemEmailGuid     = dataMap.GetString("NotificationEmail").AsGuidOrNull();
                Guid?groupRoleFilterGuid = dataMap.GetString("GroupRoleFilter").AsGuidOrNull();
                int? pendingAge          = dataMap.GetString("PendingAge").AsIntegerOrNull();


                bool includePreviouslyNotificed = dataMap.GetString("IncludePreviouslyNotified").AsBoolean();

                // get system email
                SystemEmailService emailService = new SystemEmailService(rockContext);

                SystemEmail systemEmail = null;
                if (!systemEmailGuid.HasValue || systemEmailGuid == Guid.Empty)
                {
                    context.Result = "Job failed. Unable to find System Email";
                    throw new Exception("No system email found.");
                }

                systemEmail = emailService.Get(systemEmailGuid.Value);

                // get group members
                if (!groupTypeGuid.HasValue || groupTypeGuid == Guid.Empty)
                {
                    context.Result = "Job failed. Unable to find group type";
                    throw new Exception("No group type found");
                }

                var qry = new GroupMemberService(rockContext).Queryable("Person, Group, Group.Members.GroupRole")
                          .Where(m => m.Group.GroupType.Guid == groupTypeGuid.Value &&
                                 m.GroupMemberStatus == GroupMemberStatus.Pending);

                if (!includePreviouslyNotificed)
                {
                    qry = qry.Where(m => m.IsNotified == false);
                }

                if (groupRoleFilterGuid.HasValue)
                {
                    qry = qry.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value);
                }

                if (pendingAge.HasValue && pendingAge.Value > 0)
                {
                    var ageDate = RockDateTime.Now.AddDays(pendingAge.Value * -1);
                    qry = qry.Where(m => m.ModifiedDateTime > ageDate);
                }

                var pendingGroupMembers = qry.ToList();

                var groups = pendingGroupMembers.GroupBy(m => m.Group);

                var errorList = new List <string>();
                foreach (var groupKey in groups)
                {
                    var group = groupKey.Key;

                    // get list of pending people
                    var qryPendingIndividuals = group.Members.Where(m => m.GroupMemberStatus == GroupMemberStatus.Pending);

                    if (!includePreviouslyNotificed)
                    {
                        qryPendingIndividuals = qryPendingIndividuals.Where(m => m.IsNotified == false);
                    }

                    if (groupRoleFilterGuid.HasValue)
                    {
                        qryPendingIndividuals = qryPendingIndividuals.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value);
                    }

                    var pendingIndividuals = qryPendingIndividuals.Select(m => m.Person).ToList();

                    if (!pendingIndividuals.Any())
                    {
                        continue;
                    }

                    // get list of leaders
                    var groupLeaders = group.Members.Where(m => m.GroupRole.IsLeader == true && m.Person != null && m.Person.Email != null && m.Person.Email != string.Empty);

                    if (!groupLeaders.Any())
                    {
                        errorList.Add("Unable to send emails to members in group " + group.Name + " because there is no group leader");
                        continue;
                    }

                    var recipients = new List <RecipientData>();
                    foreach (var leader in groupLeaders)
                    {
                        // create merge object
                        var mergeFields = new Dictionary <string, object>();
                        mergeFields.Add("PendingIndividuals", pendingIndividuals);
                        mergeFields.Add("Group", group);
                        mergeFields.Add("ParentGroup", group.ParentGroup);
                        mergeFields.Add("Person", leader.Person);
                        recipients.Add(new RecipientData(leader.Person.Email, mergeFields));
                    }


                    var errorMessages = new List <string>();
                    var emailMessage  = new RockEmailMessage(systemEmail.Guid);
                    emailMessage.SetRecipients(recipients);
                    emailMessage.Send(out errorMessages);

                    errorsEncountered += errorMessages.Count;
                    errorList.AddRange(errorMessages);

                    // be conservative: only mark as notified if we are sure the email didn't fail
                    if (errorMessages.Any())
                    {
                        continue;
                    }

                    notificationsSent += recipients.Count();
                    // mark pending members as notified as we go in case the job fails
                    var notifiedPersonIds = pendingIndividuals.Select(p => p.Id);
                    foreach (var pendingGroupMember in pendingGroupMembers.Where(m => m.IsNotified == false && notifiedPersonIds.Contains(m.PersonId)))
                    {
                        pendingGroupMember.IsNotified = true;
                    }

                    rockContext.SaveChanges();
                }

                context.Result = string.Format("Sent {0} emails to leaders for {1} pending individuals. {2} errors encountered.", notificationsSent, pendingMembersCount, errorsEncountered);
                if (errorList.Any())
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine();
                    sb.Append("Errors: ");
                    errorList.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                    string errors = sb.ToString();
                    context.Result += errors;
                    throw new Exception(errors);
                }
            }
            catch (Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
                throw;
            }
        }
Exemple #4
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var errors      = new List <string>();
            var rockContext = new RockContext();

            JobDataMap dataMap         = context.JobDetail.JobDataMap;
            Guid?      systemEmailGuid = dataMap.GetString("NotificationEmailTemplate").AsGuidOrNull();

            if (systemEmailGuid.HasValue)
            {
                var selectedGroupTypes = new List <Guid>();
                if (!string.IsNullOrWhiteSpace(dataMap.GetString("GroupTypes")))
                {
                    selectedGroupTypes = dataMap.GetString("GroupTypes").Split(',').Select(Guid.Parse).ToList();
                }

                var notificationOption = dataMap.GetString("NotifyParentLeaders").ConvertToEnum <NotificationOption>(NotificationOption.None);

                var accountAbilityGroupGuid = dataMap.GetString("AccountabilityGroup").AsGuid();

                var groupRequirementsQry = new GroupRequirementService(rockContext).Queryable();


                // get groups matching of the types provided
                GroupService groupService = new GroupService(rockContext);
                var          groups       = groupService.Queryable().AsNoTracking()
                                            .Where(g => selectedGroupTypes.Contains(g.GroupType.Guid) &&
                                                   g.IsActive == true &&
                                                   groupRequirementsQry.Any(a => (a.GroupId.HasValue && a.GroupId == g.Id) || (a.GroupTypeId.HasValue && a.GroupTypeId == g.GroupTypeId)));

                foreach (var group in groups)
                {
                    // check for members that don't meet requirements
                    var groupMembersWithIssues = groupService.GroupMembersNotMeetingRequirements(group, true);

                    if (groupMembersWithIssues.Count > 0)
                    {
                        // add issues to issue list
                        GroupsMissingRequirements groupMissingRequirements = new GroupsMissingRequirements();
                        groupMissingRequirements.Id   = group.Id;
                        groupMissingRequirements.Name = group.Name;
                        if (group.GroupType != null)
                        {
                            groupMissingRequirements.GroupTypeId   = group.GroupTypeId;
                            groupMissingRequirements.GroupTypeName = group.GroupType.Name;
                        }
                        groupMissingRequirements.AncestorPathName = groupService.GroupAncestorPathName(group.Id);

                        // get list of the group leaders
                        groupMissingRequirements.Leaders = group.Members
                                                           .Where(m => m.GroupRole.ReceiveRequirementsNotifications)
                                                           .Select(m => new GroupMemberResult
                        {
                            Id       = m.Id,
                            PersonId = m.PersonId,
                            FullName = m.Person.FullName
                        })
                                                           .ToList();


                        List <GroupMembersMissingRequirements> groupMembers = new List <GroupMembersMissingRequirements>();

                        foreach (var groupMemberIssue in groupMembersWithIssues)
                        {
                            GroupMembersMissingRequirements groupMember = new GroupMembersMissingRequirements();
                            groupMember.FullName        = groupMemberIssue.Key.Person.FullName;
                            groupMember.Id              = groupMemberIssue.Key.Id;
                            groupMember.PersonId        = groupMemberIssue.Key.PersonId;
                            groupMember.GroupMemberRole = groupMemberIssue.Key.GroupRole.Name;

                            List <MissingRequirement> missingRequirements = new List <MissingRequirement>();
                            foreach (var issue in groupMemberIssue.Value)
                            {
                                MissingRequirement missingRequirement = new MissingRequirement();
                                missingRequirement.Id             = issue.Key.GroupRequirement.GroupRequirementType.Id;
                                missingRequirement.Name           = issue.Key.GroupRequirement.GroupRequirementType.Name;
                                missingRequirement.Status         = issue.Key.MeetsGroupRequirement;
                                missingRequirement.OccurrenceDate = issue.Value;

                                switch (issue.Key.MeetsGroupRequirement)
                                {
                                case MeetsGroupRequirement.Meets:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.PositiveLabel;
                                    break;

                                case MeetsGroupRequirement.MeetsWithWarning:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.WarningLabel;
                                    break;

                                case MeetsGroupRequirement.NotMet:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.NegativeLabel;
                                    break;
                                }

                                missingRequirements.Add(missingRequirement);
                            }

                            groupMember.MissingRequirements = missingRequirements;

                            groupMembers.Add(groupMember);
                        }
                        groupMissingRequirements.GroupMembersMissingRequirements = groupMembers;

                        _groupsMissingRequriements.Add(groupMissingRequirements);

                        // add leaders as people to notify
                        foreach (var leader in group.Members.Where(m => m.GroupRole.ReceiveRequirementsNotifications))
                        {
                            NotificationItem notification = new NotificationItem();
                            notification.GroupId = group.Id;
                            notification.Person  = leader.Person;
                            _notificationList.Add(notification);
                        }

                        // notify parents
                        if (notificationOption != NotificationOption.None)
                        {
                            var parentLeaders = new GroupMemberService(rockContext).Queryable("Person").AsNoTracking()
                                                .Where(m => m.GroupRole.ReceiveRequirementsNotifications);

                            if (notificationOption == NotificationOption.DirectParent)
                            {
                                // just the parent group
                                parentLeaders = parentLeaders.Where(m => m.GroupId == group.ParentGroupId);
                            }
                            else
                            {
                                // all parents in the hierarchy
                                var parentIds = groupService.GetAllAncestorIds(group.Id);
                                parentLeaders = parentLeaders.Where(m => parentIds.Contains(m.GroupId));
                            }

                            foreach (var parentLeader in parentLeaders.ToList())
                            {
                                NotificationItem parentNotification = new NotificationItem();
                                parentNotification.Person  = parentLeader.Person;
                                parentNotification.GroupId = group.Id;
                                _notificationList.Add(parentNotification);
                            }
                        }
                    }
                }

                // send out notifications
                int recipients             = 0;
                var notificationRecipients = _notificationList.GroupBy(p => p.Person.Id).ToList();
                foreach (var recipientId in notificationRecipients)
                {
                    var recipient = _notificationList.Where(n => n.Person.Id == recipientId.Key).Select(n => n.Person).FirstOrDefault();

                    if (!recipient.IsEmailActive || recipient.Email.IsNullOrWhiteSpace() || recipient.EmailPreference == EmailPreference.DoNotEmail)
                    {
                        continue;
                    }

                    var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);
                    mergeFields.Add("Person", recipient);
                    var notificationGroupIds = _notificationList
                                               .Where(n => n.Person.Id == recipient.Id)
                                               .Select(n => n.GroupId)
                                               .ToList();
                    var missingRequirements = _groupsMissingRequriements.Where(g => notificationGroupIds.Contains(g.Id)).ToList();
                    mergeFields.Add("GroupsMissingRequirements", missingRequirements);

                    var emailMessage = new RockEmailMessage(systemEmailGuid.Value);
                    emailMessage.AddRecipient(new RecipientData(recipient.Email, mergeFields));
                    var emailErrors = new List <string>();
                    emailMessage.Send(out emailErrors);
                    errors.AddRange(emailErrors);

                    recipients++;
                }

                // add accountability group members
                if (!accountAbilityGroupGuid.IsEmpty())
                {
                    var accountabilityGroupMembers = new GroupMemberService(rockContext).Queryable().AsNoTracking()
                                                     .Where(m => m.Group.Guid == accountAbilityGroupGuid)
                                                     .Select(m => m.Person);

                    var emailMessage = new RockEmailMessage(systemEmailGuid.Value);
                    foreach (var person in accountabilityGroupMembers)
                    {
                        var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);
                        mergeFields.Add("Person", person);
                        mergeFields.Add("GroupsMissingRequirements", _groupsMissingRequriements);
                        emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields));
                        recipients++;
                    }
                    var emailErrors = new List <string>();
                    emailMessage.Send(out emailErrors);
                    errors.AddRange(emailErrors);
                }

                context.Result = string.Format("{0} requirement notification {1} sent", recipients, "email".PluralizeIf(recipients != 1));

                if (errors.Any())
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine();
                    sb.Append(string.Format("{0} Errors: ", errors.Count()));
                    errors.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                    string errorMessage = sb.ToString();
                    context.Result += errorMessage;
                    var         exception = new Exception(errorMessage);
                    HttpContext context2  = HttpContext.Current;
                    ExceptionLogService.LogException(exception, context2);
                    throw exception;
                }
            }
            else
            {
                context.Result = "Warning: No NotificationEmailTemplate found";
            }
        }
        private void ListGroups()
        {
            RockContext rockContext = new RockContext();

            var qry = new GroupMemberService(rockContext)
                      .Queryable("Group");

            var parentGroupGuid = GetAttributeValue("ParentGroup").AsGuidOrNull();

            if (parentGroupGuid != null)
            {
                var availableGroupIds = (List <int>)GetCacheItem("GroupListPersonalizedLava:" + parentGroupGuid.ToString());

                if (availableGroupIds == null)
                {
                    var parentGroup = new GroupService(rockContext).Get(parentGroupGuid ?? new Guid());
                    if (parentGroup != null)
                    {
                        availableGroupIds = GetChildGroups(parentGroup).Select(g => g.Id).ToList();
                    }
                    else
                    {
                        availableGroupIds = new List <int>();
                    }
                    var    cacheLength = GetAttributeValue("CacheDuration").AsInteger();
                    string cacheTags   = GetAttributeValue("CacheTags") ?? string.Empty;
                    AddCacheItem("GroupListPersonalizedLava:" + parentGroupGuid.ToString(), availableGroupIds, cacheLength, cacheTags);
                }
                qry = qry.Where(m => availableGroupIds.Contains(m.GroupId));
            }

            qry = qry.Where(m => m.PersonId == CurrentPersonId &&
                            m.GroupMemberStatus == GroupMemberStatus.Active);

            if (_hideInactive)
            {
                qry = qry.Where(m => m.Group.IsActive == true && !m.Group.IsArchived);
            }

            List <Guid> includeGroupTypeGuids = GetAttributeValue("IncludeGroupTypes").SplitDelimitedValues().Select(a => Guid.Parse(a)).ToList();

            if (includeGroupTypeGuids.Count > 0)
            {
                qry = qry.Where(t => includeGroupTypeGuids.Contains(t.Group.GroupType.Guid));
            }

            List <Guid> excludeGroupTypeGuids = GetAttributeValue("ExcludeGroupTypes").SplitDelimitedValues().Select(a => Guid.Parse(a)).ToList();

            if (excludeGroupTypeGuids.Count > 0)
            {
                qry = qry.Where(t => !excludeGroupTypeGuids.Contains(t.Group.GroupType.Guid));
            }

            var groups = new List <GroupInvolvementSummary>();

            foreach (var groupMember in qry.ToList())
            {
                if (groupMember.Group.IsAuthorized(Authorization.VIEW, CurrentPerson))
                {
                    groups.Add(new GroupInvolvementSummary
                    {
                        Group     = groupMember.Group,
                        Role      = groupMember.GroupRole.Name,
                        IsLeader  = groupMember.GroupRole.IsLeader,
                        GroupType = groupMember.Group.GroupType.Name
                    });
                }
            }

            var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson);

            mergeFields.Add("Groups", groups);

            Dictionary <string, object> linkedPages = new Dictionary <string, object>();

            linkedPages.Add("DetailPage", LinkedPageRoute("DetailPage"));
            mergeFields.Add("LinkedPages", linkedPages);

            if (this.GetAttributeValue("DisplayInactiveGroups").AsBoolean())
            {
                mergeFields.Add("ShowInactive", this.GetAttributeValue("DisplayInactiveGroups"));
                mergeFields.Add("InitialActive", this.GetAttributeValue("InitialActiveSetting"));
                mergeFields.Add("InactiveParameter", this.GetAttributeValue("InactiveParameterName"));
            }

            string template = GetAttributeValue("LavaTemplate");

            lContent.Text = template.ResolveMergeFields(mergeFields);
        }
        /// <summary>
        /// Unsubscribes the person from any lists that were selected.
        /// </summary>
        /// <returns>true if they were actually unsubscribed from something or false otherwise.</returns>
        private bool UnsubscribeFromLists()
        {
            if (_person == null)
            {
                return(false);
            }

            if (!cblUnsubscribeFromLists.SelectedValuesAsInt.Any())
            {
                nbUnsubscribeSuccessMessage.NotificationBoxType = NotificationBoxType.Warning;
                nbUnsubscribeSuccessMessage.Text    = "Please select the lists that you want to unsubscribe from.";
                nbUnsubscribeSuccessMessage.Visible = true;
                return(false);
            }

            List <Group> unsubscribedGroups = new List <Group>();
            var          rockContext        = new RockContext();

            foreach (var communicationListId in cblUnsubscribeFromLists.SelectedValuesAsInt)
            {
                // normally there would be at most 1 group member record for the person, but just in case, mark them all inactive
                var groupMemberRecordsForPerson = new GroupMemberService(rockContext).Queryable().Include(a => a.Group).Where(a => a.GroupId == communicationListId && a.PersonId == _person.Id);
                foreach (var groupMember in groupMemberRecordsForPerson.ToList())
                {
                    groupMember.GroupMemberStatus = GroupMemberStatus.Inactive;
                    if (groupMember.Note.IsNullOrWhiteSpace())
                    {
                        groupMember.Note = "Unsubscribed";
                    }

                    unsubscribedGroups.Add(groupMember.Group);

                    rockContext.SaveChanges();
                }

                // if they selected the CommunicationList associated with the CommunicationId from the Url, log an 'Unsubscribe' Interaction
                if (_communication != null && _communication.ListGroupId.HasValue && communicationListId == _communication.ListGroupId)
                {
                    var communicationRecipient = _communication.GetRecipientsQry(rockContext).Where(a => a.PersonAlias.PersonId == _person.Id).FirstOrDefault();
                    if (communicationRecipient != null)
                    {
                        var interactionService = new InteractionService(rockContext);

                        InteractionComponent interactionComponent = new InteractionComponentService(rockContext)
                                                                    .GetComponentByEntityId(Rock.SystemGuid.InteractionChannel.COMMUNICATION.AsGuid(), _communication.Id, _communication.Subject);

                        rockContext.SaveChanges();

                        var ipAddress = GetClientIpAddress();
                        var userAgent = Request.UserAgent ?? "";

                        UAParser.ClientInfo client = UAParser.Parser.GetDefault().Parse(userAgent);
                        var clientOs      = client.OS.ToString();
                        var clientBrowser = client.UA.ToString();
                        var clientType    = InteractionDeviceType.GetClientType(userAgent);

                        interactionService.AddInteraction(interactionComponent.Id, communicationRecipient.Id, "Unsubscribe", "", communicationRecipient.PersonAliasId, RockDateTime.Now, clientBrowser, clientOs, clientType, userAgent, ipAddress, null);

                        rockContext.SaveChanges();
                    }
                }
            }

            var mergeFields     = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson);
            int?communicationId = PageParameter(PageParameterKey.CommunicationId).AsIntegerOrNull();

            if (_communication != null)
            {
                mergeFields.Add("Communication", _communication);
            }

            mergeFields.Add("UnsubscribedGroups", unsubscribedGroups);

            nbUnsubscribeSuccessMessage.NotificationBoxType = NotificationBoxType.Success;
            nbUnsubscribeSuccessMessage.Text    = GetAttributeValue(AttributeKey.UnsubscribeSuccessText).ResolveMergeFields(mergeFields);
            nbUnsubscribeSuccessMessage.Visible = true;
            return(true);
        }
Exemple #7
0
        private void ListGroups()
        {
            RockContext rockContext = new RockContext();

            var qry = new GroupMemberService(rockContext)
                      .Queryable("Group")
                      .Where(m => m.PersonId == CurrentPersonId &&
                             m.GroupMemberStatus == GroupMemberStatus.Active &&
                             m.Group.IsActive == true);

            List <Guid> includeGroupTypeGuids = GetAttributeValue("IncludeGroupTypes").SplitDelimitedValues().Select(a => Guid.Parse(a)).ToList();

            if (includeGroupTypeGuids.Count > 0)
            {
                qry = qry.Where(t => includeGroupTypeGuids.Contains(t.Group.GroupType.Guid));
            }

            List <Guid> excludeGroupTypeGuids = GetAttributeValue("ExcludeGroupTypes").SplitDelimitedValues().Select(a => Guid.Parse(a)).ToList();

            if (excludeGroupTypeGuids.Count > 0)
            {
                qry = qry.Where(t => !excludeGroupTypeGuids.Contains(t.Group.GroupType.Guid));
            }

            var groups = new List <GroupInvolvementSummary>();

            foreach (var groupMember in qry.ToList())
            {
                if (groupMember.Group.IsAuthorized(Authorization.VIEW, CurrentPerson))
                {
                    groups.Add(new GroupInvolvementSummary
                    {
                        Group     = groupMember.Group,
                        Role      = groupMember.GroupRole.Name,
                        IsLeader  = groupMember.GroupRole.IsLeader,
                        GroupType = groupMember.Group.GroupType.Name
                    });
                }
            }

            var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson);

            mergeFields.Add("Groups", groups);

            Dictionary <string, object> linkedPages = new Dictionary <string, object>();

            linkedPages.Add("DetailPage", LinkedPageRoute("DetailPage"));
            mergeFields.Add("LinkedPages", linkedPages);

            string template = GetAttributeValue("LavaTemplate");

            // show debug info
            bool enableDebug = GetAttributeValue("EnableDebug").AsBoolean();

            if (enableDebug && IsUserAuthorized(Authorization.EDIT))
            {
                lDebug.Visible = true;
                lDebug.Text    = mergeFields.lavaDebugInfo();
            }

            lContent.Text = template.ResolveMergeFields(mergeFields);
        }
Exemple #8
0
        /// <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>();

            Guid?  groupGuid      = null;
            Person person         = null;
            string attributeValue = string.Empty;
            Guid   groupRoleGuid  = Guid.Empty;
            string attributeKey   = string.Empty;

            // get the group attribute
            Guid groupAttributeGuid = GetAttributeValue(action, "Group").AsGuid();

            if (!groupAttributeGuid.IsEmpty())
            {
                groupGuid = action.GetWorkflowAttributeValue(groupAttributeGuid).AsGuidOrNull();

                if (!groupGuid.HasValue)
                {
                    errorMessages.Add("The group could not be found!");
                }
            }

            // get person alias guid
            Guid   personAliasGuid = Guid.Empty;
            string personAttribute = GetAttributeValue(action, "Person");

            Guid guid = personAttribute.AsGuid();

            if (!guid.IsEmpty())
            {
                var attribute = AttributeCache.Get(guid, rockContext);
                if (attribute != null)
                {
                    string value = action.GetWorkflowAttributeValue(guid);
                    personAliasGuid = value.AsGuid();
                }

                if (personAliasGuid != Guid.Empty)
                {
                    person = new PersonAliasService(rockContext).Queryable().AsNoTracking()
                             .Where(p => p.Guid.Equals(personAliasGuid))
                             .Select(p => p.Person)
                             .FirstOrDefault();
                }
                else
                {
                    errorMessages.Add("The person could not be found in the attribute!");
                }
            }

            // get group member attribute value
            attributeValue = GetAttributeValue(action, "AttributeValue");
            guid           = attributeValue.AsGuid();
            if (guid.IsEmpty())
            {
                attributeValue = attributeValue.ResolveMergeFields(GetMergeFields(action));
            }
            else
            {
                var workflowAttributeValue = action.GetWorkflowAttributeValue(guid);

                if (workflowAttributeValue != null)
                {
                    attributeValue = workflowAttributeValue;
                }
            }

            // get optional role filter
            groupRoleGuid = GetAttributeValue(action, "GroupRoleFilter").AsGuid();

            // get attribute key
            attributeKey = GetAttributeValue(action, "GroupMemberAttributeKey").Replace(" ", "");

            // set attribute
            if (groupGuid.HasValue && person != null)
            {
                var qry = new GroupMemberService(rockContext).Queryable()
                          .Where(m => m.Group.Guid == groupGuid && m.PersonId == person.Id);

                if (groupRoleGuid != Guid.Empty)
                {
                    qry = qry.Where(m => m.GroupRole.Guid == groupRoleGuid);
                }

                foreach (var groupMember in qry.ToList())
                {
                    groupMember.LoadAttributes(rockContext);
                    if (groupMember.Attributes.ContainsKey(attributeKey))
                    {
                        var attribute = groupMember.Attributes[attributeKey];
                        Rock.Attribute.Helper.SaveAttributeValue(groupMember, attribute, attributeValue, rockContext);
                    }
                    else
                    {
                        action.AddLogEntry(string.Format("The group member attribute {0} does not exist!", attributeKey));
                        break;
                    }
                }
            }

            errorMessages.ForEach(m => action.AddLogEntry(m, true));

            return(true);
        }
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var exceptionMsgs = new List <string>();

            JobDataMap dataMap         = context.JobDetail.JobDataMap;
            Guid?      groupGuid       = dataMap.GetString("EligibleFollowers").AsGuidOrNull();
            Guid?      systemEmailGuid = dataMap.GetString("EmailTemplate").AsGuidOrNull();
            int        followingSuggestionsEmailsSent       = 0;
            int        followingSuggestionsSuggestionsTotal = 0;

            if (groupGuid.HasValue && systemEmailGuid.HasValue)
            {
                using (var rockContext = new RockContext())
                {
                    var followingService = new FollowingService(rockContext);

                    // The people who are eligible to get following suggestions based on the group type setting for this job
                    var eligiblePersonIds = new GroupMemberService(rockContext)
                                            .Queryable().AsNoTracking()
                                            .Where(m =>
                                                   m.Group != null &&
                                                   m.Group.Guid.Equals(groupGuid.Value) &&
                                                   m.GroupMemberStatus == GroupMemberStatus.Active &&
                                                   m.Person != null &&
                                                   m.Person.Email != null &&
                                                   m.Person.Email != "")
                                            .Select(m => m.PersonId)
                                            .Distinct();

                    // check to see if there are any event types that require notification
                    var followerPersonIds = new List <int>();
                    if (new FollowingEventTypeService(rockContext)
                        .Queryable().AsNoTracking()
                        .Any(e => e.IsNoticeRequired))
                    {
                        // if so, include all eligible people
                        followerPersonIds = eligiblePersonIds.ToList();
                    }
                    else
                    {
                        // if not, filter the list of eligible people down to only those that actually have subscribed to one or more following events
                        followerPersonIds = new FollowingEventSubscriptionService(rockContext)
                                            .Queryable().AsNoTracking()
                                            .Where(f => eligiblePersonIds.Contains(f.PersonAlias.PersonId))
                                            .Select(f => f.PersonAlias.PersonId)
                                            .Distinct()
                                            .ToList();
                    }

                    if (followerPersonIds.Any())
                    {
                        // Get the primary person alias id for each of the followers
                        var primaryAliasIds = new Dictionary <int, int>();
                        new PersonAliasService(rockContext)
                        .Queryable().AsNoTracking()
                        .Where(a =>
                               followerPersonIds.Contains(a.PersonId) &&
                               a.PersonId == a.AliasPersonId)
                        .ToList()
                        .ForEach(a => primaryAliasIds.AddOrIgnore(a.PersonId, a.Id));

                        // Get current date/time.
                        var timestamp = RockDateTime.Now;

                        var suggestionTypes = new FollowingSuggestionTypeService(rockContext)
                                              .Queryable().AsNoTracking()
                                              .Where(s => s.IsActive)
                                              .OrderBy(s => s.Name)
                                              .ToList();

                        var components        = new Dictionary <int, SuggestionComponent>();
                        var suggestedEntities = new Dictionary <int, Dictionary <int, IEntity> >();

                        foreach (var suggestionType in suggestionTypes)
                        {
                            try
                            {
                                // Get the suggestion type component
                                var suggestionComponent = suggestionType.GetSuggestionComponent();
                                if (suggestionComponent != null)
                                {
                                    components.Add(suggestionType.Id, suggestionComponent);

                                    // Get the entitytype for this suggestion type
                                    var suggestionEntityType = EntityTypeCache.Read(suggestionComponent.FollowedType);
                                    if (suggestionEntityType != null)
                                    {
                                        var entityIds = new List <int>();

                                        // Call the components method to return all of it's suggestions
                                        var personEntitySuggestions = suggestionComponent.GetSuggestions(suggestionType, followerPersonIds);

                                        // If any suggestions were returned by the component
                                        if (personEntitySuggestions.Any())
                                        {
                                            int    entityTypeId = suggestionEntityType.Id;
                                            string reasonNote   = suggestionType.ReasonNote;

                                            // Get the existing followings for any of the followers
                                            var existingFollowings = new Dictionary <int, List <int> >();
                                            foreach (var following in followingService.Queryable("PersonAlias").AsNoTracking()
                                                     .Where(f =>
                                                            f.EntityTypeId == entityTypeId &&
                                                            followerPersonIds.Contains(f.PersonAlias.PersonId)))
                                            {
                                                existingFollowings.AddOrIgnore(following.PersonAlias.PersonId, new List <int>());
                                                existingFollowings[following.PersonAlias.PersonId].Add(following.EntityId);
                                            }

                                            // Loop through each follower
                                            foreach (var followerPersonId in personEntitySuggestions
                                                     .Select(s => s.PersonId)
                                                     .Distinct())
                                            {
                                                using (var suggestionContext = new RockContext())
                                                {
                                                    var followingSuggestedService = new FollowingSuggestedService(suggestionContext);

                                                    // Read all the existing suggestions for this type and the returned followers
                                                    var existingSuggestions = followingSuggestedService
                                                                              .Queryable("PersonAlias")
                                                                              .Where(s =>
                                                                                     s.SuggestionTypeId == suggestionType.Id &&
                                                                                     s.PersonAlias.PersonId == followerPersonId)
                                                                              .ToList();

                                                    // Look  through the returned suggestions
                                                    foreach (var followedEntityId in personEntitySuggestions
                                                             .Where(s => s.PersonId == followerPersonId)
                                                             .Select(s => s.EntityId))
                                                    {
                                                        // Make sure person isn't already following this entity
                                                        if (!existingFollowings.ContainsKey(followerPersonId) ||
                                                            !existingFollowings[followerPersonId].Contains(followedEntityId))
                                                        {
                                                            // If this person had a primary alias id
                                                            if (primaryAliasIds.ContainsKey(followerPersonId))
                                                            {
                                                                entityIds.Add(followedEntityId);

                                                                // Look for existing suggestion for this person and entity
                                                                var suggestion = existingSuggestions
                                                                                 .Where(s => s.EntityId == followedEntityId)
                                                                                 .OrderByDescending(s => s.StatusChangedDateTime)
                                                                                 .FirstOrDefault();

                                                                // If not found, add one
                                                                if (suggestion == null)
                                                                {
                                                                    suggestion = new FollowingSuggested();
                                                                    suggestion.EntityTypeId          = entityTypeId;
                                                                    suggestion.EntityId              = followedEntityId;
                                                                    suggestion.PersonAliasId         = primaryAliasIds[followerPersonId];
                                                                    suggestion.SuggestionTypeId      = suggestionType.Id;
                                                                    suggestion.Status                = FollowingSuggestedStatus.PendingNotification;
                                                                    suggestion.StatusChangedDateTime = timestamp;
                                                                    followingSuggestedService.Add(suggestion);
                                                                }
                                                                else
                                                                {
                                                                    // If found, and it has not been ignored, and it's time to promote again, update the promote date
                                                                    if (suggestion.Status != FollowingSuggestedStatus.Ignored &&
                                                                        (
                                                                            !suggestionType.ReminderDays.HasValue ||
                                                                            !suggestion.LastPromotedDateTime.HasValue ||
                                                                            suggestion.LastPromotedDateTime.Value.AddDays(suggestionType.ReminderDays.Value) <= timestamp
                                                                        ))
                                                                    {
                                                                        if (suggestion.Status != FollowingSuggestedStatus.PendingNotification)
                                                                        {
                                                                            suggestion.StatusChangedDateTime = timestamp;
                                                                            suggestion.Status = FollowingSuggestedStatus.PendingNotification;
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }

                                                    // Save the suggestions for this type
                                                    suggestionContext.SaveChanges();
                                                }
                                            }
                                        }

                                        // If any entities are being suggested for this type, query database for them and save to dictionary
                                        if (entityIds.Any())
                                        {
                                            if (suggestionEntityType.AssemblyName != null)
                                            {
                                                // get the actual type of what is being followed
                                                Type entityType = suggestionEntityType.GetEntityType();
                                                if (entityType != null)
                                                {
                                                    // Get generic queryable method and query all the entities that are being followed
                                                    Type[]             modelType          = { entityType };
                                                    Type               genericServiceType = typeof(Rock.Data.Service <>);
                                                    Type               modelServiceType   = genericServiceType.MakeGenericType(modelType);
                                                    Rock.Data.IService serviceInstance    = Activator.CreateInstance(modelServiceType, new object[] { rockContext }) as IService;
                                                    MethodInfo         qryMethod          = serviceInstance.GetType().GetMethod("Queryable", new Type[] { });
                                                    var entityQry  = qryMethod.Invoke(serviceInstance, new object[] { }) as IQueryable <IEntity>;
                                                    var entityList = entityQry.AsNoTracking().Where(q => entityIds.Contains(q.Id)).ToList();
                                                    if (entityList != null && entityList.Any())
                                                    {
                                                        var entities = new Dictionary <int, IEntity>();
                                                        entityList.ForEach(e => entities.Add(e.Id, e));
                                                        suggestedEntities.Add(suggestionType.Id, entities);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                exceptionMsgs.Add(string.Format("An exception occurred calculating suggestions for the '{0}' suggestion type:{1}    {2}", suggestionType.Name, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                                ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                            }
                        }

                        var allSuggestions = new FollowingSuggestedService(rockContext)
                                             .Queryable("PersonAlias")
                                             .Where(s => s.Status == FollowingSuggestedStatus.PendingNotification)
                                             .ToList();

                        var suggestionPersonIds = allSuggestions
                                                  .Where(s => followerPersonIds.Contains(s.PersonAlias.PersonId))
                                                  .Select(s => s.PersonAlias.PersonId)
                                                  .Distinct()
                                                  .ToList();

                        var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read(rockContext).GetValue("ExternalApplicationRoot");

                        foreach (var person in new PersonService(rockContext)
                                 .Queryable().AsNoTracking()
                                 .Where(p => suggestionPersonIds.Contains(p.Id))
                                 .ToList())
                        {
                            try
                            {
                                var personSuggestionNotices = new List <FollowingSuggestionNotices>();

                                foreach (var suggestionType in suggestionTypes)
                                {
                                    var component = components.ContainsKey(suggestionType.Id) ? components[suggestionType.Id] : null;
                                    if (component != null && suggestedEntities.ContainsKey(suggestionType.Id))
                                    {
                                        var entities = new List <IEntity>();
                                        foreach (var suggestion in allSuggestions
                                                 .Where(s =>
                                                        s.PersonAlias.PersonId == person.Id &&
                                                        s.SuggestionTypeId == suggestionType.Id)
                                                 .ToList())
                                        {
                                            if (suggestedEntities[suggestionType.Id].ContainsKey(suggestion.EntityId))
                                            {
                                                entities.Add(suggestedEntities[suggestionType.Id][suggestion.EntityId]);
                                                suggestion.LastPromotedDateTime = timestamp;
                                                suggestion.Status = FollowingSuggestedStatus.Suggested;
                                            }
                                        }

                                        var notices = new List <string>();
                                        foreach (var entity in component.SortEntities(entities))
                                        {
                                            notices.Add(component.FormatEntityNotification(suggestionType, entity));
                                        }

                                        if (notices.Any())
                                        {
                                            personSuggestionNotices.Add(new FollowingSuggestionNotices(suggestionType, notices));
                                        }
                                    }
                                }

                                if (personSuggestionNotices.Any())
                                {
                                    // Send the notice
                                    var recipients  = new List <RecipientData>();
                                    var mergeFields = new Dictionary <string, object>();
                                    mergeFields.Add("Person", person);
                                    mergeFields.Add("Suggestions", personSuggestionNotices.OrderBy(s => s.SuggestionType.Order).ToList());
                                    recipients.Add(new RecipientData(person.Email, mergeFields));
                                    Email.Send(systemEmailGuid.Value, recipients, appRoot);
                                    followingSuggestionsEmailsSent       += recipients.Count();
                                    followingSuggestionsSuggestionsTotal += personSuggestionNotices.Count();
                                }

                                rockContext.SaveChanges();
                            }
                            catch (Exception ex)
                            {
                                exceptionMsgs.Add(string.Format("An exception occurred sending suggestions to '{0}':{1}    {2}", person.FullName, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                                ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                            }
                        }
                    }
                }
            }

            context.Result = string.Format("A total of {0} following suggestions sent to {1} people", followingSuggestionsSuggestionsTotal, followingSuggestionsEmailsSent);

            if (exceptionMsgs.Any())
            {
                throw new Exception("One or more exceptions occurred calculating suggestions..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
            }
        }
Exemple #10
0
        /// <summary>
        /// Binds the data.
        /// </summary>
        private void BindData()
        {
            if (Person != null && Person.Id > 0)
            {
                if (ownerRoleGuid != Guid.Empty)
                {
                    using (var rockContext = new RockContext())
                    {
                        var memberService = new GroupMemberService(rockContext);
                        var group         = memberService.Queryable(true)
                                            .Where(m =>
                                                   m.PersonId == Person.Id &&
                                                   m.GroupRole.Guid == ownerRoleGuid)
                                            .Select(m => m.Group)
                                            .FirstOrDefault();

                        if (group == null && GetAttributeValue("CreateGroup").AsBoolean())
                        {
                            var role = new GroupTypeRoleService(rockContext).Get(ownerRoleGuid);
                            if (role != null && role.GroupTypeId.HasValue)
                            {
                                var groupService = new GroupService(rockContext);
                                group             = new Group();
                                group.Name        = role.GroupType.Name;
                                group.GroupTypeId = role.GroupTypeId.Value;
                                groupService.Add(group);
                                rockContext.SaveChanges();

                                var groupMember = new GroupMember();
                                groupMember.PersonId    = Person.Id;
                                groupMember.GroupRoleId = role.Id;
                                groupMember.GroupId     = group.Id;
                                group.Members.Add(groupMember);
                                rockContext.SaveChanges();

                                group = groupService.Get(group.Id);
                            }
                        }

                        if (group != null)
                        {
                            lGroupName.Text        = group.Name.Pluralize();
                            lGroupTypeIcon.Text    = string.Format("<i class='{0}'></i>", group.GroupType.IconCssClass);
                            lGroupTypeIcon.Visible = !string.IsNullOrWhiteSpace(group.GroupType.IconCssClass);
                            phEditActions.Visible  = group.IsAuthorized(Authorization.EDIT, CurrentPerson);

                            if (group.IsAuthorized(Authorization.VIEW, CurrentPerson))
                            {
                                int?maxRelationshipsToDisplay = this.GetAttributeValue("MaxRelationshipsToDisplay").AsIntegerOrNull();

                                IQueryable <GroupMember> qryGroupMembers = new GroupMemberService(rockContext).GetByGroupId(group.Id, true)
                                                                           .Where(m => m.PersonId != Person.Id)
                                                                           .OrderBy(m => m.Person.LastName)
                                                                           .ThenBy(m => m.Person.FirstName);

                                if (maxRelationshipsToDisplay.HasValue)
                                {
                                    qryGroupMembers = qryGroupMembers.Take(maxRelationshipsToDisplay.Value);
                                }

                                rGroupMembers.DataSource = qryGroupMembers.ToList();
                                rGroupMembers.DataBind();
                            }
                            else
                            {
                                lAccessWarning.Text = string.Format("<div class='alert alert-info'>You do not have security rights to view {0}.", group.Name.Pluralize());
                            }
                        }
                        else
                        {
                            lGroupName.Text = this.BlockCache.Name;
                        }
                    }
                }
            }
        }
        /// <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)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            try
            {
                int notificationsSent   = 0;
                int pendingMembersCount = 0;

                // get groups set to sync
                RockContext rockContext = new RockContext();

                Guid?groupTypeGuid       = dataMap.GetString("GroupType").AsGuidOrNull();
                Guid?systemEmailGuid     = dataMap.GetString("NotificationEmail").AsGuidOrNull();
                Guid?groupRoleFilterGuid = dataMap.GetString("GroupRoleFilter").AsGuidOrNull();
                int? pendingAge          = dataMap.GetString("PendingAge").AsIntegerOrNull();


                bool includePreviouslyNotificed = dataMap.GetString("IncludePreviouslyNotified").AsBoolean();

                // get system email
                SystemEmailService emailService = new SystemEmailService(rockContext);

                SystemEmail systemEmail = null;
                if (systemEmailGuid.HasValue)
                {
                    systemEmail = emailService.Get(systemEmailGuid.Value);
                }

                if (systemEmail == null)
                {
                    // no email specified, so nothing to do
                    return;
                }

                // get group members
                if (groupTypeGuid.HasValue && groupTypeGuid != Guid.Empty)
                {
                    var qry = new GroupMemberService(rockContext).Queryable("Person, Group, Group.Members.GroupRole")
                              .Where(m => m.Group.GroupType.Guid == groupTypeGuid.Value &&
                                     m.GroupMemberStatus == GroupMemberStatus.Pending);

                    if (!includePreviouslyNotificed)
                    {
                        qry = qry.Where(m => m.IsNotified == false);
                    }

                    if (groupRoleFilterGuid.HasValue)
                    {
                        qry = qry.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value);
                    }

                    if (pendingAge.HasValue && pendingAge.Value > 0)
                    {
                        var ageDate = RockDateTime.Now.AddDays(pendingAge.Value * -1);
                        qry = qry.Where(m => m.ModifiedDateTime > ageDate);
                    }

                    var pendingGroupMembers = qry.ToList();


                    var groups = pendingGroupMembers.GroupBy(m => m.Group);

                    foreach (var groupKey in groups)
                    {
                        var group = groupKey.Key;

                        // get list of pending people
                        var qryPendingIndividuals = group.Members.Where(m => m.GroupMemberStatus == GroupMemberStatus.Pending);

                        if (!includePreviouslyNotificed)
                        {
                            qryPendingIndividuals = qryPendingIndividuals.Where(m => m.IsNotified == false);
                        }

                        if (groupRoleFilterGuid.HasValue)
                        {
                            qryPendingIndividuals = qryPendingIndividuals.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value);
                        }

                        var pendingIndividuals = qryPendingIndividuals.Select(m => m.Person).ToList();

                        // get list of leaders
                        var groupLeaders = group.Members.Where(m => m.GroupRole.IsLeader == true);

                        var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read(rockContext).GetValue("PublicApplicationRoot");

                        var recipients = new List <RecipientData>();
                        foreach (var leader in groupLeaders.Where(l => l.Person != null && l.Person.Email != ""))
                        {
                            // create merge object
                            var mergeFields = new Dictionary <string, object>();
                            mergeFields.Add("PendingIndividuals", pendingIndividuals);
                            mergeFields.Add("Group", group);
                            mergeFields.Add("ParentGroup", group.ParentGroup);
                            mergeFields.Add("Person", leader.Person);
                            recipients.Add(new RecipientData(leader.Person.Email, mergeFields));
                        }

                        if (pendingIndividuals.Count() > 0)
                        {
                            var emailMessage = new RockEmailMessage(systemEmail.Guid);
                            emailMessage.SetRecipients(recipients);
                            emailMessage.Send();
                            notificationsSent += recipients.Count();
                        }

                        // mark pending members as notified as we go in case the job fails
                        var notifiedPersonIds = pendingIndividuals.Select(p => p.Id);
                        foreach (var pendingGroupMember in pendingGroupMembers.Where(m => m.IsNotified == false && notifiedPersonIds.Contains(m.PersonId)))
                        {
                            pendingGroupMember.IsNotified = true;
                        }

                        rockContext.SaveChanges();
                    }
                }

                context.Result = string.Format("Sent {0} emails to leaders for {1} pending individuals", notificationsSent, pendingMembersCount);
            }
            catch (System.Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
                throw;
            }
        }
        private List <MedicalItem> GetMedicalItems()
        {
            RockContext  rockContext    = new RockContext();
            GroupService groupService   = new GroupService(rockContext);
            var          groupIdStrings = GetAttributeValue("GroupIds").SplitDelimitedValues();
            var          groupIds       = new List <int>();

            foreach (var id in groupIdStrings)
            {
                groupIds.Add(id.AsInteger());
            }

            var groups = groupService.GetByIds(groupIds);

            var groupTypeIds = groups.ToList().Select(g => g.GroupTypeId.ToString()).Distinct();

            var groupEntityid = EntityTypeCache.GetId <Rock.Model.GroupMember>();
            var key           = GetAttributeValue("MedicationMatrixKey");

            AttributeService attributeService = new AttributeService(rockContext);

            List <int> attributeIds = attributeService.Queryable()
                                      .Where(a =>
                                             (groupIdStrings.Contains(a.EntityTypeQualifierValue) || groupTypeIds.Contains(a.EntityTypeQualifierValue)) &&
                                             a.Key == key &&
                                             a.EntityTypeId == groupEntityid)
                                      .Select(a => a.Id).ToList();

            if (attributeIds == null)
            {
                nbAlert.Visible = true;
                nbAlert.Text    = "Medication attribute not found";
                return(null);
            }

            List <int> filterAttributeIds = null;
            var        filterAttributeKey = GetAttributeValue("GroupMemberAttributeFilter");

            if (!string.IsNullOrWhiteSpace(filterAttributeKey))
            {
                filterAttributeIds = attributeService.Queryable()
                                     .Where(a =>
                                            (groupIdStrings.Contains(a.EntityTypeQualifierValue) || groupTypeIds.Contains(a.EntityTypeQualifierValue)) &&
                                            a.Key == filterAttributeKey &&
                                            a.EntityTypeId == groupEntityid)
                                     .Select(a => a.Id).ToList();
            }

            var attributeMatrixItemEntityId = EntityTypeCache.GetId <AttributeMatrixItem>();

            AttributeValueService      attributeValueService      = new AttributeValueService(rockContext);
            AttributeMatrixService     attributeMatrixService     = new AttributeMatrixService(rockContext);
            AttributeMatrixItemService attributeMatrixItemService = new AttributeMatrixItemService(rockContext);
            HistoryService             historyService             = new HistoryService(rockContext);

            var qry = new GroupMemberService(rockContext).Queryable()
                      .Join(
                attributeValueService.Queryable().Where(av => attributeIds.Contains(av.AttributeId)),
                m => m.Id,
                av => av.EntityId.Value,
                (m, av) => new { Member = m, AttributeValue = av.Value }
                )
                      .Join(
                attributeMatrixService.Queryable(),
                m => m.AttributeValue,
                am => am.Guid.ToString(),
                (m, am) => new { Member = m.Member, AttributeMatrix = am }
                )
                      .Join(
                attributeMatrixItemService.Queryable(),
                m => m.AttributeMatrix.Id,
                ami => ami.AttributeMatrixId,
                (m, ami) => new { Member = m.Member, AttributeMatrixItem = ami, TemplateId = ami.AttributeMatrix.AttributeMatrixTemplateId }
                )
                      .Join(
                attributeService.Queryable(),
                m => new { TemplateIdString = m.TemplateId.ToString(), EntityTypeId = attributeMatrixItemEntityId },
                a => new { TemplateIdString = a.EntityTypeQualifierValue, EntityTypeId = a.EntityTypeId },
                (m, a) => new { Member = m.Member, AttributeMatrixItem = m.AttributeMatrixItem, Attribute = a }
                )
                      .Join(
                attributeValueService.Queryable(),
                m => new { EntityId = m.AttributeMatrixItem.Id, AttributeId = m.Attribute.Id },
                av => new { EntityId = av.EntityId ?? 0, AttributeId = av.AttributeId },
                (m, av) => new { Member = m.Member, Attribute = m.Attribute, AttributeValue = av, MatrixItemId = m.AttributeMatrixItem.Id, FilterValue = "" }
                ).
                      Where(obj => groupIds.Contains(obj.Member.GroupId));

            if (filterAttributeIds != null && pnlAttribute.Visible && !string.IsNullOrWhiteSpace(ddlAttribute.SelectedValue))
            {
                var filterValue = ddlAttribute.SelectedValue;
                qry = qry
                      .Join(
                    attributeValueService.Queryable().Where(av => filterAttributeIds.Contains(av.AttributeId)),
                    m => new { Id = m.Member.Id, Value = filterValue },
                    av => new { Id = av.EntityId ?? 0, Value = av.Value },
                    (m, av) => new { Member = m.Member, Attribute = m.Attribute, AttributeValue = m.AttributeValue, MatrixItemId = m.MatrixItemId, FilterValue = av.Value });
            }
            var members = qry.ToList().GroupBy(a => a.Member).ToList();

            var firstDay = (dpDate.SelectedDate ?? Rock.RockDateTime.Today).Date;
            var nextday  = firstDay.AddDays(1);

            var personIds = members.Select(m => m.Key.PersonId);
            var attributeMatrixEntityTypeId = EntityTypeCache.GetId <AttributeMatrixItem>().Value;

            var historyItems = historyService.Queryable()
                               .Where(h => personIds.Contains(h.EntityId))
                               .Where(h => h.RelatedEntityTypeId == attributeMatrixEntityTypeId)
                               .Where(h => h.CreatedDateTime >= firstDay && h.CreatedDateTime < nextday)
                               .ToList();

            foreach (var member in members)
            {
                if (!string.IsNullOrWhiteSpace(tbName.Text) &&
                    !member.Key.Person.FullName.ToLower().Contains(tbName.Text.ToLower()) &&
                    !member.Key.Person.FullNameReversed.ToLower().Contains(tbName.Text.ToLower()))
                {
                    continue;
                }

                var medicines = member.GroupBy(m => m.MatrixItemId);
                foreach (var medicine in medicines)
                {
                    var scheduleAtt = medicine.FirstOrDefault(m => m.Attribute.Key == "Schedule");
                    var schedules   = scheduleAtt.AttributeValue.Value.SplitDelimitedValues();
                    foreach (var schedule in schedules)
                    {
                        if (ddlSchedule.SelectedValue != "" && ddlSchedule.SelectedValue.AsGuid() != schedule.AsGuid())
                        {
                            continue;
                        }

                        var medicalItem = new MedicalItem()
                        {
                            Person          = member.Key.Person.FullNameReversed,
                            GroupMemberId   = member.Key.Id,
                            GroupMember     = member.FirstOrDefault().Member,
                            PersonId        = member.Key.Person.Id,
                            FilterAttribute = member.FirstOrDefault().FilterValue
                        };

                        if (!string.IsNullOrWhiteSpace(schedule))
                        {
                            var dv = DefinedValueCache.Read(schedule.AsGuid());
                            if (dv != null)
                            {
                                medicalItem.Schedule     = dv.Value;
                                medicalItem.ScheduleGuid = dv.Guid;
                            }
                        }

                        var medAtt = medicine.FirstOrDefault(m => m.Attribute.Key == "Medication");
                        if (medAtt != null)
                        {
                            medicalItem.Medication = medAtt.AttributeValue.Value;
                        }

                        var instructionAtt = medicine.FirstOrDefault(m => m.Attribute.Key == "Instructions");
                        if (instructionAtt != null)
                        {
                            medicalItem.Instructions = instructionAtt.AttributeValue.Value;
                        }
                        medicalItem.Key = string.Format("{0}|{1}|{2}", medicalItem.PersonId, medicine.Key, medicalItem.ScheduleGuid);

                        var history = historyItems.Where(h => h.EntityId == medicalItem.PersonId && h.RelatedEntityId == medicine.Key && (string.IsNullOrWhiteSpace(h.RelatedData) || h.RelatedData.AsGuid() == medicalItem.ScheduleGuid));
                        if (history.Any())
                        {
                            medicalItem.Distributed = true;
                            medicalItem.History     = string.Join("<br>", history.Select(h => h.Summary));
                        }
                        medicalItems.Add(medicalItem);
                    }
                }
            }

            SortProperty sortProperty = gGrid.SortProperty;

            if (sortProperty != null)
            {
                if (sortProperty.Property == "Person")
                {
                    if (sortProperty.Direction == SortDirection.Ascending)
                    {
                        medicalItems = medicalItems.OrderBy(mi => mi.Person).ToList();
                    }
                    else
                    {
                        medicalItems = medicalItems.OrderByDescending(mi => mi.Person).ToList();
                    }
                }
            }
            else
            {
                medicalItems       = medicalItems.OrderBy(mi => mi.Person).ToList();
                gGrid.SortProperty = new SortProperty()
                {
                    Property = "Person"
                };
            }

            return(medicalItems);
        }
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var rockContext = new RockContext();

            JobDataMap dataMap         = context.JobDetail.JobDataMap;
            Guid?      systemEmailGuid = dataMap.GetString("NotificationEmailTemplate").AsGuidOrNull();

            if (systemEmailGuid.HasValue)
            {
                var selectedGroupTypes = new List <Guid>();
                if (!string.IsNullOrWhiteSpace(dataMap.GetString("GroupTypes")))
                {
                    selectedGroupTypes = dataMap.GetString("GroupTypes").Split(',').Select(Guid.Parse).ToList();
                }

                var excludedGroupRoleIds = new List <int>();
                if (!string.IsNullOrWhiteSpace(dataMap.GetString("ExcludedGroupRoleIds")))
                {
                    excludedGroupRoleIds = dataMap.GetString("ExcludedGroupRoleIds").Split(',').Select(int.Parse).ToList();
                }

                var notificationOption = dataMap.GetString("NotifyParentLeaders").ConvertToEnum <NotificationOption>(NotificationOption.None);

                var accountAbilityGroupGuid = dataMap.GetString("AccountabilityGroup").AsGuid();

                // get groups matching of the types provided
                GroupService groupService = new GroupService(rockContext);
                var          groups       = groupService.Queryable().AsNoTracking()
                                            .Where(g => selectedGroupTypes.Contains(g.GroupType.Guid) &&
                                                   g.IsActive == true &&
                                                   g.GroupRequirements.Any());

                foreach (var group in groups)
                {
                    // check for members that don't meet requirements
                    var groupMembersWithIssues = groupService.GroupMembersNotMeetingRequirements(group.Id, true);

                    if (groupMembersWithIssues.Count > 0)
                    {
                        // add issues to issue list
                        GroupsMissingRequirements groupMissingRequirements = new GroupsMissingRequirements();
                        groupMissingRequirements.Id   = group.Id;
                        groupMissingRequirements.Name = group.Name;
                        if (group.GroupType != null)
                        {
                            groupMissingRequirements.GroupTypeId   = group.GroupTypeId;
                            groupMissingRequirements.GroupTypeName = group.GroupType.Name;
                        }
                        groupMissingRequirements.AncestorPathName = groupService.GroupAncestorPathName(group.Id);

                        // get list of the group leaders
                        groupMissingRequirements.Leaders = group.Members
                                                           .Where(m => m.GroupRole.IsLeader == true && !excludedGroupRoleIds.Contains(m.GroupRoleId))
                                                           .Select(m => new GroupMemberResult
                        {
                            Id       = m.Id,
                            PersonId = m.PersonId,
                            FullName = m.Person.FullName
                        })
                                                           .ToList();


                        List <GroupMembersMissingRequirements> groupMembers = new List <GroupMembersMissingRequirements>();

                        foreach (var groupMemberIssue in groupMembersWithIssues)
                        {
                            GroupMembersMissingRequirements groupMember = new GroupMembersMissingRequirements();
                            groupMember.FullName        = groupMemberIssue.Key.Person.FullName;
                            groupMember.Id              = groupMemberIssue.Key.Id;
                            groupMember.PersonId        = groupMemberIssue.Key.PersonId;
                            groupMember.GroupMemberRole = groupMemberIssue.Key.GroupRole.Name;

                            List <MissingRequirement> missingRequirements = new List <MissingRequirement>();
                            foreach (var issue in groupMemberIssue.Value)
                            {
                                MissingRequirement missingRequirement = new MissingRequirement();
                                missingRequirement.Id             = issue.Key.GroupRequirement.GroupRequirementType.Id;
                                missingRequirement.Name           = issue.Key.GroupRequirement.GroupRequirementType.Name;
                                missingRequirement.Status         = issue.Key.MeetsGroupRequirement;
                                missingRequirement.OccurrenceDate = issue.Value;

                                switch (issue.Key.MeetsGroupRequirement)
                                {
                                case MeetsGroupRequirement.Meets:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.PositiveLabel;
                                    break;

                                case MeetsGroupRequirement.MeetsWithWarning:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.WarningLabel;
                                    break;

                                case MeetsGroupRequirement.NotMet:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.NegativeLabel;
                                    break;
                                }

                                missingRequirements.Add(missingRequirement);
                            }

                            groupMember.MissingRequirements = missingRequirements;

                            groupMembers.Add(groupMember);
                        }
                        groupMissingRequirements.GroupMembersMissingRequirements = groupMembers;

                        _groupsMissingRequriements.Add(groupMissingRequirements);

                        // add leaders as people to notify
                        foreach (var leader in group.Members.Where(m => m.GroupRole.IsLeader == true && !excludedGroupRoleIds.Contains(m.GroupRoleId)))
                        {
                            NotificationItem notification = new NotificationItem();
                            notification.GroupId = group.Id;
                            notification.Person  = leader.Person;
                            _notificationList.Add(notification);

                            // notify parents
                            if (notificationOption != NotificationOption.None)
                            {
                                var parentLeaders = new GroupMemberService(rockContext).Queryable("Person").AsNoTracking()
                                                    .Where(m => m.GroupRole.IsLeader && !excludedGroupRoleIds.Contains(m.GroupRoleId));

                                if (notificationOption == NotificationOption.DirectParent)
                                {
                                    // just the parent group
                                    parentLeaders = parentLeaders.Where(m => m.GroupId == group.ParentGroupId);
                                }
                                else
                                {
                                    // all parents in the heirarchy
                                    var parentIds = groupService.GetAllAncestorIds(group.Id);
                                    parentLeaders = parentLeaders.Where(m => parentIds.Contains(m.GroupId));
                                }

                                foreach (var parentLeader in parentLeaders.ToList())
                                {
                                    NotificationItem parentNotification = new NotificationItem();
                                    parentNotification.Person  = parentLeader.Person;
                                    parentNotification.GroupId = group.Id;
                                    _notificationList.Add(parentNotification);
                                }
                            }
                        }
                    }
                }

                // send out notificatons
                var appRoot    = Rock.Web.Cache.GlobalAttributesCache.Read(rockContext).GetValue("ExternalApplicationRoot");
                var recipients = new List <RecipientData>();

                var notificationRecipients = _notificationList.GroupBy(p => p.Person.Id).ToList();
                foreach (var recipientId in notificationRecipients)
                {
                    var recipient = _notificationList.Where(n => n.Person.Id == recipientId.Key).Select(n => n.Person).FirstOrDefault();

                    var mergeFields = new Dictionary <string, object>();
                    mergeFields.Add("Person", recipient);

                    var notificationGroupIds = _notificationList
                                               .Where(n => n.Person.Id == recipient.Id)
                                               .Select(n => n.GroupId)
                                               .ToList();

                    var missingRequirements = _groupsMissingRequriements.Where(g => notificationGroupIds.Contains(g.Id)).ToList();

                    mergeFields.Add("GroupsMissingRequirements", missingRequirements);

                    var globalAttributeFields = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields(null);
                    globalAttributeFields.ToList().ForEach(d => mergeFields.Add(d.Key, d.Value));


                    recipients.Add(new RecipientData(recipient.Email, mergeFields));
                    Email.Send(systemEmailGuid.Value, recipients, appRoot);

                    recipients.Clear();
                }

                // add accountability group members
                if (!accountAbilityGroupGuid.IsEmpty())
                {
                    var accountabilityGroupMembers = new GroupMemberService(rockContext).Queryable().AsNoTracking()
                                                     .Where(m => m.Group.Guid == accountAbilityGroupGuid)
                                                     .Select(m => m.Person);

                    foreach (var person in accountabilityGroupMembers)
                    {
                        var mergeFields = new Dictionary <string, object>();
                        mergeFields.Add("Person", person);
                        mergeFields.Add("GroupsMissingRequirements", _groupsMissingRequriements);

                        var globalAttributeFields = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields(null);
                        globalAttributeFields.ToList().ForEach(d => mergeFields.Add(d.Key, d.Value));
                        recipients.Add(new RecipientData(person.Email, mergeFields));
                    }
                }

                Email.Send(systemEmailGuid.Value, recipients, appRoot);
            }
        }
Exemple #14
0
        /// <summary>
        /// Binds the data.
        /// </summary>
        private void BindData()
        {
            ShowRole = GetAttributeValue("ShowRole").AsBoolean();

            if (person != null && person.Id > 0)
            {
                if (ownerRoleGuid != Guid.Empty)
                {
                    using (var rockContext = new RockContext())
                    {
                        var memberService = new GroupMemberService(rockContext);
                        var group         = memberService.Queryable(true)
                                            .Where(m =>
                                                   m.PersonId == person.Id &&
                                                   m.GroupRole.Guid == ownerRoleGuid)
                                            .Select(m => m.Group)
                                            .FirstOrDefault();

                        if (group != null)
                        {
                            lGroupName.Text        = group.Name.Pluralize();
                            lGroupTypeIcon.Text    = string.Format("<i class='{0}'></i>", group.GroupType.IconCssClass);
                            lGroupTypeIcon.Visible = !string.IsNullOrWhiteSpace(group.GroupType.IconCssClass);

                            if (group.IsAuthorized(Authorization.VIEW, CurrentPerson))
                            {
                                int?maxRelationshipsToDisplay = this.GetAttributeValue("MaxRelationshipsToDisplay").AsIntegerOrNull();

                                var roles = new List <int>();
                                if (canCheckInOnly)
                                {
                                    foreach (var role in new GroupTypeRoleService(rockContext)
                                             .Queryable().AsNoTracking()
                                             .Where(r => r.GroupType.Guid.Equals(new Guid(Rock.SystemGuid.GroupType.GROUPTYPE_KNOWN_RELATIONSHIPS))))
                                    {
                                        role.LoadAttributes(rockContext);
                                        if (role.Attributes.ContainsKey("CanCheckin"))
                                        {
                                            bool canCheckIn = false;
                                            if (bool.TryParse(role.GetAttributeValue("CanCheckin"), out canCheckIn) && canCheckIn)
                                            {
                                                roles.Add(role.Id);
                                            }
                                        }

                                        if (role.Attributes.ContainsKey("InverseRelationship"))
                                        {
                                            var inverseRoleGuid = role.GetAttributeValue("InverseRelationship").AsGuidOrNull();
                                            if (inverseRoleGuid != null)
                                            {
                                                var groupTypeRole = new GroupTypeRoleService(rockContext)
                                                                    .Queryable().AsNoTracking()
                                                                    .FirstOrDefault(r => r.Guid.Equals(( Guid )inverseRoleGuid));
                                                if (groupTypeRole != null)
                                                {
                                                    groupTypeRole.LoadAttributes(rockContext);
                                                    if (groupTypeRole.Attributes.ContainsKey("CanCheckin"))
                                                    {
                                                        bool canCheckIn = false;
                                                        if (bool.TryParse(groupTypeRole.GetAttributeValue("CanCheckin"), out canCheckIn) && canCheckIn)
                                                        {
                                                            roles.Add(role.Id);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    foreach (var role in new GroupTypeRoleService(rockContext)
                                             .Queryable().AsNoTracking()
                                             .Where(r => r.GroupType.Guid.Equals(new Guid(Rock.SystemGuid.GroupType.GROUPTYPE_KNOWN_RELATIONSHIPS))))
                                    {
                                        roles.Add(role.Id);
                                    }
                                }

                                IQueryable <GroupMember> qryGroupMembers = new GroupMemberService(rockContext).GetByGroupId(group.Id, true)
                                                                           .Where(m => m.PersonId != person.Id)
                                                                           .Where(m => roles.Contains(m.GroupRoleId))
                                                                           .OrderBy(m => m.Person.LastName)
                                                                           .ThenBy(m => m.Person.FirstName);

                                if (maxRelationshipsToDisplay.HasValue)
                                {
                                    qryGroupMembers = qryGroupMembers.Take(maxRelationshipsToDisplay.Value);
                                }

                                rGroupMembers.ItemDataBound += rptrMembers_ItemDataBound;
                                rGroupMembers.DataSource     = qryGroupMembers.ToList();
                                rGroupMembers.DataBind();
                            }
                            else
                            {
                                lAccessWarning.Text = string.Format("<div class='alert alert-info'>You do not have security rights to view {0}.", group.Name.Pluralize());
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid()
        {
            var showGoal      = GetAttributeValue("ShowMemberFundingGoal").AsBoolean();
            var showTotal     = GetAttributeValue("ShowMemberTotalFunding").AsBoolean();
            var showRemaining = GetAttributeValue("ShowMemberFundingRemaining").AsBoolean();

            gGroupMembers.Columns[4].Visible = showGoal;
            gGroupMembers.Columns[5].Visible = showTotal;
            gGroupMembers.Columns[6].Visible = showRemaining;

            var rockContext = new RockContext();

            int groupId = hfGroupId.Value.AsInteger();
            var totalFundraisingGoal  = 0.00M;
            var totalContribution     = 0.00M;
            var totalFundingRemaining = 0.00M;
            var groupMembersQuery     = new GroupMemberService(rockContext).Queryable().Where(a => a.GroupId == groupId);
            var group = new GroupService(rockContext).Get(groupId);

            group.LoadAttributes(rockContext);
            var defaultIndividualFundRaisingGoal = group.GetAttributeValue("IndividualFundraisingGoal").AsDecimalOrNull();

            groupMembersQuery = groupMembersQuery.Sort(gGroupMembers.SortProperty ?? new SortProperty {
                Property = "Person.LastName, Person.NickName"
            });

            var entityTypeIdGroupMember = EntityTypeCache.GetId <Rock.Model.GroupMember>();
            var entityTypeIdPerson      = EntityTypeCache.GetId <Rock.Model.Person>();

            var groupMemberList = groupMembersQuery.ToList().Select(a =>
            {
                var groupMember = a;
                groupMember.LoadAttributes(rockContext);

                var contributionTotal = new FinancialTransactionDetailService(rockContext).Queryable()
                                        .Where(d => d.EntityTypeId == entityTypeIdGroupMember &&
                                               d.EntityId == groupMember.Id)
                                        .Sum(d => ( decimal? )d.Amount) ?? 0.00M;

                var individualFundraisingGoal          = groupMember.GetAttributeValue("IndividualFundraisingGoal").AsDecimalOrNull();
                bool disablePublicContributionRequests = groupMember.GetAttributeValue("DisablePublicContributionRequests").AsBoolean();
                if (!individualFundraisingGoal.HasValue)
                {
                    individualFundraisingGoal = group.GetAttributeValue("IndividualFundraisingGoal").AsDecimalOrNull();
                }

                var fundingRemaining = individualFundraisingGoal - contributionTotal;
                if (disablePublicContributionRequests || !showRemaining)
                {
                    fundingRemaining = null;
                }
                else if (fundingRemaining < 0)
                {
                    fundingRemaining = 0.00M;
                }

                totalFundraisingGoal  += (individualFundraisingGoal != null ? ( decimal )individualFundraisingGoal : 0);
                totalContribution     += contributionTotal;
                totalFundingRemaining += (fundingRemaining != null ? ( decimal )fundingRemaining : 0);

                if (!showGoal)
                {
                    individualFundraisingGoal = null;
                    totalFundraisingGoal      = 0.00M;
                }

                if (!showTotal)
                {
                    contributionTotal = 0.00M;
                    totalContribution = 0.00M;
                }

                return(new
                {
                    groupMember.Id,
                    PersonId = groupMember.PersonId,
                    DateTimeAdded = groupMember.DateTimeAdded,
                    groupMember.Person.FullName,
                    groupMember.Person.Gender,
                    FundingRemaining = fundingRemaining,
                    GroupRoleName = a.GroupRole.Name,
                    FundingGoal = individualFundraisingGoal,
                    TotalFunding = contributionTotal,
                    Email = groupMember.Person.Email
                });
            }).ToList();

            _groupTotals.Add("TotalFundraisingGoal", totalFundraisingGoal);
            _groupTotals.Add("TotalContribution", totalContribution);
            _groupTotals.Add("TotalFundingRemaining", totalFundingRemaining);

            //
            // Attributes
            //

            BindAttributes(group);
            AddDynamicControls(group);

            // Get all the person ids in current page of query results
            var personIds = groupMemberList
                            .Select(m => m.PersonId)
                            .Distinct()
                            .ToList();

            // Get all the group member ids and the group id in current page of query results
            var groupMemberIds = new List <int>();

            foreach (var groupMember in groupMemberList
                     .Select(m => m))
            {
                groupMemberIds.Add(groupMember.Id);
            }

            var groupMemberAttributesIds = new List <int>();

            foreach (var gma in AvailableAttributes.Where(a => a.EntityTypeId == entityTypeIdGroupMember))
            {
                groupMemberAttributesIds.Add(gma.Id);
            }

            var personAttributesIds = new List <int>();

            foreach (var pa in AvailableAttributes.Where(a => a.EntityTypeId == entityTypeIdPerson))
            {
                personAttributesIds.Add(pa.Id);
            }

            // If there are any attributes that were selected to be displayed, we're going
            // to try and read all attribute values in one query and then put them into a
            // custom grid ObjectList property so that the AttributeField columns don't need
            // to do the LoadAttributes and querying of values for each row/column

            // Query the attribute values for all rows and attributes
            var attributeValues = new AttributeValueService(rockContext)
                                  .Queryable("Attribute").AsNoTracking()
                                  .Where(v =>
                                         v.EntityId.HasValue &&
                                         (
                                             (
                                                 personAttributesIds.Contains(v.AttributeId) &&
                                                 personIds.Contains(v.EntityId.Value)
                                             ) ||
                                             (
                                                 groupMemberAttributesIds.Contains(v.AttributeId) &&
                                                 groupMemberIds.Contains(v.EntityId.Value)
                                             )
                                         )
                                         )
                                  .ToList();

            // Get the attributes to add to each row's object
            BindAttributes(group);
            var attributes = new Dictionary <string, AttributeCache>();

            AvailableAttributes.ForEach(a => attributes
                                        .Add(a.Id.ToString() + a.Key, a));

            // Initialize the grid's object list
            gGroupMembers.ObjectList = new Dictionary <string, object>();

            // Loop through each of the current page's registrants and build an attribute
            // field object for storing attributes and the values for each of the registrants
            foreach (var gm in groupMemberList)
            {
                // Create a row attribute object
                var attributeFieldObject = new AttributeFieldObject();

                // Add the attributes to the attribute object
                attributeFieldObject.Attributes = attributes;

                // Add any person attribute values to object
                attributeValues
                .Where(v =>
                       personAttributesIds.Contains(v.AttributeId) &&
                       v.EntityId.Value == gm.PersonId)
                .ToList()
                .ForEach(v => attributeFieldObject.AttributeValues
                         .Add(v.AttributeId.ToString() + v.Attribute.Key, new AttributeValueCache(v)));

                // Add any group member attribute values to object
                attributeValues
                .Where(v =>
                       groupMemberAttributesIds.Contains(v.AttributeId) &&
                       v.EntityId.Value == gm.Id)
                .ToList()
                .ForEach(v => attributeFieldObject.AttributeValues
                         .Add(v.AttributeId.ToString() + v.Attribute.Key, new AttributeValueCache(v)));

                // Add row attribute object to grid's object list
                gGroupMembers.ObjectList.Add(gm.Id.ToString(), attributeFieldObject);
            }

            gGroupMembers.DataSource = groupMemberList;
            gGroupMembers.DataBind();
        }