The data access/service class for Rock.Model.GroupMember entity objects.
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute( IJobExecutionContext context )
        {
            var rockContext = new RockContext();
            var groupRequirementService = new GroupRequirementService( rockContext );
            var groupMemberRequirementService = new GroupMemberRequirementService( rockContext );
            var groupMemberService = new GroupMemberService( rockContext );

            // we only need to consider group requirements that are based on a DataView or SQL
            var groupRequirementQry = groupRequirementService.Queryable()
                .Where( a => a.GroupRequirementType.RequirementCheckType != RequirementCheckType.Manual )
                .AsNoTracking();

            var calculationExceptions = new List<Exception>();
            int groupRequirementsCalculatedMemberCount = 0;

            foreach ( var groupRequirement in groupRequirementQry.Include( i => i.GroupRequirementType ).AsNoTracking().ToList() )
            {
                try
                {
                    var currentDateTime = RockDateTime.Now;
                    var qryGroupMemberRequirementsAlreadyOK = groupMemberRequirementService.Queryable().Where( a => a.GroupRequirementId == groupRequirement.Id );

                    if ( groupRequirement.GroupRequirementType.CanExpire && groupRequirement.GroupRequirementType.ExpireInDays.HasValue )
                    {
                        // Expirable: don't recalculate members that already met the requirement within the expiredays (unless they are flagged with a warning)
                        var expireDaysCount = groupRequirement.GroupRequirementType.ExpireInDays.Value;
                        qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where( a => !a.RequirementWarningDateTime.HasValue && a.RequirementMetDateTime.HasValue && SqlFunctions.DateDiff( "day", a.RequirementMetDateTime, currentDateTime ) < expireDaysCount );
                    }
                    else
                    {
                        // No Expiration: don't recalculate members that already met the requirement
                        qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where( a => a.RequirementMetDateTime.HasValue );
                    }

                    var groupMemberQry = groupMemberService.Queryable().Where( a => a.GroupId == groupRequirement.GroupId ).AsNoTracking();
                    var personQry = groupMemberQry.Where( a => !qryGroupMemberRequirementsAlreadyOK.Any( r => r.GroupMemberId == a.Id ) ).Select( a => a.Person );

                    var results = groupRequirement.PersonQueryableMeetsGroupRequirement( rockContext, personQry, groupRequirement.GroupRoleId ).ToList();
                    groupRequirementsCalculatedMemberCount += results.Select( a => a.PersonId ).Distinct().Count();
                    foreach ( var result in results )
                    {
                        // use a fresh rockContext per Update so that ChangeTracker doesn't get bogged down
                        var rockContextUpdate = new RockContext();
                        groupRequirement.UpdateGroupMemberRequirementResult( rockContextUpdate, result.PersonId, result.MeetsGroupRequirement );
                        rockContextUpdate.SaveChanges();
                    }
                }
                catch ( Exception ex )
                {
                    calculationExceptions.Add( new Exception( string.Format( "Exception when calculating group requirement: {0} ", groupRequirement ), ex ) );
                }
            }

            context.Result = string.Format( "Group member requirements re-calculated for {0} group members", groupRequirementsCalculatedMemberCount );

            if ( calculationExceptions.Any() )
            {
                throw new AggregateException( "One or more group requirement calculations failed ", calculationExceptions );
            }
        }
Example #2
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute( RockContext rockContext, Model.WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            var checkInState = GetCheckInState( entity, out errorMessages );
            if ( checkInState != null )
            {
                var family = checkInState.CheckIn.Families.Where( f => f.Selected ).FirstOrDefault();
                if ( family != null )
                {
                    var service = new GroupMemberService( rockContext );
                    foreach ( var groupMember in service.GetByGroupId( family.Group.Id ).AsNoTracking().ToList() )
                    {
                        if ( !family.People.Any( p => p.Person.Id == groupMember.PersonId ) )
                        {
                            var person = new CheckInPerson();
                            person.Person = groupMember.Person.Clone( false );
                            person.FamilyMember = true;
                            family.People.Add( person );
                        }
                    }

                    return true;
                }
                else
                {
                    errorMessages.Add( "There is not a family that is selected" );
                }

                return false;
            }

            return false;
        }
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Init" /> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnInit( EventArgs e )
        {
            base.OnInit( e );

            try
            {
                string groupMemberKey = PageParameter( "gm" );
                if ( string.IsNullOrWhiteSpace( groupMemberKey ) )
                {
                    ShowError( "Missing Parameter Value" );
                }
                else
                {
                    var groupMemberService = new GroupMemberService();
                    var groupMember = groupMemberService.GetByUrlEncodedKey( PageParameter( "gm" ) );
                    if ( groupMember == null )
                    {
                        ShowError();
                    }
                    else
                    {
                        groupMember.GroupMemberStatus = GroupMemberStatus.Active;
                        groupMemberService.Save( groupMember, CurrentPersonId );

                        nbMessage.NotificationBoxType = NotificationBoxType.Success;
                        nbMessage.Title = "Success";
                        nbMessage.Text = GetAttributeValue( "SuccessMessage" );
                    }
                }
            }
            catch (SystemException ex)
            {
                ShowError( ex.Message );
            }
        }
Example #4
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute( RockContext rockContext, Model.WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            var checkInState = GetCheckInState( entity, out errorMessages );
            if ( checkInState != null )
            {

                bool loadAll = false;
                if ( bool.TryParse( GetAttributeValue( action, "LoadAll" ), out loadAll ) && loadAll )
                {
                    loadAll = true;
                }

                foreach ( var family in checkInState.CheckIn.Families.Where( f => f.Selected ).ToList() )
                {
                    foreach ( var person in family.People.Where( p => p.Selected || loadAll ).ToList() )
                    {
                        foreach ( var groupType in person.GroupTypes.Where( g => g.Selected || loadAll ).ToList() )
                        {
                            var kioskGroupType = checkInState.Kiosk.FilteredGroupTypes(checkInState.ConfiguredGroupTypes).Where( g => g.GroupType.Id == groupType.GroupType.Id ).FirstOrDefault();
                            if ( kioskGroupType != null )
                            {
                                foreach ( var kioskGroup in kioskGroupType.KioskGroups )
                                {
                                    bool validGroup = true;
                                    if ( groupType.GroupType.AttendanceRule == AttendanceRule.AlreadyBelongs )
                                    {
                                        validGroup = new GroupMemberService( rockContext ).Queryable()
                                            .Any( m =>
                                                m.GroupId == kioskGroup.Group.Id &&
                                                m.PersonId == person.Person.Id );
                                    }

                                    if ( validGroup && !groupType.Groups.Any( g => g.Group.Id == kioskGroup.Group.Id ) )
                                    {
                                        var checkInGroup = new CheckInGroup();
                                        checkInGroup.Group = kioskGroup.Group.Clone( false );
                                        checkInGroup.Group.CopyAttributesFrom( kioskGroup.Group );
                                        groupType.Groups.Add( checkInGroup );
                                    }
                                }
                            }
                        }
                    }
                }

                return true;
            }

            return false;
        }
Example #5
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute( Model.WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            var checkInState = GetCheckInState( entity, out errorMessages );
            if (checkInState != null)
            {
                using ( new Rock.Data.UnitOfWorkScope() )
                {
                    var personService = new PersonService();
                    var memberService = new GroupMemberService();
                    IQueryable<Person> people = null;

                    if ( checkInState.CheckIn.SearchType.Guid.Equals( new Guid( SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_PHONE_NUMBER ) ) )
                    {
                        people = personService.GetByPhonePartial( checkInState.CheckIn.SearchValue );
                    }
                    else if ( checkInState.CheckIn.SearchType.Guid.Equals( new Guid( SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_NAME ) ) )
                    {
                        people = personService.GetByFullName( checkInState.CheckIn.SearchValue );
                    }
                    else
                    {
                        errorMessages.Add( "Invalid Search Type" );
                        return false;
                    }

                    foreach ( var person in people.ToList() )
                    {
                        foreach ( var group in person.Members.Where( m => m.Group.GroupType.Guid == new Guid( SystemGuid.GroupType.GROUPTYPE_FAMILY ) ).Select( m => m.Group ).ToList() )
                        {
                            var family = checkInState.CheckIn.Families.Where( f => f.Group.Id == group.Id ).FirstOrDefault();
                            if ( family == null )
                            {
                                family = new CheckInFamily();
                                family.Group = group.Clone( false );
                                family.Group.LoadAttributes();
                                family.Caption = group.ToString();
                                family.SubCaption = memberService.GetFirstNames( group.Id ).ToList().AsDelimited( ", " );
                                checkInState.CheckIn.Families.Add( family );
                            }
                        }
                    }

                    return true;
                }
            }

            errorMessages.Add( "Invalid Check-in State" );
            return false;
        }
Example #6
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>();

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

            if ( !groupAttributeGuid.IsEmpty() )
            {
                Guid? groupGuid = action.GetWorklowAttributeValue( groupAttributeGuid ).AsGuidOrNull();

                if ( groupGuid.HasValue )
                {
                    var groupLeader = new GroupMemberService(rockContext).Queryable().AsNoTracking()
                                       .Where(g => g.Group.Guid == groupGuid && g.GroupRole.IsLeader)
                                       .Select(g => g.Person).FirstOrDefault();

                    if ( groupLeader != null )
                    {
                        // Get the attribute to set
                        Guid leaderGuid = GetAttributeValue(action, "Leader").AsGuid();
                        if ( !leaderGuid.IsEmpty() )
                        {
                            var personAttribute = AttributeCache.Read(leaderGuid, rockContext);
                            if ( personAttribute != null )
                            {
                                // If this is a person type attribute
                                if ( personAttribute.FieldTypeId == FieldTypeCache.Read(SystemGuid.FieldType.PERSON.AsGuid(), rockContext).Id )
                                {
                                    SetWorkflowAttributeValue(action, leaderGuid, groupLeader.PrimaryAlias.Guid.ToString());
                                }
                                else if ( personAttribute.FieldTypeId == FieldTypeCache.Read(SystemGuid.FieldType.TEXT.AsGuid(), rockContext).Id )
                                {
                                    SetWorkflowAttributeValue(action, leaderGuid, groupLeader.FullName);
                                }
                            }
                        }
                    }
                }
                else
                {
                    errorMessages.Add("The group could not be found!");
                }
            }

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

            return true;
        }
Example #7
0
        /// <summary>
        /// Returns a list of matching people
        /// </summary>
        /// <param name="searchterm"></param>
        /// <returns></returns>
        public override IQueryable<string> Search( string searchterm )
        {
            Guid groupTypefamilyGuid = new Guid( Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY );
            Guid homeAddressTypeGuid = new Guid( Rock.SystemGuid.DefinedValue.GROUP_LOCATION_TYPE_HOME );
            var homeAddressTypeValueId = Rock.Web.Cache.DefinedValueCache.Read( homeAddressTypeGuid ).Id;

            var service = new GroupMemberService( new RockContext() );
            return service.Queryable()
                .Where( m => m.Group.GroupType.Guid == groupTypefamilyGuid )
                .SelectMany( g => g.Group.GroupLocations )
                .Where( gl => gl.GroupLocationTypeValueId == homeAddressTypeValueId &&
                    gl.Location.Street1.Contains(searchterm) )
                .Select( gl => gl.Location.Street1)
                .Distinct();
        }
        public GroupOfTypeResult GetInGroupOfType(int personId, Guid groupTypeId)
        {
            GroupOfTypeResult result = new GroupOfTypeResult();
            result.PersonId = personId;
            result.PersonInGroup = false;
            result.GroupList = new List<GroupSummary>();

            // get person info
            Person person = new PersonService( (Rock.Data.RockContext)Service.Context ).Get( personId );

            if (person != null)
            {
                result.NickName = person.NickName;
                result.LastName = person.LastName;
            }

            // get group type info
            GroupType groupType = new GroupTypeService( (Rock.Data.RockContext)Service.Context ).Get( groupTypeId );

            if (groupType != null)
            {
                result.GroupTypeName = groupType.Name;
                result.GroupTypeIconCss = groupType.IconCssClass;
                result.GroupTypeId = groupType.Id;
            }

            // determine if person is in this type of group
            GroupMemberService groupMemberService = new GroupMemberService( (Rock.Data.RockContext)Service.Context );
            IQueryable<GroupMember> groupMembershipsQuery = groupMemberService.Queryable("Person,GroupRole,Group")
                                        .Where(t => t.Group.GroupType.Guid == groupTypeId && t.PersonId == personId )
                                        .OrderBy(g => g.GroupRole.Order);

            foreach (GroupMember member in groupMembershipsQuery)
            {
                result.PersonInGroup = true;
                GroupSummary group = new GroupSummary();
                group.GroupName = member.Group.Name;
                group.GroupId = member.Group.Id;
                group.RoleName = member.GroupRole.Name;

                result.GroupList.Add(group);
            }

            return result;
        }
Example #9
0
        public System.Net.Http.HttpResponseMessage CreateKnownRelationship( int personId, int relatedPersonId, int relationshipRoleId )
        {
            SetProxyCreation( true );
            var rockContext = this.Service.Context as RockContext;
            var personService = new PersonService(rockContext);
            var person = personService.Get(personId);
            var relatedPerson = personService.Get(relatedPersonId);

            CheckCanEdit( person );
            CheckCanEdit( relatedPerson );

            System.Web.HttpContext.Current.Items.Add( "CurrentPerson", GetPerson() );

            var groupMemberService = new GroupMemberService(rockContext);
            groupMemberService.CreateKnownRelationship( personId, relatedPersonId, relationshipRoleId );

            return ControllerContext.Request.CreateResponse( HttpStatusCode.Created );
        }
Example #10
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute( RockContext rockContext, Model.WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            var checkInState = GetCheckInState( entity, out errorMessages );
            if ( checkInState != null )
            {
                var family = checkInState.CheckIn.CurrentFamily;
                if ( family != null )
                {
                    var service = new GroupMemberService( rockContext );

                    var people = service.GetByGroupId( family.Group.Id ).AsNoTracking();
                    if ( checkInState.CheckInType != null && checkInState.CheckInType.PreventInactivePeopele )
                    {
                        var dvInactive = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE.AsGuid() );
                        if ( dvInactive != null )
                        {
                            people = people.Where( m => m.Person.RecordStatusValueId != dvInactive.Id );
                        }
                    }

                    foreach ( var groupMember in people.ToList() )
                    {
                        if ( !family.People.Any( p => p.Person.Id == groupMember.PersonId ) )
                        {
                            var person = new CheckInPerson();
                            person.Person = groupMember.Person.Clone( false );
                            person.FamilyMember = true;
                            family.People.Add( person );
                        }
                    }

                    return true;
                }
                else
                {
                    errorMessages.Add( "There is not a family that is selected" );
                }

                return false;
            }

            return false;
        }
        /// <summary>
        /// Adds the group member.
        /// </summary>
        /// <param name="familyGroup">The family group.</param>
        /// <param name="person">The person.</param>
        /// <returns></returns>
        protected GroupMember AddGroupMember( int familyGroupId, Person person )
        {
            var rockContext = new RockContext();

            GroupMember groupMember = new GroupMember();
            groupMember.IsSystem = false;
            groupMember.GroupId = familyGroupId;
            groupMember.PersonId = person.Id;
            if ( person.Age >= 18 )
            {
                groupMember.GroupRoleId = new GroupTypeRoleService( rockContext ).Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ).Id;
            }
            else
            {
                groupMember.GroupRoleId = new GroupTypeRoleService( rockContext ).Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD ) ).Id;
            }

            GroupMemberService groupMemberService = new GroupMemberService( rockContext );
            groupMemberService.Add( groupMember );
            rockContext.SaveChanges();

            return groupMember;
        }
Example #12
0
        /// <summary>
        /// The groups of a particular type that current person belongs to
        /// </summary>
        /// <returns></returns>
        protected IEnumerable<Group> PersonGroups( int groupTypeId )
        {
            string itemKey = "RockGroups:" + groupTypeId.ToString();

            var groups = Context.Items[itemKey] as IEnumerable<Group>;
            if ( groups != null )
                return groups;

            if ( Person == null )
                return null;

            var service = new GroupMemberService();
            groups = service.Queryable()
                .Where( m =>
                    m.PersonId == Person.Id &&
                    m.Group.GroupTypeId == groupTypeId )
                .Select( m => m.Group )
                .OrderByDescending( g => g.Name );

            Context.Items.Add( itemKey, groups );

            return groups;
        }
Example #13
0
        /// <summary>
        /// Returns breadcrumbs specific to the block that should be added to navigation
        /// based on the current page reference.  This function is called during the page's
        /// oninit to load any initial breadcrumbs
        /// </summary>
        /// <param name="pageReference">The page reference.</param>
        /// <returns></returns>
        public override List<BreadCrumb> GetBreadCrumbs( PageReference pageReference )
        {
            var breadCrumbs = new List<BreadCrumb>();

            int? groupMemberId = PageParameter( pageReference, "GroupMemberId" ).AsIntegerOrNull();
            if ( groupMemberId != null )
            {
                GroupMember groupMember = new GroupMemberService( new RockContext() ).Get( groupMemberId.Value );
                if ( groupMember != null )
                {
                    var parentPageReference = PageReference.GetParentPageReferences( this.RockPage, this.PageCache, pageReference ).LastOrDefault();

                    if ( parentPageReference != null )
                    {
                        var groupIdParam = parentPageReference.QueryString["GroupId"].AsIntegerOrNull();
                        if ( !groupIdParam.HasValue || groupIdParam.Value != groupMember.GroupId)
                        {
                            // if the GroupMember's Group isn't included in the breadcrumbs, make sure to add the Group to the breadcrumbs so we know which group the group member is in
                            breadCrumbs.Add( new BreadCrumb( groupMember.Group.Name, true ) );
                        }
                    }

                    breadCrumbs.Add( new BreadCrumb( groupMember.Person.FullName, pageReference ) );
                }
                else
                {
                    breadCrumbs.Add( new BreadCrumb( "New Group Member", pageReference ) );
                }
            }
            else
            {
                // don't show a breadcrumb if we don't have a pageparam to work with
            }

            return breadCrumbs;
        }
Example #14
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute( IJobExecutionContext context )
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;
            var emailTemplateGuid = dataMap.Get( "SystemEmail" ).ToString().AsGuid();
            var groupGuid = dataMap.Get( "Group" ).ToString().AsGuid();
            var sendToDescendants = dataMap.Get( "SendToDescendantGroups" ).ToString().AsBoolean();

            var rockContext = new RockContext();
            var group = new GroupService( rockContext ).Get( groupGuid );
            if ( group != null )
            {
                List<int> groupIds = new List<int>();
                GetGroupIds( groupIds, sendToDescendants, group );

                var recipients = new List<RecipientData>();

                var groupMemberList = new GroupMemberService( rockContext ).Queryable().Where( gm =>
                    groupIds.Contains( gm.GroupId ) &&
                    gm.GroupMemberStatus == GroupMemberStatus.Active )
                    .ToList();

                foreach ( GroupMember groupMember in groupMemberList )
                {
                    var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields( null );
                    mergeFields.Add( "Person", groupMember.Person );
                    mergeFields.Add( "GroupMember", groupMember );
                    mergeFields.Add( "Group", groupMember.Group );

                    recipients.Add( new RecipientData( groupMember.Person.Email, mergeFields ) );
                }

                var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read( rockContext ).GetValue( "ExternalApplicationRoot" );
                Email.Send( emailTemplateGuid, recipients, appRoot );
                context.Result = string.Format( "{0} emails sent", recipients.Count() );
            }
        }
        /// <summary>
        /// Returns breadcrumbs specific to the block that should be added to navigation
        /// based on the current page reference.  This function is called during the page's
        /// oninit to load any initial breadcrumbs
        /// </summary>
        /// <param name="pageReference">The page reference.</param>
        /// <returns></returns>
        public override List<BreadCrumb> GetBreadCrumbs( PageReference pageReference )
        {
            var breadCrumbs = new List<BreadCrumb>();

            int? groupMemberId = PageParameter( pageReference, "GroupMemberId" ).AsIntegerOrNull();
            if ( groupMemberId != null )
            {
                GroupMember groupMember = new GroupMemberService( new RockContext() ).Get( groupMemberId.Value );
                if ( groupMember != null )
                {
                    breadCrumbs.Add( new BreadCrumb( groupMember.Person.FullName, pageReference ) );
                }
                else
                {
                    breadCrumbs.Add( new BreadCrumb( "New Group Member", pageReference ) );
                }
            }
            else
            {
                // don't show a breadcrumb if we don't have a pageparam to work with
            }

            return breadCrumbs;
        }
        /// <summary>
        /// Handles the SaveClick event of the modalAddPerson control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        void modalAddPerson_SaveClick( object sender, EventArgs e )
        {
            if ( hfActiveTab.Value == "Existing" )
            {
                if ( ppPerson.PersonId.HasValue && !FamilyMembers.Any( m => m.Id == ppPerson.PersonId.Value ) )
                {
                    var rockContext = new RockContext();
                    var person = new PersonService( rockContext ).Get( ppPerson.PersonId.Value );
                    if ( person != null )
                    {
                        var familyMember = new FamilyMember();
                        familyMember.SetValuesFromPerson( person );

                        var familyRoleIds = familyRoles.Select( r => r.Id ).ToList();

                        var existingFamilyRoles = new GroupMemberService( rockContext ).Queryable( "GroupRole" )
                            .Where( m => m.PersonId == person.Id && familyRoleIds.Contains( m.GroupRoleId ) )
                            .OrderBy( m => m.GroupRole.Order )
                            .ToList();

                        var existingRole = existingFamilyRoles.Select( m => m.GroupRole ).FirstOrDefault();
                        if ( existingRole != null )
                        {
                            familyMember.RoleGuid = existingRole.Guid;
                            familyMember.RoleName = existingRole.Name;
                        }

                        familyMember.ExistingFamilyMember = existingFamilyRoles.Any( r => r.GroupId == _family.Id );
                        familyMember.RemoveFromOtherFamilies = cbRemoveOtherFamilies.Checked;

                        FamilyMembers.Add( familyMember );
                    }

                }
            }
            else
            {
                var familyMember = new FamilyMember();
                familyMember.FirstName = tbNewPersonFirstName.Text;
                familyMember.NickName = tbNewPersonFirstName.Text;
                familyMember.LastName = tbNewPersonLastName.Text;
                familyMember.Gender = ddlNewPersonGender.SelectedValueAsEnum<Gender>();
                familyMember.BirthDate = dpNewPersonBirthDate.SelectedDate;
                var role = familyRoles.Where( r => r.Id == ( rblNewPersonRole.SelectedValueAsInt() ?? 0 ) ).FirstOrDefault();
                if ( role != null )
                {
                    familyMember.RoleGuid = role.Guid;
                    familyMember.RoleName = role.Name;
                }

                FamilyMembers.Add( familyMember );
            }

            ppPerson.Required = false;
            tbNewPersonFirstName.Required = false;
            tbNewPersonLastName.Required = false;

            confirmExit.Enabled = true;

            hfActiveTab.Value = string.Empty;

            modalAddPerson.Hide();

            BindMembers();
        }
Example #17
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;
            Group group = null;
            string noteValue = string.Empty;
            string captionValue = string.Empty;
            bool isAlert = false;

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

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

                if ( groupGuid.HasValue )
                {
                    group = new GroupService( rockContext ).Get( groupGuid.Value );

                    if ( group == null )
                    {
                        errorMessages.Add( "The group provided does not exist." );
                    }
                }
                else
                {
                    errorMessages.Add( "Invalid group provided." );
                }
            }

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

            Guid guid = personAttribute.AsGuid();
            if ( !guid.IsEmpty() )
            {
                var attribute = AttributeCache.Read( guid, rockContext );
                if ( attribute != null )
                {
                    string value = action.GetWorklowAttributeValue( guid );
                    personAliasGuid = value.AsGuid();
                }

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

            // get caption
            captionValue = GetAttributeValue( action, "Caption" );
            guid = captionValue.AsGuid();
            if ( guid.IsEmpty() )
            {
                captionValue = captionValue.ResolveMergeFields( GetMergeFields( action ) );
            }
            else
            {
                var workflowAttributeValue = action.GetWorklowAttributeValue( guid );

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

            // get group member note
            noteValue = GetAttributeValue( action, "Note" );
            guid = noteValue.AsGuid();
            if ( guid.IsEmpty() )
            {
                noteValue = noteValue.ResolveMergeFields( GetMergeFields( action ) );
            }
            else
            {
                var workflowAttributeValue = action.GetWorklowAttributeValue( guid );

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

            // get alert type
            string isAlertString = GetAttributeValue( action, "IsAlert" );
            guid = isAlertString.AsGuid();
            if ( guid.IsEmpty() )
            {
                isAlert = isAlertString.AsBoolean();
            }
            else
            {
                var workflowAttributeValue = action.GetWorklowAttributeValue( guid );

                if ( workflowAttributeValue != null )
                {
                    isAlert = workflowAttributeValue.AsBoolean();
                }
            }

            // get note type
            NoteTypeCache noteType = null;
            Guid noteTypeGuid = GetAttributeValue( action, "NoteType" ).AsGuid();

            if ( !noteTypeGuid.IsEmpty() )
            {
                noteType = NoteTypeCache.Read( noteTypeGuid, rockContext );

                if (noteType == null )
                {
                    errorMessages.Add( "The note type provided does not exist." );
                }
            }
            else
            {
                errorMessages.Add( "Invalid note type provided." );
            }

            // set note
            if ( group != null && person != null && noteType != null )
            {
                var groupMembers = new GroupMemberService( rockContext ).Queryable()
                                .Where( m => m.Group.Guid == groupGuid && m.PersonId == person.Id ).ToList();

                if ( groupMembers.Count() > 0 )
                {
                    foreach ( var groupMember in groupMembers )
                    {
                        NoteService noteservice = new NoteService( rockContext );
                        Note note = new Note();
                        noteservice.Add( note );

                        note.NoteTypeId = noteType.Id;
                        note.Text = noteValue;
                        note.IsAlert = isAlert;
                        note.Caption = captionValue;
                        note.EntityId = groupMember.Id;

                        rockContext.SaveChanges();
                    }
                }
                else
                {
                    errorMessages.Add( string.Format("{0} is not a member of the group {1}.", person.FullName, group.Name ));
                }
            }

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

            return true;
        }
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnLoad( EventArgs e )
        {
            base.OnLoad( e );

            if ( !Page.IsPostBack )
            {
                RockContext rockContext = new RockContext();

                Group group = null;
                Guid personGuid = Guid.Empty;

                // get group from url
                if ( Request["GroupId"] != null || Request["GroupGuid"] != null )
                {
                    if ( Request["GroupId"] != null )
                    {
                        int groupId = 0;
                        if ( Int32.TryParse( Request["GroupId"], out groupId ) )
                        {
                            group = new GroupService( rockContext ).Queryable().Where( g => g.Id == groupId ).FirstOrDefault();
                        }
                    }
                    else
                    {
                        Guid groupGuid = Request["GroupGuid"].AsGuid();
                        group = new GroupService( rockContext ).Queryable().Where( g => g.Guid == groupGuid ).FirstOrDefault();
                    }
                }
                else
                {
                    Guid groupGuid = Guid.Empty;
                    if ( Guid.TryParse( GetAttributeValue( "DefaultGroup" ), out groupGuid ) ) {
                        group = new GroupService( rockContext ).Queryable().Where( g => g.Guid == groupGuid ).FirstOrDefault(); ;
                    }
                }

                if ( group == null )
                {
                    lAlerts.Text = "Could not determine the group to add to.";
                    return;
                }

                // get person
                Person person = null;

                if ( !string.IsNullOrWhiteSpace(Request["PersonGuid"]) )
                {
                    person = new PersonService( rockContext ).Get( Request["PersonGuid"].AsGuid() );
                }

                if ( person == null )
                {
                    lAlerts.Text += "A person could not be found for the identifier provided.";
                    return;
                }

                // hide alert
                divAlert.Visible = false;

                // get status
                var groupMemberStatus = this.GetAttributeValue( "GroupMemberStatus" ).ConvertToEnum<GroupMemberStatus>( GroupMemberStatus.Active );

                // load merge fields
                var mergeFields = new Dictionary<string, object>();
                mergeFields.Add( "Group", group );
                mergeFields.Add( "Person", person );
                mergeFields.Add( "CurrentPerson", CurrentPerson );

                // show debug info?
                bool enableDebug = GetAttributeValue( "EnableDebug" ).AsBoolean();
                if ( enableDebug && IsUserAuthorized( Authorization.EDIT ) )
                {
                    lDebug.Visible = true;
                    lDebug.Text = mergeFields.lavaDebugInfo();
                }

                var groupMemberService = new GroupMemberService(rockContext);

                var groupMemberList = groupMemberService.Queryable()
                                        .Where( m => m.GroupId == group.Id && m.PersonId == person.Id )
                                        .ToList();

                if (groupMemberList.Count > 0 )
                {
                    foreach(var groupMember in groupMemberList )
                    {
                        if ( GetAttributeValue( "Inactivate" ).AsBoolean() )
                        {
                            groupMember.GroupMemberStatus = GroupMemberStatus.Inactive;
                        }
                        else
                        {
                            groupMemberService.Delete( groupMember );
                        }

                        rockContext.SaveChanges();
                    }

                    lContent.Text = GetAttributeValue( "SuccessMessage" ).ResolveMergeFields( mergeFields );
                }
                else
                {
                    if ( GetAttributeValue( "WarnWhenNotInGroup").AsBoolean() )
                    {
                        lContent.Text = GetAttributeValue( "NotInGroupMessage" ).ResolveMergeFields( mergeFields );
                    }
                    else
                    {
                        lContent.Text = GetAttributeValue( "SuccessMessage" ).ResolveMergeFields( mergeFields );
                    }
                }
            }
        }
Example #19
0
        /// <summary>
        /// Creates a Linq Expression that can be applied to an IQueryable to filter the result set.
        /// </summary>
        /// <param name="entityType">The type of entity in the result set.</param>
        /// <param name="serviceInstance">A service instance that can be queried to obtain the result set.</param>
        /// <param name="parameterExpression">The input parameter that will be injected into the filter expression.</param>
        /// <param name="selection">A formatted string representing the filter settings.</param>
        /// <returns>
        /// A Linq Expression that can be used to filter an IQueryable.
        /// </returns>
        public override Expression GetExpression( Type entityType, IService serviceInstance, ParameterExpression parameterExpression, string selection )
        {
            var settings = new SelectSettings( selection );

            var context = (RockContext)serviceInstance.Context;

            //
            // Evaluate the Data View that defines the candidate Groups.
            //
            var dataView = DataComponentSettingsHelper.GetDataViewForFilterComponent( settings.DataViewGuid, context );

            var groupService = new GroupService( context );

            var groupQuery = groupService.Queryable();

            if (dataView != null)
            {
                groupQuery = DataComponentSettingsHelper.FilterByDataView( groupQuery, dataView, groupService );
            }
            else
            {
                // Apply a default Group filter to only show Groups that would be visible in a Group List.
                groupQuery = groupQuery.Where( x => x.GroupType.ShowInGroupList );
            }

            var groupKeys = groupQuery.Select( x => x.Id );

            //
            // Construct the Query to return the list of Group Members matching the filter conditions.
            //
            var groupMemberQuery = new GroupMemberService( context ).Queryable();

            // Filter By Group.
            groupMemberQuery = groupMemberQuery.Where( x => groupKeys.Contains( x.GroupId ) );

            // Filter By Group Role Type.
            switch ( settings.RoleType )
            {
                case RoleTypeSpecifier.Member:
                    groupMemberQuery = groupMemberQuery.Where( x => !x.GroupRole.IsLeader );
                    break;

                case RoleTypeSpecifier.Leader:
                    groupMemberQuery = groupMemberQuery.Where( x => x.GroupRole.IsLeader );
                    break;
            }

            // Filter by Group Member Status.
            if ( settings.MemberStatus.HasValue )
            {
                groupMemberQuery = groupMemberQuery.Where( x => x.GroupMemberStatus == settings.MemberStatus.Value );
            }

            //
            // Create a Select Expression to return the Person records referenced by the Group Members.
            //
            var personGroupsQuery = new PersonService( context ).Queryable()
                                                                .Where( p => groupMemberQuery.Select( gm => gm.PersonId ).Contains( p.Id ) );

            var selectExpression = FilterExpressionExtractor.Extract<Model.Person>( personGroupsQuery, parameterExpression, "p" );

            return selectExpression;
        }
 /// <summary>
 /// Loads the drop downs.
 /// </summary>
 private void LoadDropDowns( BenevolenceRequest benevolenceRequest )
 {
     ddlRequestStatus.BindToDefinedType( DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.BENEVOLENCE_REQUEST_STATUS ) ), false );
     ddlConnectionStatus.BindToDefinedType( DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_CONNECTION_STATUS ) ), true );
     Guid groupGuid = GetAttributeValue( "CaseWorkerGroup" ).AsGuid();
     var listData = new GroupMemberService( new RockContext() ).Queryable( "Person, Group" )
         .Where( gm => gm.Group.Guid == groupGuid )
         .Select( gm => gm.Person )
         .ToList();
     ddlCaseWorker.DataSource = listData;
     ddlCaseWorker.DataTextField = "FullName";
     ddlCaseWorker.DataValueField = "PrimaryAliasId";
     ddlCaseWorker.DataBind();
     ddlCaseWorker.Items.Insert( 0, new ListItem() );
 }
Example #21
0
        private Person GetPersonOrBusiness( Person person )
        {
            if ( person != null && phGiveAsOption.Visible && !tglGiveAsOption.Checked )
            {
                var rockContext = new RockContext();
                var personService = new PersonService( rockContext );
                var groupService = new GroupService( rockContext );
                var groupMemberService = new GroupMemberService( rockContext );

                Group familyGroup = null;

                Person business = null;
                int? businessId = cblBusiness.SelectedValueAsInt();
                if ( businessId.HasValue )
                {
                    business = personService.Get( businessId.Value );
                }

                if ( business == null )
                {
                    DefinedValueCache dvcConnectionStatus = DefinedValueCache.Read( GetAttributeValue( "ConnectionStatus" ).AsGuid() );
                    DefinedValueCache dvcRecordStatus = DefinedValueCache.Read( GetAttributeValue( "RecordStatus" ).AsGuid() );

                    // Create Person
                    business = new Person();
                    business.LastName = txtLastName.Text;
                    business.IsEmailActive = true;
                    business.EmailPreference = EmailPreference.EmailAllowed;
                    business.RecordTypeValueId = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_BUSINESS.AsGuid() ).Id;
                    if ( dvcConnectionStatus != null )
                    {
                        business.ConnectionStatusValueId = dvcConnectionStatus.Id;
                    }

                    if ( dvcRecordStatus != null )
                    {
                        business.RecordStatusValueId = dvcRecordStatus.Id;
                    }

                    // Create Person/Family
                    familyGroup = PersonService.SaveNewPerson( business, rockContext, null, false );

                    // Get the relationship roles to use
                    var knownRelationshipGroupType = GroupTypeCache.Read( Rock.SystemGuid.GroupType.GROUPTYPE_KNOWN_RELATIONSHIPS.AsGuid() );
                    int businessContactRoleId = knownRelationshipGroupType.Roles
                        .Where( r =>
                            r.Guid.Equals( Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_BUSINESS_CONTACT.AsGuid() ) )
                        .Select( r => r.Id )
                        .FirstOrDefault();
                    int businessRoleId = knownRelationshipGroupType.Roles
                        .Where( r =>
                            r.Guid.Equals( Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_BUSINESS.AsGuid() ) )
                        .Select( r => r.Id )
                        .FirstOrDefault();
                    int ownerRoleId = knownRelationshipGroupType.Roles
                        .Where( r =>
                            r.Guid.Equals( Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_OWNER.AsGuid() ) )
                        .Select( r => r.Id )
                        .FirstOrDefault();

                    if ( ownerRoleId > 0 && businessContactRoleId > 0 && businessRoleId > 0 )
                    {
                        // get the known relationship group of the business contact
                        // add the business as a group member of that group using the group role of GROUPROLE_KNOWN_RELATIONSHIPS_BUSINESS
                        var contactKnownRelationshipGroup = groupMemberService.Queryable()
                            .Where( g =>
                                g.GroupRoleId == ownerRoleId &&
                                g.PersonId == person.Id )
                            .Select( g => g.Group )
                            .FirstOrDefault();
                        if ( contactKnownRelationshipGroup == null )
                        {
                            // In some cases person may not yet have a know relationship group type
                            contactKnownRelationshipGroup = new Group();
                            groupService.Add( contactKnownRelationshipGroup );
                            contactKnownRelationshipGroup.Name = "Known Relationship";
                            contactKnownRelationshipGroup.GroupTypeId = knownRelationshipGroupType.Id;

                            var ownerMember = new GroupMember();
                            ownerMember.PersonId = person.Id;
                            ownerMember.GroupRoleId = ownerRoleId;
                            contactKnownRelationshipGroup.Members.Add( ownerMember );
                        }
                        var groupMember = new GroupMember();
                        groupMember.PersonId = business.Id;
                        groupMember.GroupRoleId = businessRoleId;
                        contactKnownRelationshipGroup.Members.Add( groupMember );

                        // get the known relationship group of the business
                        // add the business contact as a group member of that group using the group role of GROUPROLE_KNOWN_RELATIONSHIPS_BUSINESS_CONTACT
                        var businessKnownRelationshipGroup = groupMemberService.Queryable()
                            .Where( g =>
                                g.GroupRole.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_OWNER ) ) &&
                                g.PersonId == business.Id )
                            .Select( g => g.Group )
                            .FirstOrDefault();
                        if ( businessKnownRelationshipGroup == null )
                        {
                            // In some cases business may not yet have a know relationship group type
                            businessKnownRelationshipGroup = new Group();
                            groupService.Add( businessKnownRelationshipGroup );
                            businessKnownRelationshipGroup.Name = "Known Relationship";
                            businessKnownRelationshipGroup.GroupTypeId = knownRelationshipGroupType.Id;

                            var ownerMember = new GroupMember();
                            ownerMember.PersonId = business.Id;
                            ownerMember.GroupRoleId = ownerRoleId;
                            businessKnownRelationshipGroup.Members.Add( ownerMember );
                        }
                        var businessGroupMember = new GroupMember();
                        businessGroupMember.PersonId = person.Id;
                        businessGroupMember.GroupRoleId = businessContactRoleId;
                        businessKnownRelationshipGroup.Members.Add( businessGroupMember );

                        rockContext.SaveChanges();
                    }
                }

                business.LastName = txtBusinessName.Text;
                business.Email = txtEmail.Text;

                if ( GetAttributeValue( "DisplayPhone" ).AsBooleanOrNull() ?? false )
                {
                    var numberTypeId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_WORK ) ).Id;
                    var phone = business.PhoneNumbers.FirstOrDefault( p => p.NumberTypeValueId == numberTypeId );
                    if ( phone == null )
                    {
                        phone = new PhoneNumber();
                        business.PhoneNumbers.Add( phone );
                        phone.NumberTypeValueId = numberTypeId;
                    }
                    phone.CountryCode = PhoneNumber.CleanNumber( pnbPhone.CountryCode );
                    phone.Number = PhoneNumber.CleanNumber( pnbPhone.Number );
                }

                if ( familyGroup == null )
                {
                    var groupLocationService = new GroupLocationService( rockContext );
                    if ( GroupLocationId.HasValue )
                    {
                        familyGroup = groupLocationService.Queryable()
                            .Where( gl => gl.Id == GroupLocationId.Value )
                            .Select( gl => gl.Group )
                            .FirstOrDefault();
                    }
                    else
                    {
                        familyGroup = personService.GetFamilies( business.Id ).FirstOrDefault();
                    }
                }

                rockContext.SaveChanges();

                if ( familyGroup != null )
                {
                    GroupService.AddNewGroupAddress(
                        rockContext,
                        familyGroup,
                        Rock.SystemGuid.DefinedValue.GROUP_LOCATION_TYPE_WORK,
                        acAddress.Street1, acAddress.Street2, acAddress.City, acAddress.State, acAddress.PostalCode, acAddress.Country,
                        false );
                }

                return business;
            }

            return person;
        }
Example #22
0
        /// <summary>
        /// Gets occurrence data for the selected group
        /// </summary>
        /// <param name="group">The group.</param>
        /// <param name="fromDateTime">From date time.</param>
        /// <param name="toDateTime">To date time.</param>
        /// <param name="locationIds">The location ids.</param>
        /// <param name="scheduleIds">The schedule ids.</param>
        /// <param name="loadSummaryData">if set to <c>true</c> [load summary data].</param>
        /// <param name="campusId">The campus identifier.</param>
        /// <returns></returns>
        public List <ScheduleOccurrence> GetGroupOccurrences(Group group, DateTime?fromDateTime, DateTime?toDateTime,
                                                             List <int> locationIds, List <int> scheduleIds, bool loadSummaryData, int?campusId)
        {
            var occurrences = new List <ScheduleOccurrence>();

            if (group != null)
            {
                var rockContext       = (RockContext)this.Context;
                var attendanceService = new AttendanceService(rockContext);
                var scheduleService   = new ScheduleService(rockContext);
                var locationService   = new LocationService(rockContext);

                using (new Rock.Data.QueryHintScope(rockContext, QueryHintType.RECOMPILE))
                {
                    // Set up an 'occurrences' query for the group
                    var qry = attendanceService
                              .Queryable().AsNoTracking()
                              .Where(a => a.GroupId == group.Id);

                    // Filter by date range
                    if (fromDateTime.HasValue)
                    {
                        var fromDate = fromDateTime.Value.Date;
                        qry = qry.Where(a => DbFunctions.TruncateTime(a.StartDateTime) >= (fromDate));
                    }
                    if (toDateTime.HasValue)
                    {
                        var toDate = toDateTime.Value.Date;
                        qry = qry.Where(a => DbFunctions.TruncateTime(a.StartDateTime) < (toDate));
                    }

                    // Location Filter
                    if (locationIds.Any())
                    {
                        qry = qry.Where(a => locationIds.Contains(a.LocationId ?? 0));
                    }

                    // Schedule Filter
                    if (scheduleIds.Any())
                    {
                        qry = qry.Where(a => scheduleIds.Contains(a.ScheduleId ?? 0));
                    }

                    // Get the unique combination of location/schedule/date for the selected group
                    var occurrenceDates = qry
                                          .Select(a => new
                    {
                        a.LocationId,
                        a.ScheduleId,
                        Date = DbFunctions.TruncateTime(a.StartDateTime)
                    })
                                          .Distinct()
                                          .ToList();

                    // Get the locations for each unique location id
                    var selectedlocationIds = occurrenceDates.Select(o => o.LocationId).Distinct().ToList();

                    var locations = locationService
                                    .Queryable().AsNoTracking()
                                    .Where(l => selectedlocationIds.Contains(l.Id))
                                    .Select(l => new { l.Id, l.ParentLocationId, l.Name })
                                    .ToList();
                    var locationNames = new Dictionary <int, string>();
                    locations.ForEach(l => locationNames.Add(l.Id, l.Name));

                    // Get the parent location path for each unique location
                    var parentlocationPaths = new Dictionary <int, string>();
                    locations
                    .Where(l => l.ParentLocationId.HasValue)
                    .Select(l => l.ParentLocationId.Value)
                    .Distinct()
                    .ToList()
                    .ForEach(l => parentlocationPaths.Add(l, locationService.GetPath(l)));
                    var locationPaths = new Dictionary <int, string>();
                    locations
                    .Where(l => l.ParentLocationId.HasValue)
                    .ToList()
                    .ForEach(l => locationPaths.Add(l.Id, parentlocationPaths[l.ParentLocationId.Value]));

                    // Get the schedules for each unique schedule id
                    var selectedScheduleIds = occurrenceDates.Select(o => o.ScheduleId).Distinct().ToList();
                    var schedules           = scheduleService
                                              .Queryable().AsNoTracking()
                                              .Where(s => selectedScheduleIds.Contains(s.Id))
                                              .ToList();
                    var scheduleNames      = new Dictionary <int, string>();
                    var scheduleStartTimes = new Dictionary <int, TimeSpan>();
                    schedules
                    .ForEach(s =>
                    {
                        scheduleNames.Add(s.Id, s.Name);
                        scheduleStartTimes.Add(s.Id, s.StartTimeOfDay);
                    });

                    foreach (var occurrence in occurrenceDates.Where(o => o.Date.HasValue))
                    {
                        occurrences.Add(
                            new ScheduleOccurrence(
                                occurrence.Date.Value,
                                occurrence.ScheduleId.HasValue && scheduleStartTimes.ContainsKey(occurrence.ScheduleId.Value) ?
                                scheduleStartTimes[occurrence.ScheduleId.Value] : new TimeSpan(),
                                occurrence.ScheduleId,
                                occurrence.ScheduleId.HasValue && scheduleNames.ContainsKey(occurrence.ScheduleId.Value) ?
                                scheduleNames[occurrence.ScheduleId.Value] : string.Empty,
                                occurrence.LocationId,
                                occurrence.LocationId.HasValue && locationNames.ContainsKey(occurrence.LocationId.Value) ?
                                locationNames[occurrence.LocationId.Value] : string.Empty,
                                occurrence.LocationId.HasValue && locationPaths.ContainsKey(occurrence.LocationId.Value) ?
                                locationPaths[occurrence.LocationId.Value] : string.Empty
                                ));
                    }
                }

                // Load the attendance data for each occurrence
                if (loadSummaryData && occurrences.Any())
                {
                    var minDate       = occurrences.Min(o => o.Date);
                    var maxDate       = occurrences.Max(o => o.Date).AddDays(1);
                    var attendanceQry = attendanceService
                                        .Queryable().AsNoTracking()
                                        .Where(a =>
                                               a.GroupId.HasValue &&
                                               a.GroupId == group.Id &&
                                               a.StartDateTime >= minDate &&
                                               a.StartDateTime < maxDate &&
                                               a.PersonAlias != null &&
                                               a.PersonAliasId.HasValue)
                                        .Select(a => new
                    {
                        a.LocationId,
                        a.ScheduleId,
                        a.StartDateTime,
                        a.DidAttend,
                        a.DidNotOccur,
                        a.PersonAliasId,
                        PersonId = a.PersonAlias.PersonId
                    });

                    if (campusId.HasValue)
                    {
                        var familyGroupType = GroupTypeCache.Read(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid());
                        var campusQry       = new GroupMemberService(rockContext)
                                              .Queryable()
                                              .Where(g =>
                                                     g.Group != null &&
                                                     g.Group.GroupTypeId == familyGroupType.Id &&
                                                     g.Group.CampusId.HasValue &&
                                                     g.Group.CampusId.Value == campusId.Value
                                                     )
                                              .Select(m => m.PersonId);

                        attendanceQry = attendanceQry
                                        .Where(s => campusQry.Contains(s.PersonId));
                    }

                    var attendances = attendanceQry.ToList();

                    foreach (var summary in attendances
                             .GroupBy(a => new
                    {
                        a.LocationId,
                        a.ScheduleId,
                        Date = a.StartDateTime.Date
                    })
                             .Select(a => new
                    {
                        a.Key.LocationId,
                        a.Key.ScheduleId,
                        a.Key.Date,
                        DidAttendCount = a
                                         .Where(t => t.DidAttend.HasValue && t.DidAttend.Value)
                                         .Select(t => t.PersonAliasId.Value)
                                         .Distinct()
                                         .Count(),
                        DidNotOccurCount = a
                                           .Where(t => t.DidNotOccur.HasValue && t.DidNotOccur.Value)
                                           .Select(t => t.PersonAliasId.Value)
                                           .Distinct()
                                           .Count(),
                        TotalCount = a
                                     .Select(t => t.PersonAliasId)
                                     .Distinct()
                                     .Count()
                    }))
                    {
                        var occurrence = occurrences
                                         .Where(o =>
                                                o.ScheduleId.Equals(summary.ScheduleId) &&
                                                o.LocationId.Equals(summary.LocationId) &&
                                                o.Date.Equals(summary.Date))
                                         .FirstOrDefault();
                        if (occurrence != null)
                        {
                            occurrence.DidAttendCount   = summary.DidAttendCount;
                            occurrence.DidNotOccurCount = summary.DidNotOccurCount;
                            occurrence.TotalCount       = summary.TotalCount;
                        }
                    }
                }

                // Create any missing occurrences from the group's schedule (not location schedules)
                Schedule groupSchedule = null;
                if (group.ScheduleId.HasValue)
                {
                    groupSchedule = group.Schedule;
                    if (groupSchedule == null)
                    {
                        groupSchedule = new ScheduleService(rockContext).Get(group.ScheduleId.Value);
                    }
                }

                if (groupSchedule != null)
                {
                    var newOccurrences = new List <ScheduleOccurrence>();

                    var existingDates = occurrences
                                        .Where(o => o.ScheduleId.Equals(groupSchedule.Id))
                                        .Select(o => o.Date)
                                        .Distinct()
                                        .ToList();

                    var startDate = fromDateTime.HasValue ? fromDateTime.Value : RockDateTime.Today.AddMonths(-2);
                    var endDate   = toDateTime.HasValue ? toDateTime.Value : RockDateTime.Today.AddDays(1);

                    if (!string.IsNullOrWhiteSpace(groupSchedule.iCalendarContent))
                    {
                        // If schedule has an iCal schedule, get all the past occurrences
                        foreach (var occurrence in groupSchedule.GetOccurrences(startDate, endDate))
                        {
                            var scheduleOccurrence = new ScheduleOccurrence(
                                occurrence.Period.StartTime.Date, occurrence.Period.StartTime.TimeOfDay, groupSchedule.Id, groupSchedule.Name);
                            if (!existingDates.Contains(scheduleOccurrence.Date))
                            {
                                newOccurrences.Add(scheduleOccurrence);
                            }
                        }
                    }
                    else
                    {
                        // if schedule does not have an iCal, then check for weekly schedule and calculate occurrences starting with first attendance or current week
                        if (groupSchedule.WeeklyDayOfWeek.HasValue)
                        {
                            // default to start with date 2 months earlier
                            startDate = fromDateTime.HasValue ? fromDateTime.Value : RockDateTime.Today.AddMonths(-2);
                            if (existingDates.Any(d => d < startDate))
                            {
                                startDate = existingDates.Min();
                            }

                            // Back up start time to the correct day of week
                            while (startDate.DayOfWeek != groupSchedule.WeeklyDayOfWeek.Value)
                            {
                                startDate = startDate.AddDays(-1);
                            }

                            // Add the start time
                            if (groupSchedule.WeeklyTimeOfDay.HasValue)
                            {
                                startDate = startDate.Add(groupSchedule.WeeklyTimeOfDay.Value);
                            }

                            // Create occurrences up to current time
                            while (startDate < endDate)
                            {
                                if (!existingDates.Contains(startDate.Date))
                                {
                                    var scheduleOccurrence = new ScheduleOccurrence(startDate.Date, startDate.TimeOfDay, groupSchedule.Id, groupSchedule.Name);
                                    newOccurrences.Add(scheduleOccurrence);
                                }

                                startDate = startDate.AddDays(7);
                            }
                        }
                    }

                    if (newOccurrences.Any())
                    {
                        // Filter Exclusions
                        var groupType = GroupTypeCache.Read(group.GroupTypeId);
                        foreach (var exclusion in groupType.GroupScheduleExclusions)
                        {
                            if (exclusion.Start.HasValue && exclusion.End.HasValue)
                            {
                                foreach (var occurrence in newOccurrences.ToList())
                                {
                                    if (occurrence.Date >= exclusion.Start.Value &&
                                        occurrence.Date < exclusion.End.Value.AddDays(1))
                                    {
                                        newOccurrences.Remove(occurrence);
                                    }
                                }
                            }
                        }
                    }

                    foreach (var occurrence in newOccurrences)
                    {
                        occurrences.Add(occurrence);
                    }
                }
            }

            return(occurrences);
        }
Example #23
0
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid()
        {
            if ( _group != null )
            {
                pnlGroupMembers.Visible = true;

                lHeading.Text = string.Format( "{0} {1}", _group.GroupType.GroupTerm, _group.GroupType.GroupMemberTerm.Pluralize() );

                if ( _group.GroupType.Roles.Any() )
                {
                    nbRoleWarning.Visible = false;
                    rFilter.Visible = true;
                    gGroupMembers.Visible = true;

                    var rockContext = new RockContext();

                    GroupMemberService groupMemberService = new GroupMemberService( rockContext );
                    var qry = groupMemberService.Queryable( "Person,GroupRole", true ).AsNoTracking()
                        .Where( m => m.GroupId == _group.Id );

                    // Filter by First Name
                    string firstName = tbFirstName.Text;
                    if ( !string.IsNullOrWhiteSpace( firstName ) )
                    {
                        qry = qry.Where( m => m.Person.FirstName.StartsWith( firstName ) );
                    }

                    // Filter by Last Name
                    string lastName = tbLastName.Text;
                    if ( !string.IsNullOrWhiteSpace( lastName ) )
                    {
                        qry = qry.Where( m => m.Person.LastName.StartsWith( lastName ) );
                    }

                    // Filter by role
                    var validGroupTypeRoles = _group.GroupType.Roles.Select( r => r.Id ).ToList();
                    var roles = new List<int>();
                    foreach ( string role in cblRole.SelectedValues )
                    {
                        if ( !string.IsNullOrWhiteSpace( role ) )
                        {
                            int roleId = int.MinValue;
                            if ( int.TryParse( role, out roleId ) && validGroupTypeRoles.Contains( roleId ) )
                            {
                                roles.Add( roleId );
                            }
                        }
                    }

                    if ( roles.Any() )
                    {
                        qry = qry.Where( m => roles.Contains( m.GroupRoleId ) );
                    }

                    // Filter by Status
                    var statuses = new List<GroupMemberStatus>();
                    foreach ( string status in cblStatus.SelectedValues )
                    {
                        if ( !string.IsNullOrWhiteSpace( status ) )
                        {
                            statuses.Add( status.ConvertToEnum<GroupMemberStatus>() );
                        }
                    }

                    if ( statuses.Any() )
                    {
                        qry = qry.Where( m => statuses.Contains( m.GroupMemberStatus ) );
                    }

                    // Filter query by any configured attribute filters
                    if ( AvailableAttributes != null && AvailableAttributes.Any() )
                    {
                        var attributeValueService = new AttributeValueService( rockContext );
                        var parameterExpression = attributeValueService.ParameterExpression;

                        foreach ( var attribute in AvailableAttributes )
                        {
                            var filterControl = phAttributeFilters.FindControl( "filter_" + attribute.Id.ToString() );
                            if ( filterControl != null )
                            {
                                var filterValues = attribute.FieldType.Field.GetFilterValues( filterControl, attribute.QualifierValues, Rock.Reporting.FilterMode.SimpleFilter );
                                var expression = attribute.FieldType.Field.AttributeFilterExpression( attribute.QualifierValues, filterValues, parameterExpression );
                                if ( expression != null )
                                {
                                    var attributeValues = attributeValueService
                                        .Queryable()
                                        .Where( v => v.Attribute.Id == attribute.Id );

                                    attributeValues = attributeValues.Where( parameterExpression, expression, null );

                                    qry = qry.Where( w => attributeValues.Select( v => v.EntityId ).Contains( w.Id ) );
                                }
                            }
                        }
                    }

                    _inactiveStatus = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE );

                    SortProperty sortProperty = gGroupMembers.SortProperty;

                    bool hasGroupRequirements = new GroupRequirementService( rockContext ).Queryable().Where( a => a.GroupId == _group.Id ).Any();

                    // If there are group requirements that that member doesn't meet, show an icon in the grid
                    bool includeWarnings = false;
                    var groupMemberIdsThatLackGroupRequirements = new GroupService( rockContext ).GroupMembersNotMeetingRequirements( _group.Id, includeWarnings ).Select( a => a.Key.Id );

                    List<GroupMember> groupMembersList = null;

                    if ( sortProperty != null )
                    {
                        groupMembersList = qry.Sort( sortProperty ).ToList();
                    }
                    else
                    {
                        groupMembersList = qry.OrderBy( a => a.GroupRole.Order ).ThenBy( a => a.Person.LastName ).ThenBy( a => a.Person.FirstName ).ToList();
                    }

                    // Since we're not binding to actual group member list, but are using AttributeField columns,
                    // we need to save the workflows into the grid's object list
                    gGroupMembers.ObjectList = new Dictionary<string, object>();
                    groupMembersList.ForEach( m => gGroupMembers.ObjectList.Add( m.Id.ToString(), m ) );
                    gGroupMembers.EntityTypeId = EntityTypeCache.Read( Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid() ).Id;

                    gGroupMembers.DataSource = groupMembersList.Select( m => new
                    {
                        m.Id,
                        m.Guid,
                        m.PersonId,
                        Name = m.Person.NickName + " " + m.Person.LastName
                            + ( hasGroupRequirements && groupMemberIdsThatLackGroupRequirements.Contains( m.Id )
                                ? " <i class='fa fa-exclamation-triangle text-warning'></i>"
                                : string.Empty )
                            + ( !string.IsNullOrEmpty( m.Note )
                            ? " <i class='fa fa-file-text-o text-info'></i>"
                            : string.Empty ),
                        GroupRole = m.GroupRole.Name,
                        m.GroupMemberStatus,
                        RecordStatusValueId = m.Person.RecordStatusValueId,
                        IsDeceased = m.Person.IsDeceased
                    } ).ToList();

                    gGroupMembers.DataBind();
                }
                else
                {
                    nbRoleWarning.Text = string.Format(
                        "{0} cannot be added to this {1} because the '{2}' group type does not have any roles defined.",
                        _group.GroupType.GroupMemberTerm.Pluralize(),
                        _group.GroupType.GroupTerm,
                        _group.GroupType.Name );

                    nbRoleWarning.Visible = true;
                    rFilter.Visible = false;
                    gGroupMembers.Visible = false;
                }
            }
            else
            {
                pnlGroupMembers.Visible = false;
            }
        }
Example #24
0
        /// <summary>
        /// Handles the SaveClick event of the mdPlaceElsewhere control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void mdPlaceElsewhere_SaveClick( object sender, EventArgs e )
        {
            using ( var rockContext = new RockContext() )
            {
                var groupService = new GroupService( rockContext );
                var groupMemberService = new GroupMemberService( rockContext );
                var groupMember = groupMemberService.Get( hfPlaceElsewhereGroupMemberId.Value.AsInteger() );
                if ( groupMember != null )
                {
                    string errorMessage;
                    if ( !groupMemberService.CanDelete( groupMember, out errorMessage ) )
                    {
                        nbPlaceElsewhereWarning.Text = errorMessage;
                        return;
                    }

                    var trigger = _group.GetGroupMemberWorkflowTriggers().FirstOrDefault( a => a.Id == hfPlaceElsewhereTriggerId.Value.AsInteger() );
                    if ( trigger != null )
                    {
                        // create a transaction for the selected trigger
                        var transaction = new Rock.Transactions.GroupMemberPlacedElsewhereTransaction( groupMember, tbPlaceElsewhereNote.Text, trigger );

                        // delete the group member from the current group
                        groupMemberService.Delete( groupMember );

                        rockContext.SaveChanges();

                        // queue up the transaction
                        Rock.Transactions.RockQueue.TransactionQueue.Enqueue( transaction );
                    }
                }

                mdPlaceElsewhere.Hide();
                mdPlaceElsewhere.Visible = false;
                BindGroupMembersGrid();
            }
        }
Example #25
0
        /// <summary>
        /// Handles the Click event of the DeleteGroupMember control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Rock.Web.UI.Controls.RowEventArgs" /> instance containing the event data.</param>
        protected void DeleteGroupMember_Click( object sender, Rock.Web.UI.Controls.RowEventArgs e )
        {
            RockContext rockContext = new RockContext();
            GroupMemberService groupMemberService = new GroupMemberService( rockContext );
            GroupMember groupMember = groupMemberService.Get( e.RowKeyId );
            if ( groupMember != null )
            {
                string errorMessage;
                if ( !groupMemberService.CanDelete( groupMember, out errorMessage ) )
                {
                    mdGridWarning.Show( errorMessage, ModalAlertType.Information );
                    return;
                }

                int groupId = groupMember.GroupId;

                groupMemberService.Delete( groupMember );
                rockContext.SaveChanges();

                Group group = new GroupService( rockContext ).Get( groupId );
                if ( group.IsSecurityRole || group.GroupType.Guid.Equals( Rock.SystemGuid.GroupType.GROUPTYPE_SECURITY_ROLE.AsGuid() ) )
                {
                    // person removed from SecurityRole, Flush
                    Rock.Security.Role.Flush( group.Id );
                    Rock.Security.Authorization.Flush();
                }
            }

            BindGroupMembersGrid();
        }
Example #26
0
        /// <summary>
        /// Handles the Click event of the btnPlaceElsewhere control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs" /> instance containing the event data.</param>
        protected void btnPlaceElsewhere_Click( object sender, RowEventArgs e )
        {
            var rockContext = new RockContext();

            var groupMemberPerson = new GroupMemberService( rockContext ).GetPerson( e.RowKeyId );
            if ( groupMemberPerson != null )
            {
                hfPlaceElsewhereGroupMemberId.Value = e.RowKeyId.ToString();
                lPlaceElsewhereGroupMemberName.Text = groupMemberPerson.ToString();
                BindPlaceElsewhereTriggerButtons( true );

                mdPlaceElsewhere.Visible = true;
                mdPlaceElsewhere.Show();
            }
        }
Example #27
0
        /// <summary>
        /// Groups the members not meeting requirements.
        /// </summary>
        /// <param name="groupId">The group identifier.</param>
        /// <param name="includeWarnings">if set to <c>true</c> [include warnings].</param>
        /// <param name="includeInactive">if set to <c>true</c> [include inactive].</param>
        /// <returns></returns>
        public Dictionary <GroupMember, Dictionary <PersonGroupRequirementStatus, DateTime> > GroupMembersNotMeetingRequirements(int groupId, bool includeWarnings, bool includeInactive = false)
        {
            Dictionary <GroupMember, Dictionary <PersonGroupRequirementStatus, DateTime> > results = new Dictionary <GroupMember, Dictionary <PersonGroupRequirementStatus, DateTime> >();

            var rockContext                   = this.Context as RockContext;
            var groupRequirementService       = new GroupRequirementService(rockContext);
            var groupMemberService            = new GroupMemberService(rockContext);
            var groupMemberRequirementService = new GroupMemberRequirementService(rockContext);

            var  qryGroupRequirements = groupRequirementService.Queryable().Where(a => a.GroupId == groupId);
            bool hasGroupRequirements = qryGroupRequirements.Any();

            if (!hasGroupRequirements)
            {
                // if no group requirements, then there are no members that don't meet the requirements, so return an empty dictionary
                return(new Dictionary <GroupMember, Dictionary <PersonGroupRequirementStatus, DateTime> >());
            }

            var qryGroupMembers            = groupMemberService.Queryable().Where(a => a.GroupId == groupId);
            var qryGroupMemberRequirements = groupMemberRequirementService.Queryable().Where(a => a.GroupMember.GroupId == groupId);

            if (!includeInactive)
            {
                qryGroupMembers = qryGroupMembers.Where(a => a.GroupMemberStatus == GroupMemberStatus.Active);
            }

            // get a list of group member ids that don't meet all the requirements
            IQueryable <int> qryGroupMemberIdsThatLackGroupRequirements = qryGroupMembers.Where(
                a => !qryGroupRequirements.Select(x => x.Id).All(
                    r => a.GroupMemberRequirements.Where(mr => mr.RequirementMetDateTime.HasValue).Select(x => x.GroupRequirementId).Contains(r))).Select(a => a.Id);

            IQueryable <GroupMember> qryMembersWithIssues;

            if (includeWarnings)
            {
                IQueryable <int> qryGroupMemberIdsWithRequirementWarnings = qryGroupMemberRequirements.Where(a => a.RequirementWarningDateTime != null || a.RequirementFailDateTime != null).Select(a => a.GroupMemberId).Distinct();
                qryMembersWithIssues = qryGroupMembers.Where(a => qryGroupMemberIdsThatLackGroupRequirements.Contains(a.Id) || qryGroupMemberIdsWithRequirementWarnings.Contains(a.Id));
            }
            else
            {
                qryMembersWithIssues = qryGroupMembers.Where(a => qryGroupMemberIdsThatLackGroupRequirements.Contains(a.Id));
            }

            var qry = qryMembersWithIssues.Select(a => new
            {
                GroupMember = a,
                GroupRequirementStatuses = qryGroupMemberRequirements.Where(x => x.GroupMemberId == a.Id)
            });

            var currentDateTime = RockDateTime.Now;

            foreach (var groupMemberWithIssues in qry)
            {
                Dictionary <PersonGroupRequirementStatus, DateTime> statuses = new Dictionary <PersonGroupRequirementStatus, DateTime>();

                // populate where the status is known
                foreach (var requirementStatus in groupMemberWithIssues.GroupRequirementStatuses)
                {
                    PersonGroupRequirementStatus status = new PersonGroupRequirementStatus();
                    status.GroupRequirement = requirementStatus.GroupRequirement;
                    status.PersonId         = groupMemberWithIssues.GroupMember.PersonId;

                    DateTime occuranceDate = new DateTime();

                    if (requirementStatus.RequirementMetDateTime == null)
                    {
                        status.MeetsGroupRequirement = MeetsGroupRequirement.NotMet;
                        occuranceDate = requirementStatus.RequirementFailDateTime ?? currentDateTime;
                    }
                    else if (requirementStatus.RequirementWarningDateTime.HasValue)
                    {
                        status.MeetsGroupRequirement = MeetsGroupRequirement.MeetsWithWarning;
                        occuranceDate = requirementStatus.RequirementWarningDateTime.Value;
                    }
                    else
                    {
                        status.MeetsGroupRequirement = MeetsGroupRequirement.Meets;
                        occuranceDate = requirementStatus.RequirementMetDateTime.Value;
                    }

                    statuses.Add(status, occuranceDate);
                }

                // also add any groupRequirements that they don't have statuses for (and therefore haven't met)
                foreach (var groupRequirement in qryGroupRequirements)
                {
                    if (!statuses.Any(x => x.Key.GroupRequirement.Id == groupRequirement.Id))
                    {
                        PersonGroupRequirementStatus status = new PersonGroupRequirementStatus();
                        status.GroupRequirement      = groupRequirement;
                        status.PersonId              = groupMemberWithIssues.GroupMember.PersonId;
                        status.MeetsGroupRequirement = MeetsGroupRequirement.NotMet;
                        statuses.Add(status, currentDateTime);
                    }
                }

                var statusesWithIssues = statuses.Where(a => a.Key.MeetsGroupRequirement != MeetsGroupRequirement.Meets).ToDictionary(k => k.Key, v => v.Value);

                if (statusesWithIssues.Any())
                {
                    results.Add(groupMemberWithIssues.GroupMember, statusesWithIssues);
                }
            }

            return(results);
        }
Example #28
0
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void ShowResults()
        {
            // Get the group types that we're interested in
            Guid? groupTypeGuid = GetAttributeValue( "GroupType" ).AsGuidOrNull();
            if ( !groupTypeGuid.HasValue )
            {
                ShowError( "A valid Group Type is required." );
                return;
            }

            gGroups.Columns[1].Visible = GetAttributeValue( "ShowDescription" ).AsBoolean();
            gGroups.Columns[2].Visible = GetAttributeValue( "ShowSchedule" ).AsBoolean();
            gGroups.Columns[3].Visible = GetAttributeValue( "ShowCount" ).AsBoolean();
            gGroups.Columns[4].Visible = GetAttributeValue( "ShowAge" ).AsBoolean();

            bool showProximity = GetAttributeValue( "ShowProximity" ).AsBoolean();
            gGroups.Columns[5].Visible = showProximity;  // Distance

            // Get query of groups of the selected group type
            var rockContext = new RockContext();
            var groupService = new GroupService( rockContext );
            var groupQry = groupService
                .Queryable( "GroupLocations.Location" )
                .Where( g => g.IsActive && g.GroupType.Guid.Equals( groupTypeGuid.Value ) && g.IsPublic );

            var groupParameterExpression = groupService.ParameterExpression;
            var schedulePropertyExpression = Expression.Property( groupParameterExpression, "Schedule" );

            var dowFilterControl = phFilterControls.FindControl( "filter_dow" );
            if ( dowFilterControl != null )
            {
                var field = FieldTypeCache.Read( Rock.SystemGuid.FieldType.DAY_OF_WEEK ).Field;

                var filterValues = field.GetFilterValues( dowFilterControl, null, Rock.Reporting.FilterMode.SimpleFilter );
                var expression = field.PropertyFilterExpression( null, filterValues, schedulePropertyExpression, "WeeklyDayOfWeek", typeof( DayOfWeek? ) );
                groupQry = groupQry.Where( groupParameterExpression, expression, null );
            }

            var timeFilterControl = phFilterControls.FindControl( "filter_time" );
            if ( timeFilterControl != null )
            {
                var field = FieldTypeCache.Read( Rock.SystemGuid.FieldType.TIME ).Field;

                var filterValues = field.GetFilterValues( timeFilterControl, null, Rock.Reporting.FilterMode.SimpleFilter );
                var expression = field.PropertyFilterExpression( null, filterValues, schedulePropertyExpression, "WeeklyTimeOfDay", typeof( TimeSpan? ) );
                groupQry = groupQry.Where( groupParameterExpression, expression, null );
            }

            // Filter query by any configured attribute filters
            if ( AttributeFilters != null && AttributeFilters.Any() )
            {
                var attributeValueService = new AttributeValueService( rockContext );
                var parameterExpression = attributeValueService.ParameterExpression;

                foreach ( var attribute in AttributeFilters )
                {
                    var filterControl = phFilterControls.FindControl( "filter_" + attribute.Id.ToString() );
                    if ( filterControl != null )
                    {
                        var filterValues = attribute.FieldType.Field.GetFilterValues( filterControl, attribute.QualifierValues, Rock.Reporting.FilterMode.SimpleFilter );
                        var expression = attribute.FieldType.Field.AttributeFilterExpression( attribute.QualifierValues, filterValues, parameterExpression );
                        if ( expression != null )
                        {
                            var attributeValues = attributeValueService
                                .Queryable()
                                .Where( v => v.Attribute.Id == attribute.Id );

                            attributeValues = attributeValues.Where( parameterExpression, expression, null );

                            groupQry = groupQry.Where( w => attributeValues.Select( v => v.EntityId ).Contains( w.Id ) );
                        }
                    }
                }
            }

            List<GroupLocation> fences = null;
            List<Group> groups = null;

            // Run query to get list of matching groups
            SortProperty sortProperty = gGroups.SortProperty;
            if ( sortProperty != null )
            {
                groups = groupQry.Sort( sortProperty ).ToList();
            }
            else
            {
                groups = groupQry.OrderBy( g => g.Name ).ToList();
            }

            int? fenceGroupTypeId = GetGroupTypeId( GetAttributeValue( "GeofencedGroupType" ).AsGuidOrNull() );
            bool showMap = GetAttributeValue( "ShowMap" ).AsBoolean();
            bool showFences = showMap && GetAttributeValue( "ShowFence" ).AsBoolean();

            var distances = new Dictionary<int, double>();

            // If we care where these groups are located...
            if ( fenceGroupTypeId.HasValue || showMap || showProximity )
            {
                // Get the location for the address entered
                Location personLocation = null;
                if ( fenceGroupTypeId.HasValue || showProximity )
                {
                    personLocation = new LocationService( rockContext )
                        .Get( acAddress.Street1, acAddress.Street2, acAddress.City,
                            acAddress.State, acAddress.PostalCode, acAddress.Country );
                }

                // If showing a map, and person's location was found, save a mapitem for this location
                FinderMapItem personMapItem = null;
                if ( showMap && personLocation != null && personLocation.GeoPoint != null )
                {
                    var infoWindow = string.Format( @"
            <div style='width:250px'>
            <div class='clearfix'>
            <strong>Your Location</strong>
            <br/>{0}
            </div>
            </div>
            ", personLocation.FormattedHtmlAddress );

                    personMapItem = new FinderMapItem( personLocation );
                    personMapItem.Name = "Your Location";
                    personMapItem.InfoWindow = HttpUtility.HtmlEncode( infoWindow.Replace( Environment.NewLine, string.Empty ).Replace( "\n", string.Empty ).Replace( "\t", string.Empty ) );
                }

                // Get the locations, and optionally calculate the distance for each of the groups
                var groupLocations = new List<GroupLocation>();
                foreach ( var group in groups )
                {
                    foreach ( var groupLocation in group.GroupLocations
                        .Where( gl => gl.Location.GeoPoint != null ) )
                    {
                        groupLocations.Add( groupLocation );

                        if ( showProximity && personLocation != null && personLocation.GeoPoint != null )
                        {
                            double meters = groupLocation.Location.GeoPoint.Distance( personLocation.GeoPoint ) ?? 0.0D;
                            double miles = meters * Location.MilesPerMeter;

                            // If this group already has a distance calculated, see if this location is closer and if so, use it instead
                            if ( distances.ContainsKey( group.Id ) )
                            {
                                if ( distances[group.Id] < miles )
                                {
                                    distances[group.Id] = miles;
                                }
                            }
                            else
                            {
                                distances.Add( group.Id, miles );
                            }
                        }
                    }
                }

                // If groups should be limited by a geofence
                var fenceMapItems = new List<MapItem>();
                if ( fenceGroupTypeId.HasValue )
                {
                    fences = new List<GroupLocation>();
                    if ( personLocation != null && personLocation.GeoPoint != null )
                    {
                        fences = new GroupLocationService( rockContext )
                            .Queryable( "Group,Location" )
                            .Where( gl =>
                                gl.Group.GroupTypeId == fenceGroupTypeId &&
                                gl.Location.GeoFence != null &&
                                personLocation.GeoPoint.Intersects( gl.Location.GeoFence ) )
                            .ToList();
                    }

                    // Limit the group locations to only those locations inside one of the fences
                    groupLocations = groupLocations
                        .Where( gl =>
                            fences.Any( f => gl.Location.GeoPoint.Intersects( f.Location.GeoFence ) ) )
                        .ToList();

                    // Limit the groups to the those that still contain a valid location
                    groups = groups
                        .Where( g =>
                            groupLocations.Any( gl => gl.GroupId == g.Id ) )
                        .ToList();

                    // If the map and fences should be displayed, create a map item for each fence
                    if ( showMap && showFences )
                    {
                        foreach ( var fence in fences )
                        {
                            var mapItem = new FinderMapItem( fence.Location );
                            mapItem.EntityTypeId = EntityTypeCache.Read( "Rock.Model.Group" ).Id;
                            mapItem.EntityId = fence.GroupId;
                            mapItem.Name = fence.Group.Name;
                            fenceMapItems.Add( mapItem );
                        }
                    }
                }

                // if not sorting by ColumnClick and SortByDistance, then sort the groups by distance
                if ( gGroups.SortProperty == null && GetAttributeValue( "SortByDistance" ).AsBoolean() )
                {
                    // only show groups with a known location, and sort those by distance
                    groups = groups.Where( a => distances.Select( b => b.Key ).Contains( a.Id ) ).ToList();
                    groups = groups.OrderBy( a => distances[a.Id] ).ThenBy( a => a.Name ).ToList();
                }

                // if limiting by PageSize, limit to the top X groups
                int? pageSize = ddlPageSize.SelectedValue.AsIntegerOrNull();
                if ( pageSize.HasValue && pageSize > 0 )
                {
                    groups = groups.Take( pageSize.Value ).ToList();
                }

                // If a map is to be shown
                if ( showMap && groups.Any() )
                {

                    Template template = Template.Parse( GetAttributeValue( "MapInfo" ) );

                    bool showDebug = UserCanEdit && GetAttributeValue( "MapInfoDebug" ).AsBoolean();
                    lMapInfoDebug.Visible = showDebug;

                    // Add mapitems for all the remaining valid group locations
                    var groupMapItems = new List<MapItem>();
                    foreach ( var gl in groupLocations )
                    {
                        var group = groups.Where( g => g.Id == gl.GroupId ).FirstOrDefault();
                        if ( group != null )
                        {
                            // Resolve info window lava template
                            var linkedPageParams = new Dictionary<string, string> { { "GroupId", group.Id.ToString() } };
                            var mergeFields = new Dictionary<string, object>();
                            mergeFields.Add( "Group", gl.Group );
                            mergeFields.Add( "Location", gl.Location );

                            Dictionary<string, object> linkedPages = new Dictionary<string, object>();
                            linkedPages.Add( "GroupDetailPage", LinkedPageRoute( "GroupDetailPage" ) );

                            if ( _targetPersonGuid != Guid.Empty )
                            {
                                linkedPages.Add( "RegisterPage", LinkedPageUrl( "RegisterPage", _urlParms ) );
                            }
                            else
                            {
                                linkedPages.Add( "RegisterPage", LinkedPageUrl( "RegisterPage", null ) );
                            }

                            mergeFields.Add( "LinkedPages", linkedPages );

                            // add collection of allowed security actions
                            Dictionary<string, object> securityActions = new Dictionary<string, object>();
                            securityActions.Add( "View", group.IsAuthorized( Authorization.VIEW, CurrentPerson ) );
                            securityActions.Add( "Edit", group.IsAuthorized( Authorization.EDIT, CurrentPerson ) );
                            securityActions.Add( "Administrate", group.IsAuthorized( Authorization.ADMINISTRATE, CurrentPerson ) );
                            mergeFields.Add( "AllowedActions", securityActions );

                            string infoWindow = template.Render( Hash.FromDictionary( mergeFields ) );

                            if ( showDebug )
                            {
                                lMapInfoDebug.Text = mergeFields.lavaDebugInfo( null, "<span class='label label-info'>Lava used for the map window.</span>", "" );
                                showDebug = false;
                            }

                            // Add a map item for group
                            var mapItem = new FinderMapItem( gl.Location );
                            mapItem.EntityTypeId = EntityTypeCache.Read( "Rock.Model.Group" ).Id;
                            mapItem.EntityId = group.Id;
                            mapItem.Name = group.Name;
                            mapItem.InfoWindow = HttpUtility.HtmlEncode( infoWindow.Replace( Environment.NewLine, string.Empty ).Replace( "\n", string.Empty ).Replace( "\t", string.Empty ) );
                            groupMapItems.Add( mapItem );
                        }
                    }

                    // Show the map
                    Map( personMapItem, fenceMapItems, groupMapItems );
                    pnlMap.Visible = true;
                }
                else
                {
                    pnlMap.Visible = false;
                }
            }
            else
            {
                pnlMap.Visible = false;
            }

            // Should a lava output be displayed
            if ( GetAttributeValue( "ShowLavaOutput" ).AsBoolean() )
            {
                string template = GetAttributeValue( "LavaOutput" );

                var mergeFields = new Dictionary<string, object>();
                if ( fences != null )
                {
                    mergeFields.Add( "Fences", fences.Select( f => f.Group ).ToList() );
                }
                else
                {
                    mergeFields.Add( "Fences", new Dictionary<string, object>() );
                }

                mergeFields.Add( "Groups", groups );

                Dictionary<string, object> linkedPages = new Dictionary<string, object>();
                linkedPages.Add( "GroupDetailPage", LinkedPageUrl( "GroupDetailPage", null ) );

                if ( _targetPersonGuid != Guid.Empty )
                {
                    linkedPages.Add( "RegisterPage", LinkedPageUrl( "RegisterPage", _urlParms ) );
                }
                else
                {
                    linkedPages.Add( "RegisterPage", LinkedPageUrl( "RegisterPage", null ) );
                }

                mergeFields.Add( "LinkedPages", linkedPages );

                lLavaOverview.Text = template.ResolveMergeFields( mergeFields );

                bool showDebug = UserCanEdit && GetAttributeValue( "LavaOutputDebug" ).AsBoolean();
                lLavaOutputDebug.Visible = showDebug;
                if ( showDebug )
                {
                    lLavaOutputDebug.Text = mergeFields.lavaDebugInfo( null, "<span class='label label-info'>Lava used for the summary info.</span>" );
                }

                pnlLavaOutput.Visible = true;
            }
            else
            {
                pnlLavaOutput.Visible = false;
            }

            // Should a grid be displayed
            if ( GetAttributeValue( "ShowGrid" ).AsBoolean() )
            {
                pnlGrid.Visible = true;

                // Save the groups into the grid's object list since it is not being bound to actual group objects
                gGroups.ObjectList = new Dictionary<string, object>();
                groups.ForEach( g => gGroups.ObjectList.Add( g.Id.ToString(), g ) );

                // Bind the grid
                gGroups.DataSource = groups.Select( g =>
                {
                    var qryMembers = new GroupMemberService( rockContext ).Queryable().Where( a => a.GroupId == g.Id );
                    var groupType = GroupTypeCache.Read( g.GroupTypeId );

                    return new
                    {
                        Id = g.Id,
                        Name = g.Name,
                        GroupTypeName = groupType.Name,
                        GroupOrder = g.Order,
                        GroupTypeOrder = groupType.Order,
                        Description = g.Description,
                        IsSystem = g.IsSystem,
                        IsActive = g.IsActive,
                        GroupRole = string.Empty,
                        DateAdded = DateTime.MinValue,
                        Schedule = g.Schedule,
                        MemberCount = qryMembers.Count(),
                        AverageAge = Math.Round( qryMembers.Select( m => m.Person.BirthDate ).ToList().Select( a => Person.GetAge( a ) ).Average() ?? 0.0D ),
                        Distance = distances.Where( d => d.Key == g.Id )
                            .Select( d => d.Value ).FirstOrDefault()
                    };
                } ).ToList();
                gGroups.DataBind();
            }
            else
            {
                pnlGrid.Visible = false;
            }

            // Show the results
            pnlResults.Visible = true;
        }
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            // confirmation was disabled by btnSave on client-side.  So if returning without a redirect,
            // it should be enabled.  If returning with a redirect, the control won't be updated to reflect
            // confirmation being enabled, so it's ok to enable it here
            confirmExit.Enabled = true;

            if ( Page.IsValid )
            {
                confirmExit.Enabled = true;

                RockTransactionScope.WrapTransaction( () =>
                {
                    var rockContext = new RockContext();
                    var familyService = new GroupService( rockContext );
                    var familyMemberService = new GroupMemberService( rockContext );
                    var personService = new PersonService( rockContext );
                    var historyService = new HistoryService( rockContext );

                    var familyChanges = new List<string>();

                    // SAVE FAMILY
                    _family = familyService.Get( _family.Id );

                    History.EvaluateChange( familyChanges, "Family Name", _family.Name, tbFamilyName.Text );
                    _family.Name = tbFamilyName.Text;

                    int? campusId = cpCampus.SelectedValueAsInt();
                    if ( _family.CampusId != campusId )
                    {
                        History.EvaluateChange( familyChanges, "Campus",
                            _family.CampusId.HasValue ? CampusCache.Read( _family.CampusId.Value ).Name : string.Empty,
                            campusId.HasValue ? CampusCache.Read( campusId.Value ).Name : string.Empty );
                        _family.CampusId = campusId;
                    }

                    var familyGroupTypeId = _family.GroupTypeId;

                    rockContext.SaveChanges();

                    // SAVE FAMILY MEMBERS
                    int? recordStatusValueID = ddlRecordStatus.SelectedValueAsInt();
                    int? reasonValueId = ddlReason.SelectedValueAsInt();
                    var newFamilies = new List<Group>();

                    foreach ( var familyMember in FamilyMembers )
                    {
                        var memberChanges = new List<string>();
                        var demographicChanges = new List<string>();

                        var role = familyRoles.Where( r => r.Guid.Equals( familyMember.RoleGuid ) ).FirstOrDefault();
                        if ( role == null )
                        {
                            role = familyRoles.FirstOrDefault();
                        }

                        bool isChild = role != null && role.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD ) );

                        // People added to family (new or from other family)
                        if ( !familyMember.ExistingFamilyMember )
                        {
                            var groupMember = new GroupMember();

                            if ( familyMember.Id == -1 )
                            {
                                // added new person
                                demographicChanges.Add( "Created" );

                                var person = new Person();
                                person.FirstName = familyMember.FirstName;
                                person.NickName = familyMember.NickName;
                                History.EvaluateChange( demographicChanges, "First Name", string.Empty, person.FirstName );

                                person.LastName = familyMember.LastName;
                                History.EvaluateChange( demographicChanges, "Last Name", string.Empty, person.LastName );

                                person.Gender = familyMember.Gender;
                                History.EvaluateChange( demographicChanges, "Gender", null, person.Gender );

                                person.BirthDate = familyMember.BirthDate;
                                History.EvaluateChange( demographicChanges, "Birth Date", null, person.BirthDate );

                                if ( !isChild )
                                {
                                    person.GivingGroupId = _family.Id;
                                    History.EvaluateChange( demographicChanges, "Giving Group", string.Empty, _family.Name );
                                }

                                person.EmailPreference = EmailPreference.EmailAllowed;

                                groupMember.Person = person;
                            }
                            else
                            {
                                // added from other family
                                groupMember.Person = personService.Get( familyMember.Id );
                            }

                            if ( recordStatusValueID > 0 )
                            {
                                History.EvaluateChange( demographicChanges, "Record Status", DefinedValueCache.GetName( groupMember.Person.RecordStatusValueId ), DefinedValueCache.GetName( recordStatusValueID ) );
                                groupMember.Person.RecordStatusValueId = recordStatusValueID;

                                History.EvaluateChange( demographicChanges, "Record Status Reason", DefinedValueCache.GetName( groupMember.Person.RecordStatusReasonValueId ), DefinedValueCache.GetName( reasonValueId ) );
                                groupMember.Person.RecordStatusReasonValueId = reasonValueId;
                            }

                            groupMember.GroupId = _family.Id;
                            if ( role != null )
                            {
                                History.EvaluateChange( memberChanges, "Role", string.Empty, role.Name );
                                groupMember.GroupRoleId = role.Id;
                            }

                            if ( groupMember.Person != null )
                            {
                                familyMemberService.Add( groupMember );
                                rockContext.SaveChanges();
                                familyMember.Id = groupMember.Person.Id;
                            }

                        }
                        else
                        {
                            // existing family members
                            var groupMember = familyMemberService.Queryable( "Person" ).Where( m =>
                                m.PersonId == familyMember.Id &&
                                m.Group.GroupTypeId == familyGroupTypeId &&
                                m.GroupId == _family.Id ).FirstOrDefault();

                            if ( groupMember != null )
                            {
                                if ( familyMember.Removed )
                                {
                                    var newFamilyChanges = new List<string>();

                                    // Family member was removed and should be created in their own new family
                                    var newFamily = new Group();
                                    newFamily.Name = familyMember.LastName + " Family";
                                    History.EvaluateChange( newFamilyChanges, "Family", string.Empty, newFamily.Name );

                                    newFamily.GroupTypeId = familyGroupTypeId;

                                    if ( _family.CampusId.HasValue )
                                    {
                                        History.EvaluateChange( newFamilyChanges, "Campus", string.Empty, CampusCache.Read( _family.CampusId.Value ).Name );
                                    }
                                    newFamily.CampusId = _family.CampusId;

                                    familyService.Add( newFamily );
                                    rockContext.SaveChanges();

                                    // If person's previous giving group was this family, set it to their new family id
                                    if ( groupMember.Person.GivingGroup != null && groupMember.Person.GivingGroupId == _family.Id )
                                    {
                                        History.EvaluateChange( demographicChanges, "Giving Group", groupMember.Person.GivingGroup.Name, _family.Name );
                                        groupMember.Person.GivingGroupId = newFamily.Id;
                                    }

                                    groupMember.Group = newFamily;
                                    rockContext.SaveChanges();

                                    var newMemberChanges = new List<string>();
                                    History.EvaluateChange( newMemberChanges, "Role", string.Empty, groupMember.GroupRole.Name );

                                    HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                        groupMember.Person.Id, newFamilyChanges, newFamily.Name, typeof( Group ), newFamily.Id );

                                    newFamilies.Add( newFamily );

                                    History.EvaluateChange( memberChanges, "Role", groupMember.GroupRole.Name, string.Empty );
                                }
                                else
                                {
                                    // Existing member was not remvoved
                                    if ( role != null )
                                    {
                                        History.EvaluateChange( memberChanges, "Role",
                                            groupMember.GroupRole != null ? groupMember.GroupRole.Name : string.Empty, role.Name );
                                        groupMember.GroupRoleId = role.Id;

                                        if ( recordStatusValueID > 0 )
                                        {
                                            History.EvaluateChange( demographicChanges, "Record Status", DefinedValueCache.GetName( groupMember.Person.RecordStatusValueId ), DefinedValueCache.GetName( recordStatusValueID ) );
                                            groupMember.Person.RecordStatusValueId = recordStatusValueID;

                                            History.EvaluateChange( demographicChanges, "Record Status Reason", DefinedValueCache.GetName( groupMember.Person.RecordStatusReasonValueId ), DefinedValueCache.GetName( reasonValueId ) );
                                            groupMember.Person.RecordStatusReasonValueId = reasonValueId;
                                        }

                                        rockContext.SaveChanges();
                                    }
                                }
                            }
                        }

                        // Remove anyone that was moved from another family
                        if ( familyMember.RemoveFromOtherFamilies )
                        {
                            var otherFamilies = familyMemberService.Queryable()
                                .Where( m =>
                                    m.PersonId == familyMember.Id &&
                                    m.Group.GroupTypeId == familyGroupTypeId &&
                                    m.GroupId != _family.Id )
                                .ToList();

                            foreach ( var otherFamilyMember in otherFamilies )
                            {
                                var fm = familyMemberService.Get( otherFamilyMember.Id );

                                // If the person's giving group id was the family they are being removed from, update it to this new family's id
                                if ( fm.Person.GivingGroupId == fm.GroupId )
                                {
                                    var person = personService.Get( fm.PersonId );

                                    History.EvaluateChange( demographicChanges, "Giving Group", person.GivingGroup.Name, _family.Name );
                                    person.GivingGroupId = _family.Id;

                                    rockContext.SaveChanges();
                                }

                                var oldMemberChanges = new List<string>();
                                History.EvaluateChange( oldMemberChanges, "Role", fm.GroupRole.Name, string.Empty );
                                History.EvaluateChange( oldMemberChanges, "Family", fm.Group.Name, string.Empty );
                                HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                                    fm.Person.Id, oldMemberChanges, fm.Group.Name, typeof( Group ), fm.Group.Id );

                                familyMemberService.Delete( fm );
                                rockContext.SaveChanges();

                                var f = familyService.Queryable()
                                    .Where( g =>
                                        g.Id == otherFamilyMember.GroupId &&
                                        !g.Members.Any() )
                                    .FirstOrDefault();
                                if ( f != null )
                                {
                                    familyService.Delete( f );
                                    rockContext.SaveChanges();
                                }

                            }
                        }

                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(),
                            familyMember.Id, demographicChanges );

                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                            familyMember.Id, memberChanges, _family.Name, typeof( Group ), _family.Id );
                    }

                    // SAVE LOCATIONS
                    var groupLocationService = new GroupLocationService( rockContext );

                    // delete any group locations that were removed
                    var remainingLocationIds = FamilyAddresses.Where( a => a.Id > 0 ).Select( a => a.Id ).ToList();
                    foreach ( var removedLocation in groupLocationService.Queryable( "GroupLocationTypeValue,Location" )
                        .Where( l => l.GroupId == _family.Id &&
                            !remainingLocationIds.Contains( l.Id ) ) )
                    {
                        History.EvaluateChange( familyChanges, removedLocation.GroupLocationTypeValue.Name + " Location",
                            removedLocation.Location.ToString(), string.Empty );
                        groupLocationService.Delete( removedLocation );
                    }
                    rockContext.SaveChanges();

                    foreach ( var familyAddress in FamilyAddresses )
                    {
                        Location updatedAddress = null;
                        if ( familyAddress.LocationIsDirty )
                        {
                            updatedAddress = new LocationService( rockContext ).Get(
                                familyAddress.Street1, familyAddress.Street2, familyAddress.City,
                                familyAddress.State, familyAddress.Zip );
                        }

                        GroupLocation groupLocation = null;
                        if ( familyAddress.Id > 0 )
                        {
                            groupLocation = groupLocationService.Get( familyAddress.Id );
                        }
                        if ( groupLocation == null )
                        {
                            groupLocation = new GroupLocation();
                            groupLocation.GroupId = _family.Id;
                            groupLocationService.Add( groupLocation );
                        }

                        History.EvaluateChange( familyChanges, "Location Type",
                            groupLocation.GroupLocationTypeValueId.HasValue ? DefinedValueCache.Read( groupLocation.GroupLocationTypeValueId.Value ).Name : string.Empty,
                            familyAddress.LocationTypeName );
                        groupLocation.GroupLocationTypeValueId = familyAddress.LocationTypeId;

                        History.EvaluateChange( familyChanges, familyAddress.LocationTypeName + " Is Mailing",
                            groupLocation.IsMailingLocation.ToString(), familyAddress.IsMailing.ToString() );
                        groupLocation.IsMailingLocation = familyAddress.IsMailing;

                        History.EvaluateChange( familyChanges, familyAddress.LocationTypeName + " Is Map Location",
                            groupLocation.IsMappedLocation.ToString(), familyAddress.IsLocation.ToString() );
                        groupLocation.IsMappedLocation = familyAddress.IsLocation;

                        if ( updatedAddress != null )
                        {
                            History.EvaluateChange( familyChanges, familyAddress.LocationTypeName + " Location",
                                groupLocation.Location != null ? groupLocation.Location.ToString() : "", updatedAddress.ToString() );
                            groupLocation.Location = updatedAddress;
                        }

                        rockContext.SaveChanges();

                        // Add the same locations to any new families created by removing an existing family member
                        if ( newFamilies.Any() )
                        {
                            //reload grouplocation for access to child properties
                            groupLocation = groupLocationService.Get( groupLocation.Id );
                            foreach ( var newFamily in newFamilies )
                            {
                                var newFamilyLocation = new GroupLocation();
                                newFamilyLocation.GroupId = newFamily.Id;
                                newFamilyLocation.LocationId = groupLocation.LocationId;
                                newFamilyLocation.GroupLocationTypeValueId = groupLocation.GroupLocationTypeValueId;
                                newFamilyLocation.IsMailingLocation = groupLocation.IsMailingLocation;
                                newFamilyLocation.IsMappedLocation = groupLocation.IsMappedLocation;
                                groupLocationService.Add( newFamilyLocation );
                            }

                            rockContext.SaveChanges();
                        }
                    }

                    foreach ( var fm in _family.Members )
                    {
                        HistoryService.SaveChanges( rockContext, typeof( Person ), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(),
                            fm.PersonId, familyChanges, _family.Name, typeof( Group ), _family.Id );
                    }

                    _family = familyService.Get( _family.Id );
                    if ( _family.Members.Any( m => m.PersonId == Person.Id ) )
                    {
                        Response.Redirect( string.Format( "~/Person/{0}", Person.Id ), false );
                    }
                    else
                    {
                        var fm = _family.Members
                            .Where( m =>
                                m.GroupRole.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ) &&
                                m.Person.Gender == Gender.Male )
                            .OrderByDescending( m => m.Person.Age )
                            .FirstOrDefault();
                        if ( fm == null )
                        {
                            fm = _family.Members
                                .Where( m =>
                                    m.GroupRole.Guid.Equals( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ) )
                                .OrderByDescending( m => m.Person.Age )
                                .FirstOrDefault();
                        }
                        if ( fm == null )
                        {
                            fm = _family.Members
                                .OrderByDescending( m => m.Person.Age )
                                .FirstOrDefault();
                        }
                        if ( fm != null )
                        {
                            Response.Redirect( string.Format( "~/Person/{0}", fm.PersonId ), false );
                        }
                        else
                        {
                            Response.Redirect( "~", false );
                        }
                    }

                } );
            }
        }
Example #30
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>();

            var mergeFields = GetMergeFields( action );

            int? fromId = null;
            Guid? fromGuid = GetAttributeValue( action, "From" ).AsGuidOrNull();
            if ( fromGuid.HasValue )
            {
                var fromValue = DefinedValueCache.Read( fromGuid.Value, rockContext );
                if ( fromValue != null )
                {
                    fromId = fromValue.Id;
                }
            }

            var recipients = new List<RecipientData>();

            string toValue = GetAttributeValue( action, "To" );
            Guid guid = toValue.AsGuid();
            if ( !guid.IsEmpty() )
            {
                var attribute = AttributeCache.Read( guid, rockContext );
                if ( attribute != null )
                {
                    string toAttributeValue = action.GetWorklowAttributeValue( guid );
                    if ( !string.IsNullOrWhiteSpace( toAttributeValue ) )
                    {
                        switch ( attribute.FieldType.Class )
                        {
                            case "Rock.Field.Types.TextFieldType":
                                {
                                    recipients.Add( new RecipientData( toAttributeValue ) );
                                    break;
                                }
                            case "Rock.Field.Types.PersonFieldType":
                                {
                                    Guid personAliasGuid = toAttributeValue.AsGuid();
                                    if ( !personAliasGuid.IsEmpty() )
                                    {
                                        var phoneNumber = new PersonAliasService( rockContext ).Queryable()
                                            .Where( a => a.Guid.Equals( personAliasGuid ) )
                                            .SelectMany( a => a.Person.PhoneNumbers )
                                            .Where( p => p.IsMessagingEnabled )
                                            .FirstOrDefault();

                                        if ( phoneNumber == null )
                                        {
                                            action.AddLogEntry( "Invalid Recipient: Person or valid SMS phone number not found", true );
                                        }
                                        else
                                        {
                                            string smsNumber = phoneNumber.Number;
                                            if ( !string.IsNullOrWhiteSpace( phoneNumber.CountryCode ) )
                                            {
                                                smsNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number;
                                            }

                                            var recipient = new RecipientData( smsNumber );
                                            recipients.Add( recipient );

                                            var person = new PersonAliasService( rockContext ).GetPerson( personAliasGuid );
                                            if ( person != null )
                                            {
                                                recipient.MergeFields.Add( "Person", person );
                                            }
                                        }
                                    }
                                    break;
                                }

                            case "Rock.Field.Types.GroupFieldType":
                            case "Rock.Field.Types.SecurityRoleFieldType":
                                {
                                    int? groupId = toAttributeValue.AsIntegerOrNull();
                                    Guid? groupGuid = toAttributeValue.AsGuidOrNull();
                                    IQueryable<GroupMember> qry = null;

                                    // Handle situations where the attribute value is the ID
                                    if ( groupId.HasValue )
                                    {
                                        qry = new GroupMemberService( rockContext ).GetByGroupId( groupId.Value );
                                    }

                                    // Handle situations where the attribute value stored is the Guid
                                    else if ( groupGuid.HasValue )
                                    {
                                        qry = new GroupMemberService( rockContext ).GetByGroupGuid( groupGuid.Value );
                                    }
                                    else
                                    {
                                        action.AddLogEntry( "Invalid Recipient: No valid group id or Guid", true );
                                    }

                                    if ( qry != null )
                                    {
                                        foreach ( var person in qry
                                            .Where( m => m.GroupMemberStatus == GroupMemberStatus.Active )
                                            .Select( m => m.Person ) )
                                        {
                                            var phoneNumber = person.PhoneNumbers
                                                .Where( p => p.IsMessagingEnabled )
                                                .FirstOrDefault();
                                            if ( phoneNumber != null )
                                            {
                                                string smsNumber = phoneNumber.Number;
                                                if ( !string.IsNullOrWhiteSpace( phoneNumber.CountryCode ) )
                                                {
                                                    smsNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number;
                                                }

                                                var recipient = new RecipientData( smsNumber );
                                                recipients.Add( recipient );
                                                recipient.MergeFields.Add( "Person", person );
                                            }
                                        }
                                    }
                                    break;
                                }
                        }
                    }
                }
            }
            else
            {
                if ( !string.IsNullOrWhiteSpace( toValue ) )
                {
                    recipients.Add( new RecipientData( toValue.ResolveMergeFields( mergeFields ) ) );
                }
            }

            string message = GetAttributeValue( action, "Message" );
            Guid messageGuid = message.AsGuid();
            if ( !messageGuid.IsEmpty() )
            {
                var attribute = AttributeCache.Read( messageGuid, rockContext );
                if ( attribute != null )
                {
                    string messageAttributeValue = action.GetWorklowAttributeValue( messageGuid );
                    if ( !string.IsNullOrWhiteSpace( messageAttributeValue ) )
                    {
                        if ( attribute.FieldType.Class == "Rock.Field.Types.TextFieldType" )
                        {
                            message = messageAttributeValue;
                        }
                    }
                }
            }

            if ( recipients.Any() && !string.IsNullOrWhiteSpace( message ) )
            {
                var mediumEntity = EntityTypeCache.Read( Rock.SystemGuid.EntityType.COMMUNICATION_MEDIUM_SMS.AsGuid(), rockContext );
                if ( mediumEntity != null )
                {
                    var medium = MediumContainer.GetComponent( mediumEntity.Name );
                    if ( medium != null && medium.IsActive )
                    {
                        var transport = medium.Transport;
                        if ( transport != null && transport.IsActive )
                        {
                            var appRoot = GlobalAttributesCache.Read( rockContext ).GetValue( "InternalApplicationRoot" );

                            foreach ( var recipient in recipients )
                            {
                                var recipientMergeFields = new Dictionary<string, object>( mergeFields );
                                foreach ( var mergeField in recipient.MergeFields )
                                {
                                    recipientMergeFields.Add( mergeField.Key, mergeField.Value );
                                }
                                var mediumData = new Dictionary<string, string>();
                                mediumData.Add( "FromValue", fromId.Value.ToString() );
                                mediumData.Add( "Message", message.ResolveMergeFields( recipientMergeFields ) );

                                var number = new List<string> { recipient.To };

                                transport.Send( mediumData, number, appRoot, string.Empty );
                            }
                        }
                    }
                }
            }

            return true;
        }
        /// <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( "PublicApplicationRoot" );
                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 = 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 );

                    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 = Rock.Lava.LavaHelper.GetCommonMergeFields( null );
                        mergeFields.Add( "Person", person );
                        mergeFields.Add( "GroupsMissingRequirements", _groupsMissingRequriements );

                        recipients.Add( new RecipientData( person.Email, mergeFields ) );
                    }
                }

                Email.Send( systemEmailGuid.Value, recipients, appRoot );

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

            }
            else
            {
                context.Result = "Warning: No NotificationEmailTemplate found";
            }
        }
Example #32
0
        /// <summary>
        /// Validates the group membership.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ValidateGroupMembership(RockContext rockContext, out string errorMessage)
        {
            errorMessage = string.Empty;
            GroupMemberService groupMemberService = new GroupMemberService(rockContext);
            var groupRole = this.GroupRole ?? new GroupTypeRoleService(rockContext).Get(this.GroupRoleId);

            // check to see if the person is already a member of the group/role
            var existingGroupMembership = groupMemberService.GetByGroupIdAndPersonId(this.GroupId, this.PersonId);

            if (existingGroupMembership.Any(a => a.GroupRoleId == this.GroupRoleId && a.Id != this.Id))
            {
                var person = this.Person ?? new PersonService(rockContext).Get(this.PersonId);

                errorMessage = string.Format(
                    "{0} already belongs to the {1} role for this {2}, and cannot be added again with the same role",
                    person,
                    groupRole.Name,
                    groupRole.GroupType.GroupTerm);

                return(false);
            }

            var databaseRecord = existingGroupMembership.FirstOrDefault(a => a.Id == this.Id);

            int memberCountInRole = new GroupMemberService(rockContext).Queryable()
                                    .Where(m =>
                                           m.GroupId == this.GroupId &&
                                           m.GroupRoleId == this.GroupRoleId &&
                                           m.GroupMemberStatus == GroupMemberStatus.Active)
                                    .Count();

            bool roleMembershipAboveMax = false;

            // if adding new active group member..
            if (this.Id.Equals(0) && this.GroupMemberStatus == GroupMemberStatus.Active)
            {
                // verify that active count has not exceeded the max
                if (groupRole.MaxCount != null && (memberCountInRole + 1) > groupRole.MaxCount)
                {
                    roleMembershipAboveMax = true;
                }
            }
            else if (databaseRecord != null && this.Id > 0 && (this.GroupRoleId != databaseRecord.GroupRoleId || this.GroupMemberStatus != databaseRecord.GroupMemberStatus) &&
                     this.GroupMemberStatus == GroupMemberStatus.Active)
            {
                // if existing group member changing role or status..
                // verify that active count has not exceeded the max
                if (groupRole.MaxCount != null && (memberCountInRole + 1) > groupRole.MaxCount)
                {
                    roleMembershipAboveMax = true;
                }
            }

            // throw error if above max.. do not proceed
            if (roleMembershipAboveMax)
            {
                errorMessage = string.Format(
                    "The number of {0} for this {1} is at or above its maximum allowed limit of {2:N0} active {3}.",
                    groupRole.Name.Pluralize(),
                    groupRole.GroupType.GroupTerm,
                    groupRole.MaxCount,
                    groupRole.GroupType.GroupMemberTerm.Pluralize(groupRole.MaxCount == 1));
                return(false);
            }

            // if the GroupMember is getting Added (or if Person or Role is different), and if this Group has requirements that must be met before the person is added, check those
            if (this.IsNewOrChangedGroupMember(rockContext))
            {
                var group = this.Group ?? new GroupService(rockContext).Get(this.GroupId);
                if (group.MustMeetRequirementsToAddMember ?? false)
                {
                    var requirementStatuses = group.PersonMeetsGroupRequirements(this.PersonId, this.GroupRoleId);

                    if (requirementStatuses.Any(a => a.MeetsGroupRequirement == MeetsGroupRequirement.NotMet))
                    {
                        // deny if any of the non-manual requirements are not met
                        errorMessage = "This person does not meet the following requirements for this group: "
                                       + requirementStatuses.Where(a => a.MeetsGroupRequirement == MeetsGroupRequirement.NotMet)
                                       .Select(a => string.Format("{0}", a.GroupRequirement.GroupRequirementType))
                                       .ToList().AsDelimited(", ");

                        return(false);
                    }
                }
            }

            return(true);
        }
Example #33
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute( IJobExecutionContext context )
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;
            var groupType = GroupTypeCache.Read( dataMap.GetString( "GroupType" ).AsGuid() );
            int attendanceRemindersSent = 0;
            if ( groupType.TakesAttendance && groupType.SendAttendanceReminder )
            {

                // Get the occurrence dates that apply
                var dates = new List<DateTime>();
                dates.Add( RockDateTime.Today );
                try
                {
                    string[] reminderDays = dataMap.GetString( "SendReminders" ).Split( ',' );
                    foreach ( string reminderDay in reminderDays )
                    {
                        if ( reminderDay.Trim() != string.Empty )
                        {
                            var reminderDate = RockDateTime.Today.AddDays( 0 - Convert.ToInt32( reminderDay ) );
                            if ( !dates.Contains( reminderDate ) )
                            {
                                dates.Add( reminderDate );
                            }
                        }
                    }
                }
                catch { }

                var rockContext = new RockContext();
                var groupService = new GroupService( rockContext );
                var groupMemberService = new GroupMemberService( rockContext );
                var scheduleService = new ScheduleService( rockContext );
                var attendanceService = new AttendanceService( rockContext );

                var startDate = dates.Min();
                var endDate = dates.Max().AddDays( 1 );

                // Find all 'occurrences' for the groups that occur on the affected dates
                var occurrences = new Dictionary<int, List<DateTime>>();
                foreach ( var group in groupService
                    .Queryable( "Schedule" ).AsNoTracking()
                    .Where( g =>
                        g.GroupTypeId == groupType.Id &&
                        g.IsActive &&
                        g.Schedule != null &&
                        g.Members.Any( m =>
                            m.GroupMemberStatus == GroupMemberStatus.Active &&
                            m.GroupRole.IsLeader &&
                            m.Person.Email != null &&
                            m.Person.Email != "" ) ) )
                {
                    // Add the group
                    occurrences.Add( group.Id, new List<DateTime>() );

                    // Check for a iCal schedule
                    if ( !string.IsNullOrWhiteSpace( group.Schedule.iCalendarContent ) )
                    {
                        // If schedule has an iCal schedule, get occurrences between first and last dates
                        foreach ( var occurrence in group.Schedule.GetOccurrences( startDate, endDate ) )
                        {
                            var startTime = occurrence.Period.StartTime.Value;
                            if ( dates.Contains( startTime.Date ) )
                            {
                                occurrences[group.Id].Add( startTime );
                            }
                        }
                    }
                    else
                    {
                        // if schedule does not have an iCal, then check for weekly schedule and calculate occurrences starting with first attendance or current week
                        if ( group.Schedule.WeeklyDayOfWeek.HasValue )
                        {
                            foreach ( var date in dates )
                            {
                                if ( date.DayOfWeek == group.Schedule.WeeklyDayOfWeek.Value )
                                {
                                    var startTime = date;
                                    if ( group.Schedule.WeeklyTimeOfDay.HasValue )
                                    {
                                        startTime = startTime.Add( group.Schedule.WeeklyTimeOfDay.Value );
                                    }
                                    occurrences[group.Id].Add( startTime );
                                }
                            }
                        }
                    }
                }

                // Remove any occurrences during group type exclusion date ranges
                foreach ( var exclusion in groupType.GroupScheduleExclusions )
                {
                    if ( exclusion.Start.HasValue && exclusion.End.HasValue )
                    {
                        foreach ( var keyVal in occurrences )
                        {
                            foreach ( var occurrenceDate in keyVal.Value.ToList() )
                            {
                                if ( occurrenceDate >= exclusion.Start.Value &&
                                    occurrenceDate < exclusion.End.Value.AddDays( 1 ) )
                                {
                                    keyVal.Value.Remove( occurrenceDate );
                                }
                            }
                        }
                    }
                }

                // Remove any 'occurrenes' that already have attendance data entered
                foreach ( var occurrence in attendanceService
                    .Queryable().AsNoTracking()
                    .Where( a =>
                        a.StartDateTime >= startDate &&
                        a.StartDateTime < endDate &&
                        occurrences.Keys.Contains( a.GroupId.Value ) &&
                        a.ScheduleId.HasValue )
                    .Select( a => new
                    {
                        GroupId = a.GroupId.Value,
                        a.StartDateTime
                    } )
                    .Distinct()
                    .ToList() )
                {
                    occurrences[occurrence.GroupId].RemoveAll( d => d.Date == occurrence.StartDateTime.Date );
                }

                // Get the groups that have occurrences
                var groupIds = occurrences.Where( o => o.Value.Any() ).Select( o => o.Key ).ToList();

                // Get the leaders of those groups
                var leaders = groupMemberService
                    .Queryable( "Group,Person" ).AsNoTracking()
                    .Where( m =>
                        groupIds.Contains( m.GroupId ) &&
                        m.GroupMemberStatus == GroupMemberStatus.Active &&
                        m.GroupRole.IsLeader &&
                        m.Person.Email != null &&
                        m.Person.Email != "" )
                    .ToList();

                // Loop through the leaders
                foreach ( var leader in leaders )
                {
                    foreach ( var group in occurrences.Where( o => o.Key == leader.GroupId ) )
                    {
                        var mergeObjects = Rock.Lava.LavaHelper.GetCommonMergeFields(  null, leader.Person );
                        mergeObjects.Add( "Person", leader.Person );
                        mergeObjects.Add( "Group", leader.Group );
                        mergeObjects.Add( "Occurrence", group.Value.Max() );

                        var recipients = new List<RecipientData>();
                        recipients.Add( new RecipientData( leader.Person.Email, mergeObjects ) );

                        Email.Send( dataMap.GetString( "SystemEmail" ).AsGuid(), recipients );
                        attendanceRemindersSent++;

                    }
                }
            }

            context.Result = string.Format( "{0} attendance reminders sent", attendanceRemindersSent );
        }
Example #34
0
        /// <summary>
        /// Validates the group membership.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ValidateGroupMembership(RockContext rockContext, out string errorMessage)
        {
            errorMessage = string.Empty;
            GroupMemberService groupMemberService = new GroupMemberService(rockContext);
            var groupRole = this.GroupRole ?? new GroupTypeRoleService(rockContext).Get(this.GroupRoleId);

            // check to see if the person is alread a member of the gorup/role
            var existingGroupMembership = groupMemberService.GetByGroupIdAndPersonId(this.GroupId, this.PersonId);

            if (existingGroupMembership.Any(a => a.GroupRoleId == this.GroupRoleId && a.Id != this.Id))
            {
                var person = this.Person ?? new PersonService(rockContext).Get(this.PersonId);

                errorMessage = string.Format(
                    "{0} already belongs to the {1} role for this {2}, and cannot be added again with the same role",
                    person,
                    groupRole.Name,
                    groupRole.GroupType.GroupTerm);

                return(false);
            }

            var databaseRecord = existingGroupMembership.FirstOrDefault(a => a.Id == this.Id);

            int memberCountInRole = new GroupMemberService(rockContext).Queryable()
                                    .Where(m =>
                                           m.GroupId == this.GroupId &&
                                           m.GroupRoleId == this.GroupRoleId &&
                                           m.GroupMemberStatus == GroupMemberStatus.Active)
                                    .Count();

            bool roleMembershipAboveMax = false;

            // if adding new active group member..
            if (this.Id.Equals(0) && this.GroupMemberStatus == GroupMemberStatus.Active)
            {
                // verify that active count has not exceeded the max
                if (groupRole.MaxCount != null && (memberCountInRole + 1) > groupRole.MaxCount)
                {
                    roleMembershipAboveMax = true;
                }
            }
            else if (this.Id > 0 && (this.GroupRoleId != databaseRecord.GroupRoleId || this.GroupMemberStatus != databaseRecord.GroupMemberStatus) &&
                     this.GroupMemberStatus == GroupMemberStatus.Active)
            {
                // if existing group member changing role or status..
                // verify that active count has not exceeded the max
                if (groupRole.MaxCount != null && (memberCountInRole + 1) > groupRole.MaxCount)
                {
                    roleMembershipAboveMax = true;
                }
            }

            // throw error if above max.. do not proceed
            if (roleMembershipAboveMax)
            {
                errorMessage = string.Format(
                    "The number of {0} for this {1} is at or above its maximum allowed limit of {2:N0} active {3}.",
                    groupRole.Name.Pluralize(),
                    groupRole.GroupType.GroupTerm,
                    groupRole.MaxCount,
                    groupRole.GroupType.GroupMemberTerm.Pluralize(groupRole.MaxCount == 1));
                return(false);
            }

            return(true);
        }