/// <summary>
        /// Gets a list of ISecured and IEntity entities (all models) that have not yet been registered and adds them
        /// as an <see cref="Rock.Model.EntityType"/>.
        /// </summary>
        /// <param name="physWebAppPath">A <see cref="System.String"/> that represents the physical path of the web application</param>
        public static void RegisterEntityTypes(string physWebAppPath)
        {
            var entityTypes = new Dictionary <string, EntityType>();

            foreach (var type in Rock.Reflection.FindTypes(typeof(Rock.Data.IEntity)))
            {
                var entityType = new EntityType();
                entityType.Name         = type.Key;
                entityType.FriendlyName = type.Value.Name.SplitCase();
                entityType.AssemblyName = type.Value.AssemblyQualifiedName;
                entityType.IsEntity     = !type.Value.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute), false).Any();
                entityType.IsSecured    = false;
                entityTypes.Add(type.Key.ToLower(), entityType);
            }

            foreach (var type in Rock.Reflection.FindTypes(typeof(Rock.Security.ISecured)))
            {
                string key = type.Key.ToLower();

                if (entityTypes.ContainsKey(key))
                {
                    entityTypes[key].IsSecured = true;
                }
                else
                {
                    var entityType = new EntityType();
                    entityType.Name         = type.Key;
                    entityType.FriendlyName = type.Value.Name.SplitCase();
                    entityType.AssemblyName = type.Value.AssemblyQualifiedName;
                    entityType.IsEntity     = false;
                    entityType.IsSecured    = true;
                    entityTypes.Add(key, entityType);
                }
            }

            using (var rockContext = new RockContext())
            {
                var entityTypeService = new EntityTypeService(rockContext);

                // Find any existing EntityTypes marked as an entity or secured that are no longer an entity or secured
                foreach (var oldEntityType in entityTypeService.Queryable()
                         .Where(e => e.IsEntity || e.IsSecured)
                         .ToList())
                {
                    if (!entityTypes.Keys.Contains(oldEntityType.Name.ToLower()))
                    {
                        oldEntityType.IsSecured    = false;
                        oldEntityType.IsEntity     = false;
                        oldEntityType.AssemblyName = null;
                        EntityTypeCache.Flush(oldEntityType.Id);
                    }
                }

                // Update any existing entities
                foreach (var existingEntityType in entityTypeService.Queryable()
                         .Where(e => entityTypes.Keys.Contains(e.Name))
                         .ToList())
                {
                    var key = existingEntityType.Name.ToLower();

                    var entityType = entityTypes[key];

                    if (existingEntityType.Name != entityType.Name ||
                        existingEntityType.IsEntity != entityType.IsEntity ||
                        existingEntityType.IsSecured != entityType.IsSecured ||
                        existingEntityType.FriendlyName != (existingEntityType.FriendlyName ?? entityType.FriendlyName) ||
                        existingEntityType.AssemblyName != entityType.AssemblyName)
                    {
                        existingEntityType.Name         = entityType.Name;
                        existingEntityType.IsEntity     = entityType.IsEntity;
                        existingEntityType.IsSecured    = entityType.IsSecured;
                        existingEntityType.FriendlyName = existingEntityType.FriendlyName ?? entityType.FriendlyName;
                        existingEntityType.AssemblyName = entityType.AssemblyName;
                        EntityTypeCache.Flush(existingEntityType.Id);
                    }
                    entityTypes.Remove(key);
                }

                // Add the newly discovered entities
                foreach (var entityTypeInfo in entityTypes)
                {
                    // Don't add the EntityType entity as it will probably have been automatically
                    // added by the audit on a previous save in this method.
                    if (entityTypeInfo.Value.Name != "Rock.Model.EntityType")
                    {
                        entityTypeService.Add(entityTypeInfo.Value);
                    }
                }

                rockContext.SaveChanges();

                // make sure the EntityTypeCache is synced up with any changes that were made
                foreach (var entityTypeModel in entityTypeService.Queryable())
                {
                    EntityTypeCache.Read(entityTypeModel);
                }
            }
        }
        /// <summary>
        /// Job that will run quick SQL queries on a schedule.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            Guid?entryWorkflowType = dataMap.GetString("EraEntryWorkflow").AsGuidOrNull();
            Guid?exitWorkflowType  = dataMap.GetString("EraExitWorkflow").AsGuidOrNull();
            bool updateVisitDates  = dataMap.GetBooleanValue("SetVisitDates");
            var  groupTypeList     = dataMap.GetString("GroupTypes");

            // configuration
            //

            // giving
            int exitGivingCount = 1;

            // attendance
            int exitAttendanceCountShort = 1;
            int exitAttendanceCountLong  = 8;

            // get era dataset from stored proc
            var resultContext = new RockContext();


            var eraAttribute      = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid());
            var eraStartAttribute = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid());
            var eraEndAttribute   = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid());

            resultContext.Database.CommandTimeout = 3600;

            var results = resultContext.Database.SqlQuery <EraResult>("spCrm_FamilyAnalyticsEraDataset").ToList();

            int personEntityTypeId        = EntityTypeCache.Read("Rock.Model.Person").Id;
            int attributeEntityTypeId     = EntityTypeCache.Read("Rock.Model.Attribute").Id;
            int eraAttributeId            = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid()).Id;
            int personAnalyticsCategoryId = CategoryCache.Read(SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid()).Id;

            foreach (var result in results)
            {
                // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops)
                RockContext updateContext         = new RockContext();
                var         attributeValueService = new AttributeValueService(updateContext);
                var         historyService        = new HistoryService(updateContext);

                // if era ensure it still meets requirements
                if (result.IsEra)
                {
                    if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong)
                    {
                        // exit era (delete attribute value from each person in family)
                        var family = new GroupService(updateContext).Queryable("Members, Members.Person").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault();

                        if (family != null)
                        {
                            foreach (var person in family.Members.Select(m => m.Person))
                            {
                                // remove the era flag
                                var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                                if (eraAttributeValue != null)
                                {
                                    attributeValueService.Delete(eraAttributeValue);
                                }

                                // set end date
                                var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                                if (eraEndAttributeValue == null)
                                {
                                    eraEndAttributeValue             = new AttributeValue();
                                    eraEndAttributeValue.EntityId    = person.Id;
                                    eraEndAttributeValue.AttributeId = eraEndAttribute.Id;
                                    attributeValueService.Add(eraEndAttributeValue);
                                }
                                eraEndAttributeValue.Value = RockDateTime.Now.ToString();

                                // add a history record
                                if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0)
                                {
                                    History historyRecord = new History();
                                    historyService.Add(historyRecord);
                                    historyRecord.EntityTypeId           = personEntityTypeId;
                                    historyRecord.EntityId               = person.Id;
                                    historyRecord.CreatedDateTime        = RockDateTime.Now;
                                    historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId;
                                    historyRecord.Caption             = "eRA";
                                    historyRecord.Summary             = "Exited eRA Status";
                                    historyRecord.Verb                = "EXITED";
                                    historyRecord.RelatedEntityTypeId = attributeEntityTypeId;
                                    historyRecord.RelatedEntityId     = eraAttributeId;
                                    historyRecord.CategoryId          = personAnalyticsCategoryId;
                                }

                                updateContext.SaveChanges();
                            }

                            // launch exit workflow
                            if (exitWorkflowType.HasValue)
                            {
                                LaunchWorkflow(exitWorkflowType.Value, family);
                            }
                        }
                    }
                }
                else
                {
                    // entered era
                    var family = new GroupService(updateContext).Queryable("Members").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault();

                    if (family != null)
                    {
                        foreach (var person in family.Members.Select(m => m.Person))
                        {
                            // set era attribute to true
                            var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraAttributeValue == null)
                            {
                                eraAttributeValue             = new AttributeValue();
                                eraAttributeValue.EntityId    = person.Id;
                                eraAttributeValue.AttributeId = eraAttribute.Id;
                                attributeValueService.Add(eraAttributeValue);
                            }
                            eraAttributeValue.Value = bool.TrueString;

                            // add start date
                            var eraStartAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraStartAttributeValue == null)
                            {
                                eraStartAttributeValue             = new AttributeValue();
                                eraStartAttributeValue.EntityId    = person.Id;
                                eraStartAttributeValue.AttributeId = eraStartAttribute.Id;
                                attributeValueService.Add(eraStartAttributeValue);
                            }
                            eraStartAttributeValue.Value = RockDateTime.Now.ToString();

                            // delete end date if it exists
                            var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault();
                            if (eraEndAttributeValue != null)
                            {
                                attributeValueService.Delete(eraEndAttributeValue);
                            }

                            // add a history record
                            if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0)
                            {
                                History historyRecord = new History();
                                historyService.Add(historyRecord);
                                historyRecord.EntityTypeId           = personEntityTypeId;
                                historyRecord.EntityId               = person.Id;
                                historyRecord.CreatedDateTime        = RockDateTime.Now;
                                historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId;
                                historyRecord.Caption             = "eRA";
                                historyRecord.Summary             = "Entered eRA Status";
                                historyRecord.Verb                = "ENTERED";
                                historyRecord.RelatedEntityTypeId = attributeEntityTypeId;
                                historyRecord.RelatedEntityId     = eraAttributeId;
                                historyRecord.CategoryId          = personAnalyticsCategoryId;
                            }

                            updateContext.SaveChanges();
                        }

                        // launch entry workflow
                        if (entryWorkflowType.HasValue)
                        {
                            LaunchWorkflow(entryWorkflowType.Value, family);
                        }
                    }
                }

                // update stats
            }

            // load giving attributes
            resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsGiving");

            // load attendance attributes
            resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsAttendance");

            // process history for group types
            if (!string.IsNullOrWhiteSpace(groupTypeList))
            {
                string[] groupTypeGuids = groupTypeList.Split(',');

                var inactiveRecordValue = DefinedValueCache.Read(SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE);

                var groupTypeEntityTypeId = EntityTypeCache.Read("Rock.Model.GroupType").Id;

                foreach (var groupTypeGuid in groupTypeGuids)
                {
                    var groupType = GroupTypeCache.Read(groupTypeGuid.AsGuid());

                    if (groupType != null)
                    {
                        // if the person is in a group of that type and the last history record for that group type isn't START write a start
                        RockContext rockContext = new RockContext();

                        // get history for this group type
                        var historyRecords = new HistoryService(rockContext).Queryable()
                                             .Where(h =>
                                                    h.EntityTypeId == personEntityTypeId &&
                                                    h.RelatedEntityTypeId == groupTypeEntityTypeId &&
                                                    h.RelatedEntityId == groupType.Id
                                                    )
                                             .GroupBy(h => h.EntityId)
                                             .Select(g => g.OrderByDescending(h => h.CreatedDateTime).Select(h => new { h.EntityId, h.Verb }).FirstOrDefault())
                                             .ToList();

                        // get group member information
                        var groupMemberInfo = new GroupMemberService(rockContext).Queryable()
                                              .Where(m =>
                                                     m.Group.GroupTypeId == groupType.Id &&
                                                     m.GroupMemberStatus == GroupMemberStatus.Active &&
                                                     m.Group.IsActive
                                                     //&& m.Person.RecordStatusValueId != inactiveRecordValue.Id
                                                     )
                                              .GroupBy(m => m.PersonId)
                                              .Select(g => g.OrderBy(m => m.CreatedDateTime).Select(m => new { m.PersonId, m.CreatedDateTime, PersonAliasId = m.Person.Aliases.Select(p => p.Id).FirstOrDefault() }).FirstOrDefault())
                                              .ToList();

                        var needsStartDate = groupMemberInfo.Where(m => !historyRecords.Any(h => h.EntityId == m.PersonId && h.Verb == "STARTED"));

                        foreach (var startItem in needsStartDate)
                        {
                            using (RockContext updateContext = new RockContext())
                            {
                                var     historyService = new HistoryService(updateContext);
                                History history        = new History();
                                historyService.Add(history);
                                history.EntityTypeId        = personEntityTypeId;
                                history.EntityId            = startItem.PersonId;
                                history.RelatedEntityTypeId = groupTypeEntityTypeId;
                                history.RelatedEntityId     = groupType.Id;
                                history.Caption             = groupType.Name;
                                history.Summary             = "Started Membership in Group Of Type";
                                history.Verb                   = "STARTED";
                                history.CreatedDateTime        = startItem.CreatedDateTime;
                                history.CreatedByPersonAliasId = startItem.PersonAliasId;
                                history.CategoryId             = personAnalyticsCategoryId;

                                updateContext.SaveChanges();
                            }
                        }

                        var needsStoppedDate = historyRecords.Where(h => h.Verb == "STARTED" && !groupMemberInfo.Any(m => m.PersonId == h.EntityId));

                        foreach (var stopItem in needsStoppedDate)
                        {
                            using (RockContext updateContext = new RockContext())
                            {
                                var person = new PersonService(updateContext).Get(stopItem.EntityId);

                                if (person != null)
                                {
                                    var     historyService = new HistoryService(updateContext);
                                    History history        = new History();
                                    historyService.Add(history);
                                    history.EntityTypeId        = personEntityTypeId;
                                    history.EntityId            = person.Id;
                                    history.RelatedEntityTypeId = groupTypeEntityTypeId;
                                    history.RelatedEntityId     = groupType.Id;
                                    history.Caption             = groupType.Name;
                                    history.Summary             = "Stopped Membership in Group Of Type";
                                    history.Verb                   = "STOPPED";
                                    history.CreatedDateTime        = RockDateTime.Now;
                                    history.CreatedByPersonAliasId = person.PrimaryAliasId;
                                    history.CategoryId             = personAnalyticsCategoryId;

                                    updateContext.SaveChanges();
                                }
                            }
                        }
                    }
                }
            }

            // process visit dates
            if (updateVisitDates)
            {
                resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsUpdateVisitDates");
            }
        }
Exemple #3
0
        /// <summary>
        /// Occurs before the action method is invoked.
        /// </summary>
        /// <param name="actionContext">The action context.</param>
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var    principal = actionContext.Request.GetUserPrincipal();
            Person person    = null;

            if (principal != null && principal.Identity != null)
            {
                using (var rockContext = new RockContext())
                {
                    string    userName  = principal.Identity.Name;
                    UserLogin userLogin = null;
                    if (userName.StartsWith("rckipid="))
                    {
                        var personService      = new PersonService(rockContext);
                        var impersonatedPerson = personService.GetByImpersonationToken(userName.Substring(8));
                        if (impersonatedPerson != null)
                        {
                            userLogin = impersonatedPerson.GetImpersonatedUser();
                        }
                    }
                    else
                    {
                        var userLoginService = new UserLoginService(rockContext);
                        userLogin = userLoginService.GetByUserName(userName);
                    }

                    if (userLogin != null)
                    {
                        person = userLogin.Person;
                        var pinAuthentication = AuthenticationContainer.GetComponent(typeof(Security.Authentication.PINAuthentication).FullName);

                        // Don't allow PIN authentications.
                        if (userLogin.EntityTypeId != null)
                        {
                            var userLoginEntityType = EntityTypeCache.Get(userLogin.EntityTypeId.Value);
                            if (userLoginEntityType != null && userLoginEntityType.Id == pinAuthentication?.EntityType?.Id)
                            {
                                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                                return;
                            }
                        }
                    }
                }
            }

            var reflectedHttpActionDescriptor = ( ReflectedHttpActionDescriptor )actionContext.ActionDescriptor;

            var controller          = actionContext.ActionDescriptor.ControllerDescriptor;
            var controllerClassName = controller.ControllerType.FullName;
            var actionMethod        = actionContext.Request.Method.Method;

            var      apiId = RestControllerService.GetApiId(reflectedHttpActionDescriptor.MethodInfo, actionMethod, controller.ControllerName);
            ISecured item  = RestActionCache.Get(apiId);

            if (item == null)
            {
                // if there isn't a RestAction in the database, use the Controller as the secured item
                item = RestControllerCache.Get(controllerClassName);
                if (item == null)
                {
                    item = new RestController();
                }
            }

            if (actionContext.Request.Properties.Keys.Contains("Person"))
            {
                person = actionContext.Request.Properties["Person"] as Person;
            }
            else
            {
                actionContext.Request.Properties.Add("Person", person);

                /* 12/12/2019 BJW
                 *
                 * Setting this current person item was only done in put, post, and patch in the ApiController
                 * class. Set it here so that it is always set for all methods, including delete. This enhances
                 * history logging done in the pre and post save model hooks (when the pre-save event is called
                 * we can access DbContext.GetCurrentPersonAlias and log who deleted the record).
                 *
                 * Task: https://app.asana.com/0/1120115219297347/1153140643799337/f
                 */
                System.Web.HttpContext.Current.AddOrReplaceItem("CurrentPerson", person);
            }

            string action = actionMethod.Equals("GET", StringComparison.OrdinalIgnoreCase) ?
                            Security.Authorization.VIEW : Security.Authorization.EDIT;

            bool authorized = false;

            if (item.IsAuthorized(action, person))
            {
                authorized = true;
            }
            else if (actionContext.Request.Headers.Contains("X-Rock-App-Id") && actionContext.Request.Headers.Contains("X-Rock-Mobile-Api-Key"))
            {
                // Normal authorization failed, but this is a Mobile App request so check
                // if the application itself has been given permission.
                var appId        = actionContext.Request.Headers.GetValues("X-Rock-App-Id").First().AsIntegerOrNull();
                var mobileApiKey = actionContext.Request.Headers.GetValues("X-Rock-Mobile-Api-Key").First();

                if (appId.HasValue)
                {
                    using (var rockContext = new RockContext())
                    {
                        var appUser = Mobile.MobileHelper.GetMobileApplicationUser(appId.Value, mobileApiKey, rockContext);

                        if (appUser != null && item.IsAuthorized(action, appUser.Person))
                        {
                            authorized = true;
                        }
                    }
                }
            }

            if (!authorized)
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
            }
        }
        /// <summary>
        /// Shows the detail.
        /// </summary>
        /// <param name="groupRequirementTypeId">The group requirement type identifier.</param>
        public void ShowDetail(int groupRequirementTypeId)
        {
            RockContext                 rockContext                 = new RockContext();
            GroupRequirementType        groupRequirementType        = null;
            GroupRequirementTypeService groupRequirementTypeService = new GroupRequirementTypeService(rockContext);

            if (!groupRequirementTypeId.Equals(0))
            {
                groupRequirementType = groupRequirementTypeService.Get(groupRequirementTypeId);
                lActionTitle.Text    = ActionTitle.Edit(GroupRequirementType.FriendlyTypeName).FormatAsHtmlTitle();
                pdAuditDetails.SetEntity(groupRequirementType, ResolveRockUrl("~"));
            }

            if (groupRequirementType == null)
            {
                groupRequirementType = new GroupRequirementType {
                    Id = 0
                };
                groupRequirementType.RequirementCheckType = RequirementCheckType.Manual;
                lActionTitle.Text = ActionTitle.Add(GroupRequirementType.FriendlyTypeName).FormatAsHtmlTitle();
                // hide the panel drawer that show created and last modified dates
                pdAuditDetails.Visible = false;
            }

            hfGroupRequirementTypeId.Value = groupRequirementType.Id.ToString();
            tbName.Text          = groupRequirementType.Name;
            tbDescription.Text   = groupRequirementType.Description;
            tbPositiveLabel.Text = groupRequirementType.PositiveLabel;
            tbNegativeLabel.Text = groupRequirementType.NegativeLabel;
            tbWarningLabel.Text  = groupRequirementType.WarningLabel;
            tbCheckboxLabel.Text = groupRequirementType.CheckboxLabel;
            cbCanExpire.Checked  = groupRequirementType.CanExpire;
            nbExpireInDays.Text  = groupRequirementType.ExpireInDays.ToString();

            nbSQLHelp.InnerHtml = @"A SQL expression that returns a list of Person Ids that meet the criteria. Example:
<pre>
SELECT [Id] FROM [Person]
WHERE [LastName] = 'Decker'</pre>
</pre>
The SQL can include Lava merge fields:

<ul>
   <li>Group</i>
   <li>GroupRequirementType</i>
</ul>

TIP: When calculating for a specific Person, a <strong>Person</strong> merge field will also be included. This can improve performance in cases when the system is checking requirements for a specific person. Example:

<pre>
    SELECT [Id] FROM [Person]
        WHERE [LastName] = 'Decker'
    {% if Person != empty %}
        AND [Id] = {{ Person.Id }}
    {% endif %}
</pre>
";

            nbSQLHelp.InnerHtml += groupRequirementType.GetMergeObjects(new Group(), this.CurrentPerson).lavaDebugInfo();

            ceSqlExpression.Text = groupRequirementType.SqlExpression;

            ceWarningSqlExpression.Text = groupRequirementType.WarningSqlExpression;

            dpDataView.EntityTypeId = EntityTypeCache.Get <Person>().Id;
            dpDataView.SetValue(groupRequirementType.DataViewId);

            dpWarningDataView.EntityTypeId = EntityTypeCache.Get <Person>().Id;
            dpWarningDataView.SetValue(groupRequirementType.WarningDataViewId);

            hfRequirementCheckType.Value = groupRequirementType.RequirementCheckType.ConvertToInt().ToString();
        }
Exemple #5
0
        /// <summary>
        /// Adds the admin controls.
        /// </summary>
        /// <param name="block">The block.</param>
        /// <param name="pnlLayoutItem">The PNL layout item.</param>
        private void AddAdminControls(BlockCache block, Panel pnlLayoutItem)
        {
            Panel pnlAdminButtons = new Panel {
                ID = "pnlBlockConfigButtons", CssClass = "pull-right actions"
            };

            // Block Properties
            Literal btnBlockProperties = new Literal();

            btnBlockProperties.Text = string.Format(@"<a title='Block Properties' class='btn btn-sm btn-default btn-square properties' id='aBlockProperties' href='javascript: Rock.controls.modal.show($(this), ""/BlockProperties/{0}?t=Block Properties"")' height='500px'><i class='fa fa-cog'></i></a>", block.Id);
            pnlAdminButtons.Controls.Add(btnBlockProperties);

            // Block Security
            int            entityTypeBlockId = EntityTypeCache.Get <Rock.Model.Block>().Id;
            SecurityButton btnBlockSecurity  = new SecurityButton {
                ID = "btnBlockSecurity", EntityTypeId = entityTypeBlockId, EntityId = block.Id, Title = block.Name
            };

            btnBlockSecurity.AddCssClass("btn btn-sm btn-square btn-security");
            pnlAdminButtons.Controls.Add(btnBlockSecurity);

            // Move Block
            LinkButton btnMoveBlock = new LinkButton();

            btnMoveBlock.ID              = string.Format("btnMoveBlock_{0}", block.Id);
            btnMoveBlock.CommandName     = "BlockId";
            btnMoveBlock.CommandArgument = block.Id.ToString();
            btnMoveBlock.CssClass        = "btn btn-sm btn-default btn-square fa fa-external-link";
            btnMoveBlock.ToolTip         = "Move Block";
            btnMoveBlock.Click          += btnMoveBlock_Click;
            pnlAdminButtons.Controls.Add(btnMoveBlock);

            // Delete Block
            LinkButton btnDeleteBlock = new LinkButton();

            btnDeleteBlock.ID                    = string.Format("btnDeleteBlock_{0}", block.Id);
            btnDeleteBlock.CommandName           = "BlockId";
            btnDeleteBlock.CommandArgument       = block.Id.ToString();
            btnDeleteBlock.CssClass              = "btn btn-sm btn-square btn-danger";
            btnDeleteBlock.Text                  = "<i class='fa fa-times'></i>";
            btnDeleteBlock.ToolTip               = "Delete Block";
            btnDeleteBlock.Click                += btnDeleteBlock_Click;
            btnDeleteBlock.Attributes["onclick"] = string.Format("javascript: return Rock.dialogs.confirmDelete(event, '{0}');", Block.FriendlyTypeName);

            pnlAdminButtons.Controls.Add(btnDeleteBlock);

            pnlLayoutItem.Controls.Add(pnlAdminButtons);

            RockBlock blockControl = null;
            IEnumerable <WebControl> customAdminControls = new List <WebControl>();

            try
            {
                blockControl = this.Page.TemplateControl.LoadControl(block.BlockType.Path) as RockBlock;
                blockControl.SetBlock(block.Page, block, true, true);
                var      adminControls           = blockControl.GetAdministrateControls(true, true);
                string[] baseAdminControlClasses = new string[4] {
                    "properties", "security", "block-move", "block-delete"
                };
                customAdminControls = adminControls.OfType <WebControl>().Where(a => !baseAdminControlClasses.Any(b => a.CssClass.Contains(b)));
            }
            catch (Exception ex)
            {
                // if the block doesn't compile, just ignore it since we are just trying to get the admin controls
                Literal lblBlockError = new Literal();
                lblBlockError.Text = string.Format("<span class='label label-danger'>ERROR: {0}</span>", ex.Message);
                pnlLayoutItem.Controls.Add(lblBlockError);
            }

            foreach (var customAdminControl in customAdminControls)
            {
                if (customAdminControl is LinkButton)
                {
                    LinkButton btn = customAdminControl as LinkButton;
                    if (btn != null)
                    {
                        // ensure custom link button looks like a button
                        btn.AddCssClass("btn");
                        btn.AddCssClass("btn-sm");
                        btn.AddCssClass("btn-default");

                        // some admincontrols will toggle the BlockConfig bar, but this isn't a block config bar, so remove the javascript
                        if (btn.Attributes["onclick"] != null)
                        {
                            btn.Attributes["onclick"] = btn.Attributes["onclick"].Replace("Rock.admin.pageAdmin.showBlockConfig()", string.Empty);
                        }
                    }
                }

                pnlLayoutItem.Controls.Add(customAdminControl);
            }

            if (customAdminControls.Any() && blockControl != null)
            {
                pnlBlocksHolder.Controls.Add(blockControl);
            }
        }
Exemple #6
0
        /// <summary>
        /// Gets the data view expression.
        /// </summary>
        /// <param name="dataViewId">The data view identifier.</param>
        /// <param name="service">The service.</param>
        /// <param name="parmExpression">The parm expression.</param>
        /// <param name="entityTypeCache">The entity type cache.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception"></exception>
        private Expression GetDataViewExpression(int dataViewId, IService service, ParameterExpression parmExpression, EntityTypeCache entityTypeCache)
        {
            if (service.Context is RockContext)
            {
                var  dataViewSource    = new DataViewService(service.Context as RockContext).Get(dataViewId);
                bool isCorrectDataType = dataViewSource.EntityTypeId == entityTypeCache.Id;

                if (isCorrectDataType)
                {
                    List <string> errorMessages   = new List <string>();
                    var           whereExpression = dataViewSource.GetExpression(service, parmExpression, out errorMessages);
                    return(whereExpression);
                }
                else
                {
                    throw new Exception(string.Format("The DataView provided is not of type {0}.", entityTypeCache.FriendlyName));
                }
            }
            else
            {
                throw new Exception(string.Format("The database context for type {0} does not support RockContext dataviews.", entityTypeCache.FriendlyName));
            }
        }
Exemple #7
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        /// <exception cref="System.Exception">Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.</exception>
        public override void Render(Context context, TextWriter result)
        {
            // first ensure that entity commands are allowed in the context
            if (!this.IsAuthorized(context))
            {
                result.Write(string.Format(RockLavaBlockBase.NotAuthorizedMessage, this.Name));
                base.Render(context, result);
                return;
            }

            bool hasFilter = false;

            // get a service for the entity based off it's friendly name
            var entityTypes = EntityTypeCache.All();

            var model = string.Empty;

            if (_entityName == "business")
            {
                model = "Rock.Model.Person";
            }
            else
            {
                model = "Rock.Model." + _entityName;
            }

            // Check first to see if this is a core model
            var entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, model, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

            // If not, look for first plug-in model that has same friendly name
            if (entityTypeCache == null)
            {
                entityTypeCache = entityTypes
                                  .Where(e =>
                                         e.IsEntity &&
                                         !e.Name.StartsWith("Rock.Model") &&
                                         e.FriendlyName != null &&
                                         e.FriendlyName.RemoveSpaces().ToLower() == _entityName)
                                  .OrderBy(e => e.Id)
                                  .FirstOrDefault();
            }

            // If still null check to see if this was a duplicate class and full class name was used as entity name
            if (entityTypeCache == null)
            {
                model           = _entityName.Replace('_', '.');
                entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, model, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
            }

            if (entityTypeCache != null)
            {
                Type entityType = entityTypeCache.GetEntityType();
                if (entityType != null)
                {
                    // Get the database context
                    var dbContext = Reflection.GetDbContextForEntityType(entityType);

                    // create an instance of the entity's service
                    Rock.Data.IService serviceInstance = Reflection.GetServiceForEntityType(entityType, dbContext);

                    ParameterExpression paramExpression = Expression.Parameter(entityType, "x");
                    Expression          queryExpression = null; // the base expression we'll use to build our query from

                    // parse markup
                    var parms = ParseMarkup(_markup, context);

                    if (parms.Any(p => p.Key == "id"))
                    {
                        string propertyName = "Id";

                        List <string> selectionParms = new List <string>();
                        selectionParms.Add(PropertyComparisonConversion("==").ToString());
                        selectionParms.Add(parms["id"].ToString());
                        selectionParms.Add(propertyName);

                        var entityProperty = entityType.GetProperty(propertyName);
                        queryExpression = ExpressionHelper.PropertyFilterExpression(selectionParms, paramExpression, propertyName, entityProperty.PropertyType);

                        hasFilter = true;
                    }
                    else
                    {
                        // where clause expression
                        if (parms.Any(p => p.Key == "where"))
                        {
                            queryExpression = ParseWhere(parms["where"], entityType, serviceInstance, paramExpression, entityType, entityTypeCache);

                            if (queryExpression != null)
                            {
                                hasFilter = true;
                            }
                        }

                        // DataView expression
                        if (parms.Any(p => p.Key == "dataview"))
                        {
                            var dataViewId = parms["dataview"].AsIntegerOrNull();

                            if (dataViewId.HasValue)
                            {
                                var dataViewExpression = GetDataViewExpression(dataViewId.Value, serviceInstance, paramExpression, entityTypeCache);

                                if (queryExpression == null)
                                {
                                    queryExpression = dataViewExpression;
                                    hasFilter       = true;
                                }
                                else
                                {
                                    queryExpression = Expression.AndAlso(queryExpression, dataViewExpression);
                                }
                            }
                        }

                        // process dynamic filter expressions (from the query string)
                        if (parms.Any(p => p.Key == "dynamicparameters"))
                        {
                            var dynamicFilters = parms["dynamicparameters"].Split(',')
                                                 .Select(x => x.Trim())
                                                 .Where(x => !string.IsNullOrWhiteSpace(x))
                                                 .ToList();

                            foreach (var dynamicFilter in dynamicFilters)
                            {
                                var dynamicFilterValue      = HttpContext.Current.Request[dynamicFilter];
                                var dynamicFilterExpression = GetDynamicFilterExpression(dynamicFilter, dynamicFilterValue, entityType, serviceInstance, paramExpression);
                                if (dynamicFilterExpression != null)
                                {
                                    if (queryExpression == null)
                                    {
                                        queryExpression = dynamicFilterExpression;
                                        hasFilter       = true;
                                    }
                                    else
                                    {
                                        queryExpression = Expression.AndAlso(queryExpression, dynamicFilterExpression);
                                    }
                                }
                            }
                        }
                    }

                    // make the query from the expression
                    MethodInfo getMethod = serviceInstance.GetType().GetMethod("Get", new Type[] { typeof(ParameterExpression), typeof(Expression), typeof(Rock.Web.UI.Controls.SortProperty), typeof(int?) });
                    if (getMethod != null)
                    {
                        var queryResult = getMethod.Invoke(serviceInstance, new object[] { paramExpression, queryExpression, null, null }) as IQueryable <IEntity>;

                        // process entity specific filters
                        switch (_entityName)
                        {
                        case "person":
                        {
                            queryResult = PersonFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }

                        case "business":
                        {
                            queryResult = BusinessFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }
                        }

                        // if there was a dynamic expression add it now
                        if (parms.Any(p => p.Key == "expression"))
                        {
                            queryResult = queryResult.Where(parms["expression"]);
                            hasFilter   = true;
                        }

                        // get a listing of ids
                        if (parms.Any(p => p.Key == "ids"))
                        {
                            var value = parms["ids"].ToString().Split(',').Select(int.Parse).ToList();
                            queryResult = queryResult.Where(x => value.Contains(x.Id));
                            hasFilter   = true;
                        }

                        var queryResultExpression = queryResult.Expression;

                        // add sort expressions
                        if (parms.Any(p => p.Key == "sort"))
                        {
                            string orderByMethod = "OrderBy";


                            foreach (var column in parms["sort"].Split(',').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList())
                            {
                                string propertyName;
                                var    direction = SortDirection.Ascending;

                                if (column.EndsWith(" desc", StringComparison.OrdinalIgnoreCase))
                                {
                                    direction    = SortDirection.Descending;
                                    propertyName = column.Left(column.Length - 5);
                                }
                                else
                                {
                                    propertyName = column;
                                }

                                string methodName = direction == SortDirection.Descending ? orderByMethod + "Descending" : orderByMethod;

                                if (entityType.GetProperty(propertyName) != null)
                                {
                                    // sorting a entity property
                                    var memberExpression          = Expression.Property(paramExpression, propertyName);
                                    LambdaExpression sortSelector = Expression.Lambda(memberExpression, paramExpression);
                                    queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                }
                                else
                                {
                                    // sorting on an attribute

                                    // get attribute id
                                    int?attributeId = null;
                                    foreach (var id in AttributeCache.GetByEntity(entityTypeCache.Id).SelectMany(a => a.AttributeIds))
                                    {
                                        var attribute = AttributeCache.Get(id);
                                        if (attribute.Key == propertyName)
                                        {
                                            attributeId = id;
                                            break;
                                        }
                                    }

                                    if (attributeId.HasValue)
                                    {
                                        // get AttributeValue queryable and parameter
                                        if (dbContext is RockContext)
                                        {
                                            var attributeValues = new AttributeValueService(dbContext as RockContext).Queryable();
                                            ParameterExpression attributeValueParameter = Expression.Parameter(typeof(AttributeValue), "v");
                                            MemberExpression    idExpression            = Expression.Property(paramExpression, "Id");
                                            var attributeExpression = Attribute.Helper.GetAttributeValueExpression(attributeValues, attributeValueParameter, idExpression, attributeId.Value);

                                            LambdaExpression sortSelector = Expression.Lambda(attributeExpression, paramExpression);
                                            queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                        }
                                        else
                                        {
                                            throw new Exception(string.Format("The database context for type {0} does not support RockContext attribute value queries.", entityTypeCache.FriendlyName));
                                        }
                                    }
                                }

                                orderByMethod = "ThenBy";
                            }
                        }

                        // reassemble the queryable with the sort expressions
                        queryResult = queryResult.Provider.CreateQuery(queryResultExpression) as IQueryable <IEntity>;

                        if (parms.GetValueOrNull("count").AsBoolean())
                        {
                            int countResult = queryResult.Count();
                            context.Scopes.Last()["count"] = countResult;
                        }
                        else
                        {
                            // run security check on each result
                            var items        = queryResult.ToList();
                            var itemsSecured = new List <IEntity>();

                            Person person = GetCurrentPerson(context);

                            foreach (IEntity item in items)
                            {
                                ISecured itemSecured = item as ISecured;
                                if (itemSecured == null || itemSecured.IsAuthorized(Authorization.VIEW, person))
                                {
                                    itemsSecured.Add(item);
                                }
                            }

                            queryResult = itemsSecured.AsQueryable();

                            // offset
                            if (parms.Any(p => p.Key == "offset"))
                            {
                                queryResult = queryResult.Skip(parms["offset"].AsInteger());
                            }

                            // limit, default to 1000
                            if (parms.Any(p => p.Key == "limit"))
                            {
                                queryResult = queryResult.Take(parms["limit"].AsInteger());
                            }
                            else
                            {
                                queryResult = queryResult.Take(1000);
                            }

                            // check to ensure we had some form of filter (otherwise we'll return all results in the table)
                            if (!hasFilter)
                            {
                                throw new Exception("Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.");
                            }

                            var resultList = queryResult.ToList();

                            // if there is only one item to return set an alternative non-array based variable
                            if (resultList.Count == 1)
                            {
                                context.Scopes.Last()[_entityName] = resultList.FirstOrDefault();
                            }

                            context.Scopes.Last()[parms["iterator"]] = resultList;
                        }
                    }
                }
            }
            else
            {
                result.Write(string.Format("Could not find a model for {0}.", _entityName));
                base.Render(context, result);
            }

            base.Render(context, result);
        }
        private void SetCampus()
        {
            RockContext rockContext = new RockContext();
            Campus      campus      = null;

            // get device
            string        deviceIp      = GetIPAddress();
            DeviceService deviceService = new DeviceService(rockContext);

            var deviceQry = deviceService.Queryable("Location")
                            .Where(d => d.IPAddress == deviceIp);

            // add device type filter
            if (!string.IsNullOrWhiteSpace(GetAttributeValue("DeviceType")))
            {
                Guid givingKioskGuid = new Guid(GetAttributeValue("DeviceType"));
                deviceQry = deviceQry.Where(d => d.DeviceType.Guid == givingKioskGuid);
            }

            var device = deviceQry.FirstOrDefault();

            if (device != null)
            {
                if (device.Locations.Count > 0)
                {
                    campus = new CampusService(new RockContext()).Get(device.Locations.First().CampusId.Value);

                    // set the context
                    if (campus != null)
                    {
                        var campusEntityType = EntityTypeCache.Read("Rock.Model.Campus");
                        var currentCampus    = RockPage.GetCurrentContext(campusEntityType) as Campus;

                        if (currentCampus == null || currentCampus.Id != campus.Id)
                        {
                            bool pageScope = GetAttributeValue("ContextScope") == "Page";
                            RockPage.SetContextCookie(campus, pageScope, true);
                        }
                    }
                }
            }

            // set display output
            var mergeFields = new Dictionary <string, object>();

            mergeFields.Add("ClientIp", deviceIp);
            mergeFields.Add("Device", device);
            mergeFields.Add("Campus", campus);
            mergeFields.Add("CurrentPerson", CurrentPerson);

            var globalAttributeFields = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields(CurrentPerson);

            globalAttributeFields.ToList().ForEach(d => mergeFields.Add(d.Key, d.Value));

            lOutput.Text = GetAttributeValue("DisplayLava").ResolveMergeFields(mergeFields);

            // show debug info
            if (GetAttributeValue("EnableDebug").AsBoolean() && IsUserAuthorized(Authorization.EDIT))
            {
                lDebug.Visible = true;
                lDebug.Text    = mergeFields.lavaDebugInfo();
            }
        }
Exemple #9
0
        /// <summary>
        /// Handles the ItemDataBound event of the rptRecipients control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RepeaterItemEventArgs" /> instance containing the event data.</param>
        protected void rptRecipients_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            // Hide the remove button for any recipient that is not pending.
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                var recipient = e.Item.DataItem as Recipient;
                if (recipient != null)
                {
                    var lRecipientName = e.Item.FindControl("lRecipientName") as Literal;
                    if (lRecipientName != null)
                    {
                        string textClass   = string.Empty;
                        string textTooltip = string.Empty;

                        if (recipient.IsDeceased)
                        {
                            textClass   = "text-danger";
                            textTooltip = "Deceased";
                        }
                        else
                        {
                            if (MediumEntityTypeId == EntityTypeCache.Read("Rock.Communication.Medium.Email").Id)
                            {
                                if (string.IsNullOrWhiteSpace(recipient.Email))
                                {
                                    textClass   = "text-danger";
                                    textTooltip = "No Email." + recipient.EmailNote;
                                }
                                else if (!recipient.IsEmailActive)
                                {
                                    // if email is not active, show reason why as tooltip
                                    textClass   = "text-danger";
                                    textTooltip = "Email is Inactive. " + recipient.EmailNote;
                                }
                                else
                                {
                                    // Email is active
                                    if (recipient.EmailPreference != EmailPreference.EmailAllowed)
                                    {
                                        textTooltip = Recipient.PreferenceMessage(recipient);

                                        if (recipient.EmailPreference == EmailPreference.NoMassEmails)
                                        {
                                            textClass = "js-no-bulk-email";
                                            var mediumData = MediumData;
                                            if (cbBulk.Checked)
                                            {
                                                // This is a bulk email and user does not want bulk emails
                                                textClass += " text-danger";
                                            }
                                        }
                                        else
                                        {
                                            // Email preference is 'Do Not Email'
                                            textClass = "text-danger";
                                        }
                                    }
                                }
                            }
                            else if (MediumEntityTypeId == EntityTypeCache.Read("Rock.Communication.Medium.Sms").Id)
                            {
                                if (!recipient.HasSmsNumber)
                                {
                                    // No SMS Number
                                    textClass   = "text-danger";
                                    textTooltip = "No phone number with SMS enabled.";
                                }
                            }
                        }

                        lRecipientName.Text = String.Format("<span data-toggle=\"tooltip\" data-placement=\"top\" title=\"{0}\" class=\"{1}\">{2}</span>",
                                                            textTooltip, textClass, recipient.PersonName);
                    }
                }
            }
        }
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid()
        {
            if (_entity != null)
            {
                var entityTypeCache = EntityTypeCache.Read(_entity.GetType(), false);
                if (entityTypeCache != null)
                {
                    var qry = new HistoryService(new RockContext()).Queryable("CreatedByPersonAlias.Person")
                              .Where(h =>
                                     (h.EntityTypeId == entityTypeCache.Id && h.EntityId == _entity.Id));

                    int?categoryId = gfSettings.GetUserPreference("Category").AsIntegerOrNull();
                    if (categoryId.HasValue)
                    {
                        qry = qry.Where(a => a.CategoryId == categoryId.Value);
                    }

                    string summary = gfSettings.GetUserPreference("Summary Contains");
                    if (!string.IsNullOrWhiteSpace(summary))
                    {
                        qry = qry.Where(h => h.Summary.Contains(summary));
                    }

                    int personId = int.MinValue;
                    if (int.TryParse(gfSettings.GetUserPreference("Who"), out personId))
                    {
                        qry = qry.Where(h => h.CreatedByPersonAlias.PersonId == personId);
                    }

                    var drp = new DateRangePicker();
                    drp.DelimitedValues = gfSettings.GetUserPreference("Date Range");
                    if (drp.LowerValue.HasValue)
                    {
                        qry = qry.Where(h => h.CreatedDateTime >= drp.LowerValue.Value);
                    }
                    if (drp.UpperValue.HasValue)
                    {
                        DateTime upperDate = drp.UpperValue.Value.Date.AddDays(1);
                        qry = qry.Where(h => h.CreatedDateTime < upperDate);
                    }

                    SortProperty sortProperty = gHistory.SortProperty;
                    if (sortProperty != null)
                    {
                        qry = qry.Sort(sortProperty);
                    }
                    else
                    {
                        qry = qry.OrderByDescending(t => t.CreatedDateTime);
                    }

                    // Combine history records that were saved at the same time
                    var histories = new List <History>();
                    foreach (var history in qry)
                    {
                        var existingHistory = histories
                                              .Where(h =>
                                                     h.CreatedByPersonAliasId == history.CreatedByPersonAliasId &&
                                                     h.CreatedDateTime == history.CreatedDateTime &&
                                                     h.EntityTypeId == history.EntityTypeId &&
                                                     h.EntityId == history.EntityId &&
                                                     h.CategoryId == history.CategoryId &&
                                                     h.RelatedEntityTypeId == history.RelatedEntityTypeId &&
                                                     h.RelatedEntityId == history.RelatedEntityId).FirstOrDefault();
                        if (existingHistory != null)
                        {
                            existingHistory.Summary += "<br/>" + history.Summary;
                        }
                        else
                        {
                            histories.Add(history);
                        }
                    }

                    gHistory.DataSource = histories.Select(h => new
                    {
                        Id                  = h.Id,
                        CategoryId          = h.CategoryId,
                        Category            = h.Category != null ? h.Category.Name : "",
                        EntityTypeId        = h.EntityTypeId,
                        EntityId            = h.EntityId,
                        Caption             = h.Caption ?? string.Empty,
                        Summary             = h.Summary,
                        RelatedEntityTypeId = h.RelatedEntityTypeId ?? 0,
                        RelatedEntityId     = h.RelatedEntityId ?? 0,
                        CreatedByPersonId   = h.CreatedByPersonAlias != null ? h.CreatedByPersonAlias.PersonId : 0,
                        PersonName          = h.CreatedByPersonAlias != null && h.CreatedByPersonAlias.Person != null ? h.CreatedByPersonAlias.Person.NickName + " " + h.CreatedByPersonAlias.Person.LastName : "",
                        CreatedDateTime     = h.CreatedDateTime
                    }).ToList();

                    gHistory.EntityTypeId = EntityTypeCache.Read <History>().Id;
                    gHistory.DataBind();
                }
            }
        }
        private void LoadContent()
        {
            var audienceGuid = GetAttributeValue("Audience").AsGuid();

            if (audienceGuid != Guid.Empty)
            {
                lMessages.Text = string.Empty;
                RockContext rockContext = new RockContext();

                // get event occurrences
                var qry = new EventItemOccurrenceService(rockContext).Queryable()
                          .Where(e => e.EventItem.EventItemAudiences.Any(a => a.DefinedValue.Guid == audienceGuid) && e.EventItem.IsActive);

                var campusFilter = new List <CampusCache>();

                // filter occurrences for campus (always include the "All Campuses" events)
                if (PageParameter("CampusId").IsNotNullOrWhiteSpace())
                {
                    var contextCampus = CampusCache.Get(PageParameter("CampusId").AsInteger());

                    if (contextCampus != null)
                    {
                        // If an EventItemOccurrence's CampusId is null, then the occurrence is an 'All Campuses' event occurrence, so include those
                        qry = qry.Where(e => e.CampusId == contextCampus.Id || !e.CampusId.HasValue);
                        campusFilter.Add(CampusCache.Get(contextCampus.Id));
                    }
                }
                else if (PageParameter("CampusGuid").IsNotNullOrWhiteSpace())
                {
                    var contextCampus = CampusCache.Get(PageParameter("CampusGuid").AsGuid());

                    if (contextCampus != null)
                    {
                        // If an EventItemOccurrence's CampusId is null, then the occurrence is an 'All Campuses' event occurrence, so include those
                        qry = qry.Where(e => e.CampusId == contextCampus.Id || !e.CampusId.HasValue);
                        campusFilter.Add(CampusCache.Get(contextCampus.Id));
                    }
                }
                else if (GetAttributeValue("UseCampusContext").AsBoolean())
                {
                    var campusEntityType = EntityTypeCache.Get("Rock.Model.Campus");
                    var contextCampus    = RockPage.GetCurrentContext(campusEntityType) as Campus;

                    if (contextCampus != null)
                    {
                        // If an EventItemOccurrence's CampusId is null, then the occurrence is an 'All Campuses' event occurrence, so include those
                        qry = qry.Where(e => e.CampusId == contextCampus.Id || !e.CampusId.HasValue);
                        campusFilter.Add(CampusCache.Get(contextCampus.Id));
                    }
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(GetAttributeValue("Campuses")))
                    {
                        var selectedCampusGuids = GetAttributeValue("Campuses").Split(',').AsGuidList();
                        campusFilter = selectedCampusGuids.Select(a => CampusCache.Get(a)).Where(a => a != null).ToList();
                        var selectedCampusIds = campusFilter.Select(a => a.Id);

                        // If an EventItemOccurrence's CampusId is null, then the occurrence is an 'All Campuses' event occurrence, so include those
                        qry = qry.Where(e => e.CampusId == null || selectedCampusIds.Contains(e.CampusId.Value));
                    }
                }

                // filter by calendar
                var calendarGuid = GetAttributeValue("Calendar").AsGuid();

                if (calendarGuid != Guid.Empty)
                {
                    qry = qry.Where(e => e.EventItem.EventCalendarItems.Any(c => c.EventCalendar.Guid == calendarGuid));
                }

                // retrieve occurrences
                var itemOccurrences = qry.ToList();

                // filter by date range
                var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues(GetAttributeValue("DateRange"));
                if (dateRange.Start != null && dateRange.End != null)
                {
                    itemOccurrences.RemoveAll(o => o.GetStartTimes(dateRange.Start.Value, dateRange.End.Value).Count() == 0);
                }
                else
                {
                    // default show all future
                    itemOccurrences.RemoveAll(o => o.GetStartTimes(RockDateTime.Now, RockDateTime.Now.AddDays(365)).Count() == 0);
                }

                // limit results
                int maxItems = GetAttributeValue("MaxOccurrences").AsInteger();
                itemOccurrences = itemOccurrences.OrderBy(i => i.NextStartDateTime).Take(maxItems).ToList();

                // make lava merge fields
                var mergeFields = new Dictionary <string, object>();

                var contextObjects = new Dictionary <string, object>();
                foreach (var contextEntityType in RockPage.GetContextEntityTypes())
                {
                    var contextEntity = RockPage.GetCurrentContext(contextEntityType);
                    if (contextEntity != null && contextEntity is ILavaRenderContext)
                    {
                        var type = Type.GetType(contextEntityType.AssemblyName ?? contextEntityType.Name);
                        if (type != null)
                        {
                            contextObjects.Add(type.Name, contextEntity);
                        }
                    }
                }

                if (contextObjects.Any())
                {
                    mergeFields.Add("Context", contextObjects);
                }

                mergeFields.Add("ListTitle", GetAttributeValue("ListTitle"));
                mergeFields.Add("EventDetailPage", LinkedPageRoute("EventDetailPage"));
                mergeFields.Add("RegistrationPage", LinkedPageRoute("RegistrationPage"));
                mergeFields.Add("EventItemOccurrences", itemOccurrences);

                mergeFields.Add("FilteredCampuses", campusFilter);
                mergeFields.Add("Audience", DefinedValueCache.Get(audienceGuid));

                if (calendarGuid != Guid.Empty)
                {
                    mergeFields.Add("Calendar", new EventCalendarService(rockContext).Get(calendarGuid));
                }

                lContent.Text = GetAttributeValue("LavaTemplate").ResolveMergeFields(mergeFields);
            }
            else
            {
                lMessages.Text = "<div class='alert alert-warning'>No audience is configured for this block.</div>";
            }
        }
Exemple #12
0
        /// <summary>
        /// Gets the merge object list for the current EntitySet
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="fetchCount">The fetch count.</param>
        /// <returns></returns>
        private List <object> GetMergeObjectList(RockContext rockContext, int?fetchCount = null)
        {
            int entitySetId      = hfEntitySetId.Value.AsInteger();
            var entitySetService = new EntitySetService(rockContext);
            var entitySet        = entitySetService.Get(entitySetId);
            Dictionary <int, object> mergeObjectsDictionary = new Dictionary <int, object>();

            // If this EntitySet contains IEntity Items, add those first
            if (entitySet.EntityTypeId.HasValue)
            {
                var qryEntity = entitySetService.GetEntityQuery(entitySetId);

                if (fetchCount.HasValue)
                {
                    qryEntity = qryEntity.Take(fetchCount.Value);
                }

                var  entityTypeCache         = EntityTypeCache.Read(entitySet.EntityTypeId.Value);
                bool isPersonEntityType      = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.PERSON.AsGuid();
                bool isGroupMemberEntityType = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid();
                bool combineFamilyMembers    = cbCombineFamilyMembers.Visible && cbCombineFamilyMembers.Checked;

                if ((isGroupMemberEntityType || isPersonEntityType) && combineFamilyMembers)
                {
                    IQueryable <IEntity> qryPersons;
                    if (isGroupMemberEntityType)
                    {
                        qryPersons = qryEntity.OfType <GroupMember>().Select(a => a.Person).Distinct();
                    }
                    else
                    {
                        qryPersons = qryEntity;
                    }

                    Guid familyGroupType       = Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid();
                    var  qryFamilyGroupMembers = new GroupMemberService(rockContext).Queryable()
                                                 .Where(a => a.Group.GroupType.Guid == familyGroupType)
                                                 .Where(a => qryPersons.Any(aa => aa.Id == a.PersonId));

                    var qryCombined = qryFamilyGroupMembers.Join(
                        qryPersons,
                        m => m.PersonId,
                        p => p.Id,
                        (m, p) => new { GroupMember = m, Person = p })
                                      .GroupBy(a => a.GroupMember.GroupId)
                                      .Select(x => new
                    {
                        GroupId = x.Key,
                        Persons = x.Select(xx => xx.Person).Distinct()
                    });

                    foreach (var combinedFamilyItem in qryCombined)
                    {
                        object mergeObject;

                        string commaPersonIds = combinedFamilyItem.Persons.Select(a => a.Id).Distinct().ToList().AsDelimited(",");

                        var primaryGroupPerson = combinedFamilyItem.Persons.FirstOrDefault() as Person;

                        if (mergeObjectsDictionary.ContainsKey(primaryGroupPerson.Id))
                        {
                            foreach (var person in combinedFamilyItem.Persons)
                            {
                                if (!mergeObjectsDictionary.ContainsKey(person.Id))
                                {
                                    primaryGroupPerson = person as Person;
                                    break;
                                }
                            }
                        }

                        // if we are combining from a GroupMemberEntityType list add the GroupMember attributes of the primary person in the combined list
                        if (isGroupMemberEntityType)
                        {
                            var groupMember = qryEntity.OfType <GroupMember>().Where(a => a.PersonId == primaryGroupPerson.Id).FirstOrDefault();
                            primaryGroupPerson.AdditionalLavaFields = primaryGroupPerson.AdditionalLavaFields ?? new Dictionary <string, object>();
                            if (groupMember != null)
                            {
                                primaryGroupPerson.AdditionalLavaFields.AddOrIgnore("GroupMember", groupMember);
                            }
                        }

                        if (combinedFamilyItem.Persons.Count() > 1)
                        {
                            var combinedPerson = primaryGroupPerson.ToJson().FromJsonOrNull <MergeTemplateCombinedPerson>();

                            var familyTitle = RockUdfHelper.ufnCrm_GetFamilyTitle(rockContext, null, combinedFamilyItem.GroupId, commaPersonIds, true);
                            combinedPerson.FullName = familyTitle;

                            var firstNameList = combinedFamilyItem.Persons.Select(a => (a as Person).FirstName).ToList();
                            var nickNameList  = combinedFamilyItem.Persons.Select(a => (a as Person).NickName).ToList();

                            combinedPerson.FirstName     = firstNameList.AsDelimited(", ", " & ");
                            combinedPerson.NickName      = nickNameList.AsDelimited(", ", " & ");
                            combinedPerson.LastName      = primaryGroupPerson.LastName;
                            combinedPerson.SuffixValueId = null;
                            combinedPerson.SuffixValue   = null;
                            mergeObject = combinedPerson;
                        }
                        else
                        {
                            mergeObject = primaryGroupPerson;
                        }

                        mergeObjectsDictionary.AddOrIgnore(primaryGroupPerson.Id, mergeObject);
                    }
                }
                else if (isGroupMemberEntityType)
                {
                    foreach (var groupMember in qryEntity.AsNoTracking().OfType <GroupMember>())
                    {
                        var person = groupMember.Person;
                        person.AdditionalLavaFields = new Dictionary <string, object>();
                        person.AdditionalLavaFields.Add("GroupMember", groupMember);
                        mergeObjectsDictionary.AddOrIgnore(groupMember.PersonId, person);
                    }
                }
                else
                {
                    foreach (var item in qryEntity.AsNoTracking())
                    {
                        mergeObjectsDictionary.AddOrIgnore(item.Id, item);
                    }
                }
            }

            var entitySetItemService = new EntitySetItemService(rockContext);

            string[] emptyJson = new string[] { string.Empty, "{}" };
            var      entitySetItemMergeValuesQry = entitySetItemService.GetByEntitySetId(entitySetId, true).Where(a => !emptyJson.Contains(a.AdditionalMergeValuesJson));

            if (fetchCount.HasValue)
            {
                entitySetItemMergeValuesQry = entitySetItemMergeValuesQry.Take(fetchCount.Value);
            }

            // the entityId to use for NonEntity objects
            int nonEntityId = 1;

            // now, add the additional MergeValues regardless of if the EntitySet contains IEntity items or just Non-IEntity items
            foreach (var additionalMergeValuesItem in entitySetItemMergeValuesQry.AsNoTracking())
            {
                object mergeObject;
                int    entityId;
                if (additionalMergeValuesItem.EntityId > 0)
                {
                    entityId = additionalMergeValuesItem.EntityId;
                }
                else
                {
                    // not pointing to an actual EntityId, so use the nonEntityId for ti
                    entityId = nonEntityId++;
                }

                if (mergeObjectsDictionary.ContainsKey(entityId))
                {
                    mergeObject = mergeObjectsDictionary[entityId];
                }
                else
                {
                    if (entitySet.EntityTypeId.HasValue)
                    {
                        // if already have real entities in our list, don't add additional items to the mergeObjectsDictionary
                        continue;
                    }

                    // non-Entity merge object, so just use Dictionary
                    mergeObject = new Dictionary <string, object>();
                    mergeObjectsDictionary.AddOrIgnore(entityId, mergeObject);
                }

                foreach (var additionalMergeValue in additionalMergeValuesItem.AdditionalMergeValues)
                {
                    if (mergeObject is IEntity)
                    {
                        // add the additional fields to AdditionalLavaFields
                        IEntity mergeEntity = (mergeObject as IEntity);
                        mergeEntity.AdditionalLavaFields = mergeEntity.AdditionalLavaFields ?? new Dictionary <string, object>();
                        object mergeValueObject = additionalMergeValue.Value;

                        // if the mergeValueObject is a JArray (JSON Object), convert it into an ExpandoObject or List<ExpandoObject> so that Lava will work on it
                        if (mergeValueObject is JArray)
                        {
                            var jsonOfObject = mergeValueObject.ToJson();
                            try
                            {
                                mergeValueObject = Rock.Lava.RockFilters.FromJSON(jsonOfObject);
                            }
                            catch (Exception ex)
                            {
                                LogException(new Exception("MergeTemplateEntry couldn't do a FromJSON", ex));
                            }
                        }

                        mergeEntity.AdditionalLavaFields.AddOrIgnore(additionalMergeValue.Key, mergeValueObject);
                    }
                    else if (mergeObject is IDictionary <string, object> )
                    {
                        // anonymous object with no fields yet
                        IDictionary <string, object> nonEntityObject = mergeObject as IDictionary <string, object>;
                        nonEntityObject.AddOrIgnore(additionalMergeValue.Key, additionalMergeValue.Value);
                    }
                    else
                    {
                        throw new Exception(string.Format("Unexpected MergeObject Type: {0}", mergeObject));
                    }
                }
            }

            var result = mergeObjectsDictionary.Select(a => a.Value);

            if (fetchCount.HasValue)
            {
                // make sure the result is limited to fetchCount (even though the above queries are also limited to fetch count)
                result = result.Take(fetchCount.Value);
            }

            return(result.ToList());
        }
        /// <summary>
        /// Adds the attribute columns.
        /// </summary>
        private void AddDynamicControls()
        {
            // Clear the filter controls
            phAttributeFilters.Controls.Clear();

            var deleteCol = gConnectionOpportunities.Columns.OfType <DeleteField>().FirstOrDefault();

            if (deleteCol != null)
            {
                gConnectionOpportunities.Columns.Remove(deleteCol);
            }

            var securityCol = gConnectionOpportunities.Columns.OfType <SecurityField>().FirstOrDefault();

            if (securityCol != null)
            {
                gConnectionOpportunities.Columns.Remove(securityCol);
            }

            // Remove attribute columns
            foreach (var column in gConnectionOpportunities.Columns.OfType <AttributeField>().ToList())
            {
                gConnectionOpportunities.Columns.Remove(column);
            }

            if (AvailableAttributes != null)
            {
                foreach (var attribute in AvailableAttributes)
                {
                    var control = attribute.FieldType.Field.FilterControl(attribute.QualifierValues, "filter_" + attribute.Id.ToString(), false, Rock.Reporting.FilterMode.SimpleFilter);
                    if (control != null)
                    {
                        if (control is IRockControl)
                        {
                            var rockControl = (IRockControl)control;
                            rockControl.Label = attribute.Name;
                            rockControl.Help  = attribute.Description;
                            phAttributeFilters.Controls.Add(control);
                        }
                        else
                        {
                            var wrapper = new RockControlWrapper();
                            wrapper.ID    = control.ID + "_wrapper";
                            wrapper.Label = attribute.Name;
                            wrapper.Controls.Add(control);
                            phAttributeFilters.Controls.Add(wrapper);
                        }

                        string savedValue = rFilter.GetUserPreference(MakeKeyUniqueToConnectionType(attribute.Key));
                        if (!string.IsNullOrWhiteSpace(savedValue))
                        {
                            try
                            {
                                var values = JsonConvert.DeserializeObject <List <string> >(savedValue);
                                attribute.FieldType.Field.SetFilterValues(control, attribute.QualifierValues, values);
                            }
                            catch
                            {
                            }
                        }
                    }

                    string dataFieldExpression = attribute.Key;
                    bool   columnExists        = gConnectionOpportunities.Columns.OfType <AttributeField>().FirstOrDefault(a => a.DataField.Equals(dataFieldExpression)) != null;
                    if (!columnExists)
                    {
                        AttributeField boundField = new AttributeField();
                        boundField.DataField   = dataFieldExpression;
                        boundField.AttributeId = attribute.Id;
                        boundField.HeaderText  = attribute.Name;

                        var attributeCache = Rock.Web.Cache.AttributeCache.Get(attribute.Id);
                        if (attributeCache != null)
                        {
                            boundField.ItemStyle.HorizontalAlign = attributeCache.FieldType.Field.AlignValue;
                        }

                        gConnectionOpportunities.Columns.Add(boundField);
                    }
                }
            }

            securityCol              = new SecurityField();
            securityCol.TitleField   = "Name";
            securityCol.EntityTypeId = EntityTypeCache.Get(typeof(Rock.Model.ConnectionOpportunity)).Id;
            gConnectionOpportunities.Columns.Add(securityCol);

            deleteCol = new DeleteField();
            gConnectionOpportunities.Columns.Add(deleteCol);
            deleteCol.Click += DeleteConnectionOpportunity_Click;
        }
Exemple #14
0
        /// <summary>
        /// Registers any block types that are not currently registered in Rock.
        /// </summary>
        /// <param name="physWebAppPath">A <see cref="System.String" /> containing the physical path to Rock on the server.</param>
        /// <param name="page">The <see cref="System.Web.UI.Page" />.</param>
        /// <param name="refreshAll">if set to <c>true</c> will refresh name, category, and description for all block types (not just the new ones)</param>
        public static void RegisterBlockTypes(string physWebAppPath, System.Web.UI.Page page, bool refreshAll = false)
        {
            // Dictionary for block types.  Key is path, value is friendly name
            var list = new Dictionary <string, string>();

            // Find all the blocks in the Blocks folder...
            FindAllBlocksInPath(physWebAppPath, list, "Blocks");

            // Now do the exact same thing for the Plugins folder...
            FindAllBlocksInPath(physWebAppPath, list, "Plugins");

            // Get a list of the BlockTypes already registered (via the path)
            var registeredPaths = new List <string>();

            using (var rockContext = new RockContext())
            {
                registeredPaths = new BlockTypeService(rockContext)
                                  .Queryable().AsNoTracking()
                                  .Select(b => b.Path)
                                  .ToList();
            }

            // Get the Block Entity Type
            int?blockEntityTypeId = EntityTypeCache.Get(typeof(Block)).Id;

            // for each BlockType
            foreach (string path in list.Keys)
            {
                if (refreshAll || !registeredPaths.Any(b => b.Equals(path, StringComparison.OrdinalIgnoreCase)))
                {
                    // Attempt to load the control
                    try
                    {
                        var blockCompiledType = System.Web.Compilation.BuildManager.GetCompiledType(path);
                        if (blockCompiledType != null)
                        {
                            using (var rockContext = new RockContext())
                            {
                                var blockTypeService = new BlockTypeService(rockContext);
                                var blockType        = blockTypeService.Queryable()
                                                       .FirstOrDefault(b => b.Path == path);
                                if (blockType == null)
                                {
                                    // Create new BlockType record and save it
                                    blockType      = new BlockType();
                                    blockType.Path = path;
                                    blockTypeService.Add(blockType);
                                }

                                Type controlType = blockCompiledType;

                                // Update Name, Category, and Description based on block's attribute definitions
                                blockType.Name = Reflection.GetDisplayName(controlType) ?? string.Empty;
                                if (string.IsNullOrWhiteSpace(blockType.Name))
                                {
                                    // Parse the relative path to get the name
                                    var nameParts = list[path].Split('/');
                                    for (int i = 0; i < nameParts.Length; i++)
                                    {
                                        if (i == nameParts.Length - 1)
                                        {
                                            nameParts[i] = Path.GetFileNameWithoutExtension(nameParts[i]);
                                        }
                                        nameParts[i] = nameParts[i].SplitCase();
                                    }
                                    blockType.Name = string.Join(" > ", nameParts);
                                }
                                if (blockType.Name.Length > 100)
                                {
                                    blockType.Name = blockType.Name.Truncate(100);
                                }
                                blockType.Category    = Rock.Reflection.GetCategory(controlType) ?? string.Empty;
                                blockType.Description = Rock.Reflection.GetDescription(controlType) ?? string.Empty;

                                rockContext.SaveChanges();

                                // Update the attributes used by the block
                                Rock.Attribute.Helper.UpdateAttributes(controlType, blockEntityTypeId, "BlockTypeId", blockType.Id.ToString(), rockContext);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine($"RegisterBlockTypes failed for {path} with exception: {ex.Message}");
                        ExceptionLogService.LogException(new Exception(string.Format("Problem processing block with path '{0}'.", path), ex), null);
                    }
                }
            }
        }
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid()
        {
            var deviceService = new DeviceService(new RockContext());
            var sortProperty  = gDevice.SortProperty;

            gDevice.EntityTypeId = EntityTypeCache.Read <Device>().Id;

            var queryable = deviceService.Queryable().Select(a =>
                                                             new
            {
                a.Id,
                a.Name,
                DeviceTypeName = a.DeviceType.Value,
                a.IPAddress,
                a.PrintToOverride,
                a.PrintFrom,
                PrinterDeviceName = a.PrinterDevice.Name,
                a.PrinterDeviceId,
                a.DeviceTypeValueId
            });

            string name = fDevice.GetUserPreference("Name");

            if (!string.IsNullOrWhiteSpace(name))
            {
                queryable = queryable.Where(d => d.Name.Contains(name));
            }

            int?deviceTypeId = fDevice.GetUserPreference("Device Type").AsIntegerOrNull();

            if (deviceTypeId.HasValue)
            {
                queryable = queryable.Where(d => d.DeviceTypeValueId == deviceTypeId.Value);
            }

            string ipAddress = fDevice.GetUserPreference("IP Address");

            if (!string.IsNullOrWhiteSpace(ipAddress))
            {
                queryable = queryable.Where(d => d.IPAddress.Contains(ipAddress));
            }

            if (!string.IsNullOrWhiteSpace(fDevice.GetUserPreference("Print To")))
            {
                PrintTo printTo = (PrintTo)System.Enum.Parse(typeof(PrintTo), fDevice.GetUserPreference("Print To"));;
                queryable = queryable.Where(d => d.PrintToOverride == printTo);
            }

            int?printerId = fDevice.GetUserPreference("Printer").AsIntegerOrNull();

            if (printerId.HasValue)
            {
                queryable = queryable.Where(d => d.PrinterDeviceId == printerId);
            }

            if (!string.IsNullOrWhiteSpace(fDevice.GetUserPreference("Print From")))
            {
                PrintFrom printFrom = (PrintFrom)System.Enum.Parse(typeof(PrintFrom), fDevice.GetUserPreference("Print From"));;
                queryable = queryable.Where(d => d.PrintFrom == printFrom);
            }

            if (sortProperty != null)
            {
                gDevice.DataSource = queryable.Sort(sortProperty).ToList();
            }
            else
            {
                gDevice.DataSource = queryable.OrderBy(d => d.Name).ToList();
            }

            gDevice.EntityTypeId = EntityTypeCache.Read <Rock.Model.Device>().Id;
            gDevice.DataBind();
        }
Exemple #16
0
        /// <summary>
        /// Shows the medium.
        /// </summary>
        private MediumControl LoadMediumControl(bool setData)
        {
            if (setData)
            {
                phContent.Controls.Clear();
            }

            // The component to load control for
            MediumComponent component  = null;
            string          mediumName = string.Empty;

            // Get the current medium type
            EntityTypeCache entityType = null;

            if (MediumEntityTypeId.HasValue)
            {
                entityType = EntityTypeCache.Read(MediumEntityTypeId.Value);
            }

            foreach (var serviceEntry in MediumContainer.Instance.Components)
            {
                var mediumComponent = serviceEntry.Value;

                // Default to first component
                if (component == null)
                {
                    component  = mediumComponent.Value;
                    mediumName = mediumComponent.Metadata.ComponentName + " ";
                }

                // If invalid entity type, exit (and use first component found)
                if (entityType == null)
                {
                    break;
                }
                else if (entityType.Id == mediumComponent.Value.EntityType.Id)
                {
                    component  = mediumComponent.Value;
                    mediumName = mediumComponent.Metadata.ComponentName + " ";
                    break;
                }
            }

            if (component != null)
            {
                var mediumControl = component.GetControl(!_fullMode);
                mediumControl.ID                    = "commControl";
                mediumControl.IsTemplate            = false;
                mediumControl.AdditionalMergeFields = this.AdditionalMergeFields.ToList();
                mediumControl.ValidationGroup       = btnSubmit.ValidationGroup;
                phContent.Controls.Add(mediumControl);

                if (setData)
                {
                    mediumControl.MediumData = MediumData;
                }

                // Set the medium in case it wasn't already set or the previous component type was not found
                MediumEntityTypeId = component.EntityType.Id;

                if (component.Transport == null || !component.Transport.IsActive)
                {
                    nbInvalidTransport.Text    = string.Format("The {0}medium does not have an active transport configured. The communication will not be delivered until the transport is configured correctly.", mediumName);
                    nbInvalidTransport.Visible = true;
                }
                else
                {
                    nbInvalidTransport.Visible = false;
                }

                cbBulk.Visible = _fullMode && component.SupportsBulkCommunication;

                return(mediumControl);
            }

            return(null);
        }
        /// <summary>
        /// Job that will sync groups.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            // Get the job setting(s)
            JobDataMap dataMap = context.JobDetail.JobDataMap;
            bool       requirePasswordReset = dataMap.GetBoolean("RequirePasswordReset");
            var        commandTimeout       = dataMap.GetString("CommandTimeout").AsIntegerOrNull() ?? 180;

            // Counters for displaying results
            int    groupsSynced  = 0;
            int    groupsChanged = 0;
            string groupName     = string.Empty;
            string dataViewName  = string.Empty;
            var    errors        = new List <string>();

            try
            {
                // get groups set to sync
                var activeSyncIds = new List <int>();
                using (var rockContext = new RockContext())
                {
                    // Get groups that are not archived and are still active.
                    activeSyncIds = new GroupSyncService(rockContext)
                                    .Queryable().AsNoTracking()
                                    .Where(x => !x.Group.IsArchived && x.Group.IsActive)
                                    .Select(x => x.Id)
                                    .ToList();
                }

                foreach (var syncId in activeSyncIds)
                {
                    bool hasSyncChanged = false;

                    // Use a fresh rockContext per sync so that ChangeTracker doesn't get bogged down
                    using (var rockContext = new RockContext())
                    {
                        // increase the timeout just in case the data view source is slow
                        rockContext.Database.CommandTimeout = commandTimeout;
                        rockContext.SourceOfChange          = "Group Sync";

                        // Get the Sync
                        var sync = new GroupSyncService(rockContext)
                                   .Queryable().AsNoTracking()
                                   .FirstOrDefault(s => s.Id == syncId);

                        // Ensure that the group's Sync Data View is a person data view
                        if (sync != null && sync.SyncDataView.EntityTypeId == EntityTypeCache.Get(typeof(Person)).Id)
                        {
                            List <string> syncErrors = new List <string>();

                            dataViewName = sync.SyncDataView.Name;
                            groupName    = sync.Group.Name;

                            // Get the person id's from the data view (source)
                            var personService   = new PersonService(rockContext);
                            var sourcePersonIds = sync.SyncDataView.GetQuery(null, rockContext, commandTimeout, out syncErrors)
                                                  .Select(q => q.Id).ToList();

                            // If any error occurred trying get the 'where expression' from the sync-data-view,
                            // just skip trying to sync that particular group's Sync Data View for now.
                            if (syncErrors.Count > 0)
                            {
                                errors.AddRange(syncErrors);
                                ExceptionLogService.LogException(new Exception(string.Format("An error occurred while trying to GroupSync group '{0}' and data view '{1}' so the sync was skipped. Error: {2}", groupName, dataViewName, String.Join(",", syncErrors))));
                                continue;
                            }

                            // Get the person id's in the group (target) for the role being synced.
                            // Note: targetPersonIds must include archived group members
                            // so we don't try to delete anyone who's already archived, and
                            // it must include deceased members so we can remove them if they
                            // are no longer in the data view.
                            var targetPersonIds = new GroupMemberService(rockContext)
                                                  .Queryable(true, true).AsNoTracking()
                                                  .Where(gm => gm.GroupId == sync.GroupId)
                                                  .Where(gm => gm.GroupRoleId == sync.GroupTypeRoleId)
                                                  .Select(gm => new {
                                PersonId   = gm.PersonId,
                                IsArchived = gm.IsArchived
                            })
                                                  .ToList();

                            // Delete people from the group/role that are no longer in the data view --
                            // but not the ones that are already archived.
                            foreach (var targetPerson in targetPersonIds.Where(t => !sourcePersonIds.Contains(t.PersonId) && t.IsArchived != true))
                            {
                                try
                                {
                                    // Use a new context to limit the amount of change-tracking required
                                    using (var groupMemberContext = new RockContext())
                                    {
                                        // Delete the records for that person's group and role
                                        var groupMemberService = new GroupMemberService(groupMemberContext);
                                        foreach (var groupMember in groupMemberService
                                                 .Queryable(true, true)
                                                 .Where(m =>
                                                        m.GroupId == sync.GroupId &&
                                                        m.GroupRoleId == sync.GroupTypeRoleId &&
                                                        m.PersonId == targetPerson.PersonId)
                                                 .ToList())
                                        {
                                            groupMemberService.Delete(groupMember);
                                        }

                                        groupMemberContext.SaveChanges();

                                        // If the Group has an exit email, and person has an email address, send them the exit email
                                        if (sync.ExitSystemEmail != null)
                                        {
                                            var person = new PersonService(groupMemberContext).Get(targetPerson.PersonId);
                                            if (person.Email.IsNotNullOrWhiteSpace())
                                            {
                                                // Send the exit email
                                                var mergeFields = new Dictionary <string, object>();
                                                mergeFields.Add("Group", sync.Group);
                                                mergeFields.Add("Person", person);
                                                var emailMessage = new RockEmailMessage(sync.ExitSystemEmail);
                                                emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields));
                                                var emailErrors = new List <string>();
                                                emailMessage.Send(out emailErrors);
                                                errors.AddRange(emailErrors);
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    ExceptionLogService.LogException(ex);
                                    continue;
                                }

                                hasSyncChanged = true;
                            }

                            // Now find all the people in the source list who are NOT already in the target list
                            // or in the target list as archived (so we can restore them).
                            foreach (var personId in sourcePersonIds.Where(s => !targetPersonIds.Any(t => t.PersonId == s) ||
                                                                           targetPersonIds.Any(t => t.PersonId == s && t.IsArchived)))
                            {
                                try
                                {
                                    // Use a new context to limit the amount of change-tracking required
                                    using (var groupMemberContext = new RockContext())
                                    {
                                        var groupMemberService = new GroupMemberService(groupMemberContext);

                                        // If this person is currently archived...
                                        if (targetPersonIds.Any(t => t.PersonId == personId && t.IsArchived == true))
                                        {
                                            // ...then we'll just restore them;

                                            // NOTE: AddOrRestoreGroupMember will find the exact group member record and
                                            // sets their IsArchived back to false.
                                            var newGroupMember = groupMemberService.AddOrRestoreGroupMember(sync.Group, personId, sync.GroupTypeRoleId);
                                            newGroupMember.GroupMemberStatus = GroupMemberStatus.Active;
                                            groupMemberContext.SaveChanges();
                                        }
                                        else
                                        {
                                            // ...otherwise we will add a new person to the group with the role specified in the sync.
                                            var newGroupMember = new GroupMember {
                                                Id = 0
                                            };
                                            newGroupMember.PersonId          = personId;
                                            newGroupMember.GroupId           = sync.GroupId;
                                            newGroupMember.GroupMemberStatus = GroupMemberStatus.Active;
                                            newGroupMember.GroupRoleId       = sync.GroupTypeRoleId;

                                            if (newGroupMember.IsValidGroupMember(groupMemberContext))
                                            {
                                                groupMemberService.Add(newGroupMember);
                                                groupMemberContext.SaveChanges();
                                            }
                                            else
                                            {
                                                // Validation errors will get added to the ValidationResults collection. Add those results to the log and then move on to the next person.
                                                var ex = new GroupMemberValidationException(string.Join(",", newGroupMember.ValidationResults.Select(r => r.ErrorMessage).ToArray()));
                                                ExceptionLogService.LogException(ex);
                                                continue;
                                            }
                                        }

                                        // If the Group has a welcome email, and person has an email address, send them the welcome email and possibly create a login
                                        if (sync.WelcomeSystemEmail != null)
                                        {
                                            var person = new PersonService(groupMemberContext).Get(personId);
                                            if (person.Email.IsNotNullOrWhiteSpace())
                                            {
                                                // If the group is configured to add a user account for anyone added to the group, and person does not yet have an
                                                // account, add one for them.
                                                string newPassword = string.Empty;
                                                bool   createLogin = sync.AddUserAccountsDuringSync;

                                                // Only create a login if requested, no logins exist and we have enough information to generate a user name.
                                                if (createLogin && !person.Users.Any() && !string.IsNullOrWhiteSpace(person.NickName) && !string.IsNullOrWhiteSpace(person.LastName))
                                                {
                                                    newPassword = System.Web.Security.Membership.GeneratePassword(9, 1);
                                                    string username = Rock.Security.Authentication.Database.GenerateUsername(person.NickName, person.LastName);

                                                    UserLogin login = UserLoginService.Create(
                                                        groupMemberContext,
                                                        person,
                                                        AuthenticationServiceType.Internal,
                                                        EntityTypeCache.Get(Rock.SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid()).Id,
                                                        username,
                                                        newPassword,
                                                        true,
                                                        requirePasswordReset);
                                                }

                                                // Send the welcome email
                                                var mergeFields = new Dictionary <string, object>();
                                                mergeFields.Add("Group", sync.Group);
                                                mergeFields.Add("Person", person);
                                                mergeFields.Add("NewPassword", newPassword);
                                                mergeFields.Add("CreateLogin", createLogin);
                                                var emailMessage = new RockEmailMessage(sync.WelcomeSystemEmail);
                                                emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields));
                                                var emailErrors = new List <string>();
                                                emailMessage.Send(out emailErrors);
                                                errors.AddRange(emailErrors);
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    ExceptionLogService.LogException(ex);
                                    continue;
                                }

                                hasSyncChanged = true;
                            }

                            // Increment Groups Changed Counter (if people were deleted or added to the group)
                            if (hasSyncChanged)
                            {
                                groupsChanged++;
                            }

                            // Increment the Groups Synced Counter
                            groupsSynced++;
                        }
                    }
                }

                // Format the result message
                var resultMessage = string.Empty;
                if (groupsSynced == 0)
                {
                    resultMessage = "No groups to sync";
                }
                else if (groupsSynced == 1)
                {
                    resultMessage = "1 group was synced";
                }
                else
                {
                    resultMessage = string.Format("{0} groups were synced", groupsSynced);
                }

                resultMessage += string.Format(" and {0} groups were changed", groupsChanged);

                if (errors.Any())
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine();
                    sb.Append("Errors: ");
                    errors.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                    string errorMessage = sb.ToString();
                    resultMessage += errorMessage;
                    throw new Exception(errorMessage);
                }

                context.Result = resultMessage;
            }
            catch (System.Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
                throw;
            }
        }
Exemple #18
0
        /// <summary>
        /// Posts the save changes.
        /// </summary>
        /// <param name="dbContext">The database context.</param>
        public override void PostSaveChanges(Data.DbContext dbContext)
        {
            int?historyEntityId = (HistoryEntityId.HasValue && HistoryEntityId.Value > 0) ? HistoryEntityId.Value : this.EntityId;
            var rockContext     = dbContext as RockContext;

            if (HistoryChanges != null && HistoryChanges.Any() && HistoryEntityTypeId.HasValue && historyEntityId.HasValue)
            {
                if (HistoryEntityTypeId.Value == EntityTypeCache.Get(typeof(Person)).Id)
                {
                    HistoryService.SaveChanges(rockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), historyEntityId.Value, HistoryChanges, string.Empty, typeof(Attribute), AttributeId, true, this.ModifiedByPersonAliasId, dbContext.SourceOfChange);
                }
                else
                {
                    HistoryService.SaveChanges(rockContext, typeof(Group), Rock.SystemGuid.Category.HISTORY_GROUP_CHANGES.AsGuid(), historyEntityId.Value, HistoryChanges, string.Empty, typeof(Attribute), AttributeId, true, this.ModifiedByPersonAliasId, dbContext.SourceOfChange);
                }
            }

            if (this.PostSaveAttributeValueHistoryCurrent)
            {
                var attributeValueHistoricalService            = new AttributeValueHistoricalService(rockContext);
                var attributeValueHistoricalPreviousCurrentRow = attributeValueHistoricalService.Queryable().Where(a => a.AttributeValueId == this.Id && a.CurrentRowIndicator == true).FirstOrDefault();
                var saveChangesDateTime = RockDateTime.Now;

                if (attributeValueHistoricalPreviousCurrentRow != null)
                {
                    attributeValueHistoricalPreviousCurrentRow.CurrentRowIndicator = false;
                    attributeValueHistoricalPreviousCurrentRow.ExpireDateTime      = saveChangesDateTime;
                }

                var attributeValueHistoricalCurrent = AttributeValueHistorical.CreateCurrentRowFromAttributeValue(this, saveChangesDateTime);

                attributeValueHistoricalService.Add(attributeValueHistoricalCurrent);
                rockContext.SaveChanges();
            }

            // If this a Person Attribute, Update the ModifiedDateTime on the Person that this AttributeValue is associated with
            if (this.EntityId.HasValue && AttributeCache.Get(this.AttributeId)?.EntityTypeId == EntityTypeCache.Get <Rock.Model.Person>().Id)
            {
                var currentDateTime    = RockDateTime.Now;
                int personId           = this.EntityId.Value;
                var qryPersonsToUpdate = new PersonService(rockContext).Queryable(true, true).Where(a => a.Id == personId);
                rockContext.BulkUpdate(qryPersonsToUpdate, p => new Person {
                    ModifiedDateTime = currentDateTime, ModifiedByPersonAliasId = this.ModifiedByPersonAliasId
                });
            }

            base.PostSaveChanges(dbContext);
        }
Exemple #19
0
        /// <summary>
        /// Parses the where.
        /// </summary>
        /// <param name="whereClause">The where clause.</param>
        /// <param name="type">The type.</param>
        /// <param name="service">The service.</param>
        /// <param name="parmExpression">The parm expression.</param>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="entityTypeCache">The entity type cache.</param>
        /// <returns></returns>
        private Expression ParseWhere(string whereClause, Type type, IService service, ParameterExpression parmExpression, Type entityType, EntityTypeCache entityTypeCache)
        {
            Expression returnExpression = null;

            // find locations of and/or's
            var expressionComponents = Regex.Split(whereClause, @"(\|\||&&)");

            var currentExpressionComparisonType = ExpressionComparisonType.And;

            foreach (var component in expressionComponents)
            {
                if (component == "||")
                {
                    currentExpressionComparisonType = ExpressionComparisonType.Or;
                    continue;
                }

                if (component == "&&")
                {
                    currentExpressionComparisonType = ExpressionComparisonType.And;
                    continue;
                }

                // parse the part to get the expression
                string regexPattern    = @"([a-zA-Z]+)|(==|<=|>=|<|!=|\^=|\*=|\*!|_=|_!|>|\$=|#=)|("".*""|\d+)";
                var    expressionParts = Regex.Matches(component, regexPattern)
                                         .Cast <Match>()
                                         .Select(m => m.Value)
                                         .ToList();

                if (expressionParts.Count == 3)
                {
                    var property     = expressionParts[0];
                    var operatorType = expressionParts[1];
                    var value        = expressionParts[2].Replace("\"", "");

                    List <string> selectionParms = new List <string>();
                    selectionParms.Add(PropertyComparisonConversion(operatorType).ToString());
                    selectionParms.Add(value);
                    selectionParms.Add(property);

                    Expression expression = null;

                    if (entityType.GetProperty(property) != null)
                    {
                        var entityProperty = entityType.GetProperty(property);
                        expression = ExpressionHelper.PropertyFilterExpression(selectionParms, parmExpression, property, entityProperty.PropertyType);
                    }
                    else
                    {
                        AttributeCache filterAttribute          = null;
                        Expression     attributeWhereExpression = null;

                        // We would really love to further qualify this beyond the EntityType by including the
                        // EntityTypeQualifier and EntityTypeQualifierValue but we can't easily do that so, we
                        // will do that "Just in case..." code below (because this actually happened in our Spark
                        // environment.
                        foreach (var id in AttributeCache.GetByEntity(entityTypeCache.Id).SelectMany(a => a.AttributeIds))
                        {
                            var attribute = AttributeCache.Get(id);

                            // Just in case this EntityType has multiple attributes with the same key, create a OR'd clause for each attribute that has this key
                            // NOTE: this could easily happen if doing an entity command against a DefinedValue, and the same attribute key is used in more than one defined type
                            if (attribute.Key == property)
                            {
                                filterAttribute = attribute;
                                var attributeEntityField = EntityHelper.GetEntityFieldForAttribute(filterAttribute);

                                if (attributeWhereExpression == null)
                                {
                                    attributeWhereExpression = ExpressionHelper.GetAttributeExpression(service, parmExpression, attributeEntityField, selectionParms);
                                }
                                else
                                {
                                    attributeWhereExpression = Expression.OrElse(attributeWhereExpression, ExpressionHelper.GetAttributeExpression(service, parmExpression, attributeEntityField, selectionParms));
                                }
                            }
                        }

                        if (attributeWhereExpression != null)
                        {
                            expression = attributeWhereExpression;
                        }
                    }

                    if (returnExpression == null)
                    {
                        returnExpression = expression;
                    }
                    else
                    {
                        if (currentExpressionComparisonType == ExpressionComparisonType.And)
                        {
                            returnExpression = Expression.AndAlso(returnExpression, expression);
                        }
                        else
                        {
                            returnExpression = Expression.OrElse(returnExpression, expression);
                        }
                    }
                }
                else
                {
                    // error in parsing expression
                    throw new Exception("Error in Where expression");
                }
            }

            return(returnExpression);
        }
Exemple #20
0
        /// <summary>
        /// Loads the campuses
        /// </summary>
        protected void LoadDropdowns()
        {
            var campusEntityType = EntityTypeCache.Get(typeof(Campus));
            var currentCampus    = RockPage.GetCurrentContext(campusEntityType) as Campus;

            var campusIdString = Request.QueryString["CampusId"];

            if (campusIdString != null)
            {
                var campusId = campusIdString.AsInteger();

                // if there is a query parameter, ensure that the Campus Context cookie is set (and has an updated expiration)
                // note, the Campus Context might already match due to the query parameter, but has a different cookie context, so we still need to ensure the cookie context is updated
                currentCampus = SetCampusContext(campusId, false);
            }

            // if the currentCampus isn't determined yet, and DefaultToCurrentUser, and the person has a CampusId, use that as the campus context
            if (currentCampus == null && GetAttributeValue(AttributeKey.DefaultToCurrentUser).AsBoolean() && CurrentPerson != null)
            {
                var campusId = CurrentPerson.GetFamily().CampusId;
                if (campusId.HasValue)
                {
                    currentCampus = SetCampusContext(campusId.Value, false);
                }
            }

            if (currentCampus != null)
            {
                var mergeObjects = new Dictionary <string, object>();
                mergeObjects.Add("CampusName", currentCampus.Name);
                lCurrentSelection.Text = GetAttributeValue(AttributeKey.CurrentItemTemplate).ResolveMergeFields(mergeObjects);
            }
            else
            {
                lCurrentSelection.Text = GetAttributeValue(AttributeKey.NoCampusText);
            }

            bool includeInactive = GetAttributeValue(AttributeKey.IncludeInactiveCampuses).AsBoolean();
            var  campusList      = CampusCache.All(includeInactive)
                                   .Select(a => new CampusItem {
                Name = a.Name, Id = a.Id
            })
                                   .ToList();

            // run lava on each campus
            string dropdownItemTemplate = GetAttributeValue(AttributeKey.DropdownItemTemplate);

            if (!string.IsNullOrWhiteSpace(dropdownItemTemplate))
            {
                foreach (var campus in campusList)
                {
                    var mergeObjects = new Dictionary <string, object>();
                    mergeObjects.Add("CampusName", campus.Name);
                    campus.Name = dropdownItemTemplate.ResolveMergeFields(mergeObjects);
                }
            }

            // check if the campus can be unselected
            if (!string.IsNullOrEmpty(GetAttributeValue(AttributeKey.ClearSelectionText)))
            {
                var blankCampus = new CampusItem
                {
                    Name = GetAttributeValue(AttributeKey.ClearSelectionText),
                    Id   = Rock.Constants.All.Id
                };

                campusList.Insert(0, blankCampus);
            }

            rptCampuses.DataSource = campusList;
            rptCampuses.DataBind();
        }
Exemple #21
0
 /// <summary>
 /// Gets the index result template.
 /// </summary>
 /// <value>
 /// The index result template.
 /// </value>
 public static string GetIndexResultTemplate()
 {
     return(EntityTypeCache.Get(typeof(T)).IndexResultTemplate);
 }
Exemple #22
0
        protected void btnSave_Click(object sender, EventArgs e)
        {
            hfAreaGroupClicked.Value = "true";

            using (var rockContext = new RockContext())
            {
                var attributeService = new AttributeService(rockContext);

                if (checkinArea.Visible)
                {
                    var groupTypeService = new GroupTypeService(rockContext);
                    var groupType        = groupTypeService.Get(checkinArea.GroupTypeGuid);
                    if (groupType != null)
                    {
                        groupType.LoadAttributes(rockContext);
                        checkinArea.GetGroupTypeValues(groupType);

                        if (groupType.IsValid)
                        {
                            rockContext.SaveChanges();
                            groupType.SaveAttributeValues(rockContext);

                            bool AttributesUpdated = false;

                            // rebuild the CheckinLabel attributes from the UI (brute-force)
                            foreach (var labelAttribute in CheckinArea.GetCheckinLabelAttributes(groupType.Attributes))
                            {
                                var attribute = attributeService.Get(labelAttribute.Value.Guid);
                                Rock.Web.Cache.AttributeCache.Flush(attribute.Id);
                                attributeService.Delete(attribute);
                                AttributesUpdated = true;
                            }

                            // Make sure default role is set
                            if (!groupType.DefaultGroupRoleId.HasValue && groupType.Roles.Any())
                            {
                                groupType.DefaultGroupRoleId = groupType.Roles.First().Id;
                            }

                            rockContext.SaveChanges();

                            int labelOrder            = 0;
                            int binaryFileFieldTypeID = FieldTypeCache.Read(Rock.SystemGuid.FieldType.BINARY_FILE.AsGuid()).Id;
                            foreach (var checkinLabelAttributeInfo in checkinArea.CheckinLabels)
                            {
                                var attribute = new Rock.Model.Attribute();
                                attribute.AttributeQualifiers.Add(new AttributeQualifier {
                                    Key = "binaryFileType", Value = Rock.SystemGuid.BinaryFiletype.CHECKIN_LABEL
                                });
                                attribute.Guid         = Guid.NewGuid();
                                attribute.FieldTypeId  = binaryFileFieldTypeID;
                                attribute.EntityTypeId = EntityTypeCache.GetId(typeof(GroupType));
                                attribute.EntityTypeQualifierColumn = "Id";
                                attribute.EntityTypeQualifierValue  = groupType.Id.ToString();
                                attribute.DefaultValue = checkinLabelAttributeInfo.BinaryFileGuid.ToString();
                                attribute.Key          = checkinLabelAttributeInfo.AttributeKey;
                                attribute.Name         = checkinLabelAttributeInfo.FileName;
                                attribute.Order        = labelOrder++;

                                if (!attribute.IsValid)
                                {
                                    return;
                                }

                                attributeService.Add(attribute);
                                AttributesUpdated = true;
                            }

                            rockContext.SaveChanges();

                            GroupTypeCache.Flush(groupType.Id);
                            Rock.CheckIn.KioskDevice.FlushAll();

                            if (AttributesUpdated)
                            {
                                AttributeCache.FlushEntityAttributes();
                            }

                            nbSaveSuccess.Visible = true;
                            BuildRows();
                        }
                        else
                        {
                            ShowInvalidResults(groupType.ValidationResults);
                        }
                    }
                }

                if (checkinGroup.Visible)
                {
                    var groupService         = new GroupService(rockContext);
                    var groupLocationService = new GroupLocationService(rockContext);

                    var group = groupService.Get(checkinGroup.GroupGuid);
                    if (group != null)
                    {
                        group.LoadAttributes(rockContext);
                        checkinGroup.GetGroupValues(group);

                        // populate groupLocations with whatever is currently in the grid, with just enough info to repopulate it and save it later
                        var newLocationIds = checkinGroup.Locations.Select(l => l.LocationId).ToList();
                        foreach (var groupLocation in group.GroupLocations.Where(l => !newLocationIds.Contains(l.LocationId)).ToList())
                        {
                            groupLocationService.Delete(groupLocation);
                            group.GroupLocations.Remove(groupLocation);
                        }

                        var existingLocationIds = group.GroupLocations.Select(g => g.LocationId).ToList();
                        foreach (var item in checkinGroup.Locations.Where(l => !existingLocationIds.Contains(l.LocationId)).ToList())
                        {
                            var groupLocation = new GroupLocation();
                            groupLocation.LocationId = item.LocationId;
                            group.GroupLocations.Add(groupLocation);
                        }

                        // Set the new order
                        foreach (var item in checkinGroup.Locations.OrderBy(l => l.Order).ToList())
                        {
                            var groupLocation = group.GroupLocations.FirstOrDefault(gl => gl.LocationId == item.LocationId);
                            groupLocation.Order = item.Order ?? 0;
                        }

                        if (group.IsValid)
                        {
                            rockContext.SaveChanges();
                            group.SaveAttributeValues(rockContext);

                            Rock.CheckIn.KioskDevice.FlushAll();
                            nbSaveSuccess.Visible = true;
                            BuildRows();
                        }
                        else
                        {
                            ShowInvalidResults(group.ValidationResults);
                        }
                    }
                }
            }

            hfIsDirty.Value = "false";
        }
        /// <summary>
        /// Creates the table controls.
        /// </summary>
        private void BindHtmlGrid()
        {
            _financialTransactionDetailList = null;
            RockContext rockContext = new RockContext();

            List <DataControlField> tableColumns = new List <DataControlField>();

            tableColumns.Add(new RockLiteralField {
                ID = "lPerson", HeaderText = "Person"
            });
            tableColumns.Add(new RockLiteralField {
                ID = "lTransactionInfo", HeaderText = "Transaction Info"
            });
            tableColumns.Add(new RockLiteralField {
                ID = "lCheckImage", HeaderText = "Check Image"
            });
            tableColumns.Add(new RockLiteralField {
                ID = "lMatchedRegistration", HeaderText = "Matched Registration"
            });
            tableColumns.Add(new RockLiteralField {
                ID = "lButton"
            });

            StringBuilder headers = new StringBuilder();

            foreach (var tableColumn in tableColumns)
            {
                if (tableColumn.HeaderStyle.CssClass.IsNotNullOrWhiteSpace())
                {
                    headers.AppendFormat("<th class='{0}'>{1}</th>", tableColumn.HeaderStyle.CssClass, tableColumn.HeaderText);
                }
                else
                {
                    headers.AppendFormat("<th>{0}</th>", tableColumn.HeaderText);
                }
            }

            lHeaderHtml.Text = headers.ToString();
            var registrationEntityTypeId = EntityTypeCache.GetId <Registration>();

            if (BatchId.HasValue && RegistrationInstanceId.HasValue)
            {
                nbErrorMessage.Visible = false;
                try
                {
                    var financialTransactionDetailQuery = new FinancialTransactionDetailService(rockContext).Queryable()
                                                          .Include(a => a.Transaction)
                                                          .Include(a => a.Transaction.AuthorizedPersonAlias.Person)
                                                          .Where(a => a.Transaction.BatchId == BatchId.Value && (!a.EntityTypeId.HasValue || a.EntityTypeId == registrationEntityTypeId))
                                                          .OrderByDescending(a => a.Transaction.TransactionDateTime);

                    _financialTransactionDetailList = financialTransactionDetailQuery.Take(1000).ToList();
                }
                catch (Exception ex)
                {
                    ExceptionLogService.LogException(ex);
                    var sqlTimeoutException = ReportingHelper.FindSqlTimeoutException(ex);

                    if (sqlTimeoutException != null)
                    {
                        nbErrorMessage.NotificationBoxType = NotificationBoxType.Warning;
                        nbErrorMessage.Text = "This report did not complete in a timely manner. You can try again or adjust the timeout setting of this block.";
                    }
                    else
                    {
                        nbErrorMessage.Text = "There was a problem with one of the filters for this report's dataview.";
                        nbErrorMessage.NotificationBoxType = NotificationBoxType.Danger;
                        nbErrorMessage.Details             = ex.Message;
                        nbErrorMessage.Visible             = true;
                        return;
                    }
                }

                phTableRows.Controls.Clear();

                int rowCount = 0;
                foreach (var financialTransactionDetail in _financialTransactionDetailList)
                {
                    rowCount += 1;
                    var tr = new HtmlGenericContainer("tr");
                    tr.ID = "tr_" + rowCount;
                    foreach (var tableColumn in tableColumns)
                    {
                        var literalControl = new LiteralControl();
                        if (tableColumn is RockLiteralField)
                        {
                            tr.Controls.Add(literalControl);
                            var literalTableColumn = tableColumn as RockLiteralField;
                            if (literalTableColumn.ID == "lPerson")
                            {
                                literalControl.Text = string.Format("<td>{0}</td>", financialTransactionDetail.Transaction.AuthorizedPersonAlias);
                            }
                            else if (literalTableColumn.ID == "lTransactionInfo")
                            {
                                literalControl.Text = string.Format("<td>{0}<br/>{1}</td>", financialTransactionDetail.Amount.FormatAsCurrency(), financialTransactionDetail.Account.ToString());
                            }
                            else if (literalTableColumn.ID == "lCheckImage")
                            {
                                var primaryImage = financialTransactionDetail.Transaction.Images
                                                   .OrderBy(i => i.Order)
                                                   .FirstOrDefault();
                                string imageTag = string.Empty;
                                if (primaryImage != null)
                                {
                                    var imageUrl = string.Format("~/GetImage.ashx?id={0}", primaryImage.BinaryFileId);
                                    imageTag = string.Format("<div class='photo transaction-image' style='max-width: 400px;'><a href='{0}'><img src='{0}'/></a></div>", ResolveRockUrl(imageUrl));
                                }

                                literalControl.Text = string.Format("<td>{0}</td>", imageTag);
                            }
                            else if (literalTableColumn.ID == "lTransactionType")
                            {
                                literalControl.ID   = "lTransactionType_" + financialTransactionDetail.Id.ToString();
                                literalControl.Text = string.Format("<td>{0}</td>", financialTransactionDetail.Transaction.TransactionTypeValue);
                            }
                            else if (literalTableColumn.ID == "lMatchedRegistration")
                            {
                                if (financialTransactionDetail.EntityTypeId == registrationEntityTypeId && financialTransactionDetail.EntityId.HasValue)
                                {
                                    literalControl.ID   = "lMatchedRegistration_" + financialTransactionDetail.Id.ToString();
                                    literalControl.Text = string.Format("<td></td>");
                                }
                                else
                                {
                                    var tdEntityControls = new HtmlGenericContainer("td")
                                    {
                                        ID = "lMatchedRegistration_" + financialTransactionDetail.Id.ToString()
                                    };
                                    tr.Controls.Add(tdEntityControls);
                                    var ddlRegistration = new RockDropDownList {
                                        ID = "ddlRegistration_" + financialTransactionDetail.Id.ToString(), EnhanceForLongLists = true
                                    };
                                    ddlRegistration.Label                 = "Registration";
                                    ddlRegistration.AutoPostBack          = true;
                                    ddlRegistration.SelectedIndexChanged += ddlRegistration_SelectedIndexChanged;
                                    tdEntityControls.Controls.Add(ddlRegistration);
                                }
                            }
                            else if (literalTableColumn.ID == "lButton")
                            {
                                var tdEntityControls = new HtmlGenericContainer("td")
                                {
                                    ID = "pnlBtnControls_" + financialTransactionDetail.Id.ToString()
                                };
                                tr.Controls.Add(tdEntityControls);
                                var lbDelete = new LinkButton {
                                    ID = "lbDelete_" + financialTransactionDetail.Id.ToString()
                                };
                                lbDelete.CausesValidation = false;
                                lbDelete.Click           += lbDelete_Click;
                                HtmlGenericControl buttonIcon = new HtmlGenericControl("i");
                                buttonIcon.Attributes.Add("class", "fa fa-close");
                                lbDelete.Controls.Add(buttonIcon);
                                tdEntityControls.Controls.Add(lbDelete);
                                lbDelete.Visible = financialTransactionDetail.EntityTypeId == registrationEntityTypeId && financialTransactionDetail.EntityId.HasValue;
                            }
                        }
                    }

                    phTableRows.Controls.Add(tr);

                    pnlTransactions.Visible = true;
                }
            }
            else
            {
                pnlTransactions.Visible = false;
            }
        }
        /// <summary>
        /// Gets the summary data.
        /// </summary>
        private void GetSummaryData()
        {
            var midnightToday = RockDateTime.Today.AddDays(1);

            SummaryState = new List <ConnectionTypeSummary>();

            var rockContext = new RockContext();
            var connectionOpportunityService = new ConnectionOpportunityService(rockContext);
            var followingService             = new FollowingService(rockContext);
            var opportunityEntityTypeId      = EntityTypeCache.Get <ConnectionOpportunity>().Id;

            var followedOpportunityIds = followingService.Queryable()
                                         .AsNoTracking()
                                         .Where(f =>
                                                f.PersonAliasId == CurrentPersonAliasId &&
                                                f.EntityTypeId == opportunityEntityTypeId &&
                                                string.IsNullOrEmpty(f.PurposeKey))
                                         .Select(f => f.EntityId)
                                         .ToList();

            var opportunityQuery = connectionOpportunityService.Queryable()
                                   .AsNoTracking()
                                   .Where(co =>
                                          co.IsActive &&
                                          co.ConnectionType.IsActive);

            var typeFilter = GetAttributeValue(AttributeKey.ConnectionTypes).SplitDelimitedValues().AsGuidList();

            if (typeFilter.Any())
            {
                opportunityQuery = opportunityQuery.Where(o => typeFilter.Contains(o.ConnectionType.Guid));
            }

            var selfAssignedOpportunities          = new List <int>();
            var isSelfAssignedOpportunitiesQueried = false;
            var opportunities = opportunityQuery.ToList();

            // Loop through opportunities
            foreach (var opportunity in opportunities)
            {
                // Check to see if person can edit the opportunity because of edit rights to this block or edit rights to
                // the opportunity
                bool canEdit = UserCanEdit || opportunity.IsAuthorized(Authorization.EDIT, CurrentPerson);
                bool campusSpecificConnector = false;
                var  campusIds = new List <int>();

                if (CurrentPersonId.HasValue)
                {
                    // Check to see if person belongs to any connector group that is not campus specific
                    if (!canEdit)
                    {
                        canEdit = opportunity
                                  .ConnectionOpportunityConnectorGroups
                                  .Any(g =>
                                       !g.CampusId.HasValue &&
                                       g.ConnectorGroup != null &&
                                       g.ConnectorGroup.Members.Any(m => m.PersonId == CurrentPersonId.Value));
                    }

                    // If user is not yet authorized to edit the opportunity, check to see if they are a member of one of the
                    // campus-specific connector groups for the opportunity, and note the campus
                    if (!canEdit)
                    {
                        foreach (var groupCampus in opportunity
                                 .ConnectionOpportunityConnectorGroups
                                 .Where(g =>
                                        g.CampusId.HasValue &&
                                        g.ConnectorGroup != null &&
                                        g.ConnectorGroup.Members.Any(m => m.PersonId == CurrentPersonId.Value)))
                        {
                            campusSpecificConnector = true;
                            canEdit = true;
                            campusIds.Add(groupCampus.CampusId.Value);
                        }
                    }
                }

                if (opportunity.ConnectionType.EnableRequestSecurity && !isSelfAssignedOpportunitiesQueried)
                {
                    isSelfAssignedOpportunitiesQueried = true;
                    selfAssignedOpportunities          = new ConnectionRequestService(rockContext)
                                                         .Queryable()
                                                         .Where(a => a.ConnectorPersonAlias.PersonId == CurrentPersonId.Value)
                                                         .Select(a => a.ConnectionOpportunityId)
                                                         .Distinct()
                                                         .ToList();
                }

                var canView = opportunity.IsAuthorized(Authorization.VIEW, CurrentPerson) ||
                              (opportunity.ConnectionType.EnableRequestSecurity && selfAssignedOpportunities.Contains(opportunity.Id));

                // Is user is authorized to view this opportunity type...
                if (canView)
                {
                    // Check if the opportunity's type has been added to summary yet, and if not, add it
                    var connectionTypeSummary = SummaryState.Where(c => c.Id == opportunity.ConnectionTypeId).FirstOrDefault();
                    if (connectionTypeSummary == null)
                    {
                        connectionTypeSummary = new ConnectionTypeSummary
                        {
                            Id   = opportunity.ConnectionTypeId,
                            Name = opportunity.ConnectionType.Name,
                            EnableRequestSecurity              = opportunity.ConnectionType.EnableRequestSecurity,
                            ConnectionRequestDetailPageId      = opportunity.ConnectionType.ConnectionRequestDetailPageId,
                            ConnectionRequestDetailPageRouteId = opportunity.ConnectionType.ConnectionRequestDetailPageRouteId,
                            Opportunities = new List <OpportunitySummary>(),
                            IconMarkup    = opportunity.ConnectionType.IconCssClass.IsNullOrWhiteSpace() ?
                                            string.Empty :
                                            $@"<i class=""{opportunity.ConnectionType.IconCssClass}""></i>",
                            Order = opportunity.ConnectionType.Order
                        };
                        SummaryState.Add(connectionTypeSummary);
                    }

                    // get list of idle requests (no activity in past X days)

                    var connectionRequestsQry = new ConnectionRequestService(rockContext).Queryable().Where(a => a.ConnectionOpportunityId == opportunity.Id);

                    var currentDateTime    = RockDateTime.Now;
                    int activeRequestCount = connectionRequestsQry
                                             .Where(cr =>
                                                    cr.ConnectionState == ConnectionState.Active ||
                                                    (cr.ConnectionState == ConnectionState.FutureFollowUp && cr.FollowupDate.HasValue && cr.FollowupDate.Value < midnightToday)
                                                    )
                                             .Count();

                    // only show if the opportunity is active and there are active requests
                    if (opportunity.IsActive || (!opportunity.IsActive && activeRequestCount > 0))
                    {
                        // idle count is:
                        //  (the request is active OR future follow-up who's time has come)
                        //  AND
                        //  (where the activity is more than DaysUntilRequestIdle days old OR no activity but created more than DaysUntilRequestIdle days ago)
                        List <int> idleConnectionRequests = connectionRequestsQry
                                                            .Where(cr =>
                                                                   (
                                                                       cr.ConnectionState == ConnectionState.Active ||
                                                                       (cr.ConnectionState == ConnectionState.FutureFollowUp && cr.FollowupDate.HasValue && cr.FollowupDate.Value < midnightToday)
                                                                   )
                                                                   &&
                                                                   (
                                                                       (cr.ConnectionRequestActivities.Any() && cr.ConnectionRequestActivities.Max(ra => ra.CreatedDateTime) < SqlFunctions.DateAdd("day", -cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle, currentDateTime)) ||
                                                                       (!cr.ConnectionRequestActivities.Any() && cr.CreatedDateTime < SqlFunctions.DateAdd("day", -cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle, currentDateTime))
                                                                   )
                                                                   )
                                                            .Select(a => a.Id).ToList();

                        // get list of requests that have a status that is considered critical.
                        List <int> criticalConnectionRequests = connectionRequestsQry
                                                                .Where(r =>
                                                                       r.ConnectionStatus.IsCritical &&
                                                                       (
                                                                           r.ConnectionState == ConnectionState.Active ||
                                                                           (r.ConnectionState == ConnectionState.FutureFollowUp && r.FollowupDate.HasValue && r.FollowupDate.Value < midnightToday)
                                                                       )
                                                                       )
                                                                .Select(a => a.Id).ToList();

                        // Add the opportunity
                        var opportunitySummary = new OpportunitySummary
                        {
                            Id                         = opportunity.Id,
                            Order                      = opportunity.Order,
                            Name                       = opportunity.Name,
                            IsActive                   = opportunity.IsActive,
                            IconCssClass               = opportunity.IconCssClass,
                            IdleConnectionRequests     = idleConnectionRequests,
                            CriticalConnectionRequests = criticalConnectionRequests,
                            DaysUntilRequestIdle       = opportunity.ConnectionType.DaysUntilRequestIdle,
                            CanEdit                    = canEdit,
                            IsFollowed                 = followedOpportunityIds.Contains(opportunity.Id)
                        };

                        // If the user is limited requests with specific campus(es) set the list, otherwise leave it to be null
                        opportunitySummary.CampusSpecificConnector = campusSpecificConnector;
                        opportunitySummary.ConnectorCampusIds      = campusIds.Distinct().ToList();

                        connectionTypeSummary.Opportunities.Add(opportunitySummary);
                    }
                }
            }

            // Get a list of all the authorized opportunity ids
            var allOpportunities = SummaryState.SelectMany(s => s.Opportunities).Select(o => o.Id).Distinct().ToList();

            // Get all the active and past-due future followup request ids, and include the campus id and personid of connector
            var activeRequestsQry = new ConnectionRequestService(rockContext)
                                    .Queryable().AsNoTracking()
                                    .Where(r =>
                                           allOpportunities.Contains(r.ConnectionOpportunityId) &&
                                           (r.ConnectionState == ConnectionState.Active ||
                                            (r.ConnectionState == ConnectionState.FutureFollowUp && r.FollowupDate.HasValue && r.FollowupDate.Value < midnightToday)))
                                    .Select(r => new
            {
                r.Id,
                r.ConnectionOpportunityId,
                r.CampusId,
                ConnectorPersonId = r.ConnectorPersonAlias != null ? r.ConnectorPersonAlias.PersonId : -1
            });

            var activeRequests = activeRequestsQry.ToList();

            // Based on the active requests, set additional properties for each opportunity
            foreach (var opportunity in SummaryState.SelectMany(s => s.Opportunities))
            {
                // Get the active requests for this opportunity that user is authorized to view (based on campus connector)
                var opportunityRequests = activeRequests
                                          .Where(r =>
                                                 r.ConnectionOpportunityId == opportunity.Id &&
                                                 (
                                                     !opportunity.CampusSpecificConnector ||
                                                     (r.CampusId.HasValue && opportunity.ConnectorCampusIds.Contains(r.CampusId.Value))
                                                 ))
                                          .ToList();

                // The active requests assigned to the current person
                opportunity.AssignedToYouConnectionRequests = opportunityRequests.Where(r => r.ConnectorPersonId == CurrentPersonId).Select(a => a.Id).ToList();

                // The active requests that are unassigned
                opportunity.UnassignedConnectionRequests = opportunityRequests.Where(r => r.ConnectorPersonId == -1).Select(a => a.Id).ToList();

                // Flag indicating if current user is connector for any of the active types
                opportunity.HasActiveRequestsForConnector = opportunityRequests.Any(r => r.ConnectorPersonId == CurrentPersonId);

                // Total number of requests for opportunity/campus/connector
                opportunity.TotalRequests = opportunityRequests.Count();
            }

            //Set the Idle tooltip
            var           connectionTypes = opportunities.Where(o => allOpportunities.Contains(o.Id)).Select(o => o.ConnectionType).Distinct().ToList();
            StringBuilder sb = new StringBuilder();

            if (connectionTypes.Select(t => t.DaysUntilRequestIdle).Distinct().Count() == 1)
            {
                sb.Append(String.Format("Idle (no activity in {0} days)", connectionTypes.Select(t => t.DaysUntilRequestIdle).Distinct().First()));
            }
            else
            {
                sb.Append("Idle (no activity in several days)<br/><ul class='list-unstyled'>");
                foreach (var connectionType in connectionTypes)
                {
                    sb.Append(String.Format("<li>{0}: {1} days</li>", connectionType.Name, connectionType.DaysUntilRequestIdle));
                }
                sb.Append("</ul>");
            }

            var statusTemplate    = GetAttributeValue(AttributeKey.StatusTemplate);
            var statusMergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage);

            statusMergeFields.Add("ConnectionOpportunities", allOpportunities);
            statusMergeFields.Add("ConnectionTypes", connectionTypes);
            statusMergeFields.Add("IdleTooltip", sb.ToString().EncodeHtml());
            lStatusBarContent.Text = statusTemplate.ResolveMergeFields(statusMergeFields);
            BindSummaryData();
        }
        /// <summary>
        /// Liquidizes the child properties of an object for displaying debug information about fields available for lava templates
        /// </summary>
        /// <param name="myObject">an object.</param>
        /// <param name="levelsDeep">The levels deep.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="entityHistory">The entity history.</param>
        /// <param name="parentElement">The parent element.</param>
        /// <returns></returns>
        private static object LiquidizeChildren(this object myObject, int levelsDeep = 0, RockContext rockContext = null, Dictionary <int, List <int> > entityHistory = null, string parentElement = "")
        {
            // Add protection for stack-overflow if property attributes are not set correctly resulting in child/parent objects being evaluated in loop
            levelsDeep++;
            if (levelsDeep > 6)
            {
                return(string.Empty);
            }

            // If the object is liquidable, get the object return by its ToLiquid() method.
            if (myObject is DotLiquid.ILiquidizable)
            {
                myObject = ((DotLiquid.ILiquidizable)myObject).ToLiquid();
            }

            // If the object is null, return an empty string
            if (myObject == null)
            {
                return(string.Empty);
            }

            // If the object is a string, return its value converted to HTML and truncated
            if (myObject is string)
            {
                return(myObject.ToString().Truncate(50).EncodeHtml());
            }

            // If the object is a guid, return its string representation
            if (myObject is Guid)
            {
                return(myObject.ToString());
            }

            // Get the object's type ( checking for a proxy object )
            Type entityType = myObject.GetType();

            if (entityType.IsDynamicProxyType())
            {
                entityType = entityType.BaseType;
            }

            // If this is an IEntity, check to see if it's already been liquidized in prev hierarchy. If so, just return string indicating "--See Previous Entry--"
            if (myObject is IEntity)
            {
                var entity          = myObject as IEntity;
                var entityTypeCache = EntityTypeCache.Get(entityType, false, rockContext);
                if (entity != null && entityTypeCache != null)
                {
                    if (entityHistory == null)
                    {
                        entityHistory = new Dictionary <int, List <int> >();
                    }
                    entityHistory.AddOrIgnore(entityTypeCache.Id, new List <int>());
                    if (entityHistory[entityTypeCache.Id].Contains(entity.Id))
                    {
                        return("--See Previous Entry--");
                    }
                    else
                    {
                        entityHistory[entityTypeCache.Id].Add(entity.Id);
                    }
                }
            }

            // If the object is a Liquid Drop object, return a list of all of the object's properties
            if (myObject is Drop)
            {
                var  result   = new Dictionary <string, object>();
                Type baseDrop = typeof(DropBase);

                foreach (var propInfo in entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (propInfo != null && propInfo.DeclaringType != baseDrop)
                    {
                        try
                        {
                            result.Add(propInfo.Name, propInfo.GetValue(myObject, null).LiquidizeChildren(levelsDeep, rockContext, entityHistory));
                        }
                        catch (Exception ex)
                        {
                            result.Add(propInfo.Name, ex.ToString());
                        }
                    }
                }

                return(result);
            }

            // If the object has the [LiquidType] attribute, enumerate the allowed properties and return a list of those properties
            if (entityType.GetCustomAttributes(typeof(LiquidTypeAttribute), false).Any())
            {
                var result = new Dictionary <string, object>();

                var attr = (LiquidTypeAttribute)entityType.GetCustomAttributes(typeof(LiquidTypeAttribute), false).First();
                foreach (string propName in attr.AllowedMembers)
                {
                    var propInfo = entityType.GetProperty(propName);
                    {
                        if (propInfo != null)
                        {
                            try
                            {
                                result.Add(propInfo.Name, propInfo.GetValue(myObject, null).LiquidizeChildren(levelsDeep, rockContext, entityHistory, parentElement + "." + propName));
                            }
                            catch (Exception ex)
                            {
                                result.Add(propInfo.Name, ex.ToString());
                            }
                        }
                    }
                }

                return(result);
            }

            // If the object is a Rock Liquidizable object, call the object's AvailableKeys method to determine the properties available.
            if (myObject is Lava.ILiquidizable)
            {
                var liquidObject = (Lava.ILiquidizable)myObject;

                var result = new Dictionary <string, object>();

                foreach (var key in liquidObject.AvailableKeys)
                {
                    // Ignore the person property of the person's primary alias (prevent unnecessary recursion)
                    if (key == "Person" && parentElement.Contains(".PrimaryAlias"))
                    {
                        result.AddOrIgnore(key, string.Empty);
                    }
                    else
                    {
                        try
                        {
                            object propValue = null;

                            var propType = entityType.GetProperty(key)?.PropertyType;
                            if (propType?.Name == "ICollection`1")
                            {
                                // if the property type is an ICollection, get the underlying query and just fetch one for an example (just in case there are 1000s of records)
                                var entityDbContext = GetDbContextFromEntity(myObject);
                                if (entityDbContext != null)
                                {
                                    var entryCollection = entityDbContext.Entry(myObject)?.Collection(key);
                                    if (entryCollection.EntityEntry.State == EntityState.Detached)
                                    {
                                        // create a sample since we can't fetch real data
                                        Type listOfType     = propType.GenericTypeArguments[0];
                                        var  sampleListType = typeof(List <>).MakeGenericType(listOfType);
                                        var  sampleList     = Activator.CreateInstance(sampleListType) as IList;
                                        var  sampleItem     = Activator.CreateInstance(listOfType);
                                        sampleList.Add(sampleItem);
                                        propValue = sampleList;
                                    }
                                    else
                                    {
                                        if (entryCollection.IsLoaded)
                                        {
                                            propValue = liquidObject[key];
                                        }
                                        else
                                        {
                                            try
                                            {
                                                var           propQry             = entryCollection.Query().Provider.CreateQuery <Rock.Data.IEntity>(entryCollection.Query().Expression);
                                                int           propCollectionCount = propQry.Count();
                                                List <object> listSample          = propQry.Take(1).ToList().Cast <object>().ToList();
                                                if (propCollectionCount > 1)
                                                {
                                                    listSample.Add($"({propCollectionCount - 1} more...)");
                                                }

                                                propValue = listSample;
                                            }
                                            catch
                                            {
                                                // The Collection might be a database model that isn't an IEntity, so just do it the regular way
                                                propValue = liquidObject[key];
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                propValue = liquidObject[key];
                            }

                            if (propValue != null)
                            {
                                result.Add(key, propValue.LiquidizeChildren(levelsDeep, rockContext, entityHistory, parentElement + "." + key));
                            }
                            else
                            {
                                result.AddOrIgnore(key, string.Empty);
                            }
                        }
                        catch (Exception ex)
                        {
                            result.AddOrIgnore(key, ex.ToString());
                        }
                    }
                }

                // Add the attributes if this object has attributes
                if (liquidObject is IHasAttributes)
                {
                    var objWithAttrs = (IHasAttributes)liquidObject;
                    if (objWithAttrs.Attributes == null)
                    {
                        rockContext = rockContext ?? new RockContext();
                        objWithAttrs.LoadAttributes(rockContext);
                    }

                    var objAttrs = new Dictionary <string, object>();
                    foreach (var objAttr in objWithAttrs.Attributes)
                    {
                        var    attributeCache = objAttr.Value;
                        string value          = attributeCache.FieldType.Field.FormatValue(null, attributeCache.EntityTypeId, objWithAttrs.Id, objWithAttrs.GetAttributeValue(attributeCache.Key), attributeCache.QualifierValues, false);
                        objAttrs.Add(attributeCache.Key, value.Truncate(50).EncodeHtml());
                    }

                    if (objAttrs.Any())
                    {
                        result.Add(string.Format("Attributes <p class='attributes'>Below is a list of attributes that can be retrieved using <code>{{{{ {0} | Attribute:'[AttributeKey]' }}}}</code>.</p>", parentElement), objAttrs);
                    }
                }

                return(result);
            }

            if (myObject is IDictionary <string, object> )
            {
                var result = new Dictionary <string, object>();

                foreach (var keyValue in ((IDictionary <string, object>)myObject))
                {
                    try
                    {
                        var parentVariable = (keyValue.Value?.GetType().GetInterface("IList") != null) ? keyValue.Key.ToLower().Singularize() : keyValue.Key;
                        result.Add(keyValue.Key, keyValue.Value?.LiquidizeChildren(levelsDeep, rockContext, entityHistory, parentVariable));
                    }
                    catch (Exception ex)
                    {
                        result.Add(keyValue.Key, ex.ToString());
                    }
                }

                return(result);
            }

            if (myObject is Newtonsoft.Json.Linq.JObject)
            {
                var result  = new Dictionary <string, object>();
                var jObject = myObject as Newtonsoft.Json.Linq.JObject;

                foreach (var keyValue in jObject)
                {
                    try
                    {
                        result.Add(keyValue.Key, keyValue.Value.LiquidizeChildren(levelsDeep, rockContext, entityHistory, keyValue.Key));
                    }
                    catch (Exception ex)
                    {
                        result.Add(keyValue.Key, ex.ToString());
                    }
                }

                return(result);
            }

            if (myObject is Newtonsoft.Json.Linq.JValue)
            {
                var jValue = (myObject as Newtonsoft.Json.Linq.JValue);
                if (jValue != null && jValue.Value != null)
                {
                    return(jValue.Value.ToString());
                }
                else
                {
                    return(string.Empty);
                }
            }

            if (myObject is IEnumerable)
            {
                var result = new List <object>();

                // Only show first two items in an enumerable list
                int iEnumCount = 1;
                foreach (var value in ((IEnumerable)myObject))
                {
                    if (iEnumCount > 2)
                    {
                        result.Add("...");
                        break;
                    }
                    iEnumCount++;
                    try
                    {
                        result.Add(value.LiquidizeChildren(levelsDeep, rockContext, entityHistory, parentElement));
                    }
                    catch { }
                }

                return(result);
            }

            return(myObject.ToStringSafe());
        }
Exemple #26
0
        /// <summary>
        /// Binds the grid.
        /// </summary>
        protected void BindGrid()
        {
            AddScheduleColumns();

            var rockContext = new RockContext();

            var groupLocationService = new GroupLocationService(rockContext);
            var groupTypeService     = new GroupTypeService(rockContext);
            var groupService         = new GroupService(rockContext);

            var groupLocationQry = groupLocationService.Queryable();

            var templateGroupPaths = new Dictionary <int, List <GroupTypePath> >();
            var currentAndDescendantGroupTypeIds = new List <int>();

            foreach (var groupType in groupTypeService.Queryable().Where(a => this.LocalDeviceConfig.CurrentGroupTypeIds.Contains(a.Id)))
            {
                foreach (var parentGroupType in groupType.ParentGroupTypes)
                {
                    if (!templateGroupPaths.ContainsKey(parentGroupType.Id))
                    {
                        templateGroupPaths.Add(parentGroupType.Id, groupTypeService.GetAllAssociatedDescendentsPath(parentGroupType.Id).ToList());
                    }
                }

                currentAndDescendantGroupTypeIds.Add(groupType.Id);
                currentAndDescendantGroupTypeIds.AddRange(groupTypeService.GetAllAssociatedDescendents(groupType.Id).Select(a => a.Id).ToList());
            }

            var groupPaths = new List <GroupTypePath>();

            foreach (var path in templateGroupPaths)
            {
                groupPaths.AddRange(path.Value);
            }

            groupLocationQry = groupLocationQry.Where(a => currentAndDescendantGroupTypeIds.Contains(a.Group.GroupTypeId));

            groupLocationQry = groupLocationQry.OrderBy(a => a.Group.Name).ThenBy(a => a.Location.Name);

            List <int> currentDeviceLocationIdList = this.GetGroupTypesLocations(rockContext).Select(a => a.Id).Distinct().ToList();

            var qryList = groupLocationQry
                          .Where(a => currentDeviceLocationIdList.Contains(a.LocationId))
                          .Select(a =>
                                  new
            {
                GroupLocationId = a.Id,
                a.Location,
                GroupId        = a.GroupId,
                GroupName      = a.Group.Name,
                ScheduleIdList = a.Schedules.Select(s => s.Id),
                GroupTypeId    = a.Group.GroupTypeId
            }).ToList();

            var locationService = new LocationService(rockContext);

            // put stuff in a datatable so we can dynamically have columns for each Schedule
            DataTable dataTable = new DataTable();

            dataTable.Columns.Add("GroupLocationId");
            dataTable.Columns.Add("GroupId");
            dataTable.Columns.Add("GroupName");
            dataTable.Columns.Add("GroupPath");
            dataTable.Columns.Add("LocationName");
            dataTable.Columns.Add("LocationPath");
            foreach (var field in gGroupLocationSchedule.Columns.OfType <CheckBoxEditableField>())
            {
                dataTable.Columns.Add(field.DataField, typeof(bool));
            }

            var locationPaths = new Dictionary <int, string>();

            foreach (var row in qryList)
            {
                DataRow dataRow = dataTable.NewRow();
                dataRow["GroupLocationId"] = row.GroupLocationId;
                dataRow["GroupName"]       = groupService.GroupAncestorPathName(row.GroupId);
                dataRow["GroupPath"]       = groupPaths.Where(gt => gt.GroupTypeId == row.GroupTypeId).Select(gt => gt.Path).FirstOrDefault();
                dataRow["LocationName"]    = row.Location.Name;

                if (row.Location.ParentLocationId.HasValue)
                {
                    int locationId = row.Location.ParentLocationId.Value;

                    if (!locationPaths.ContainsKey(locationId))
                    {
                        var locationNames  = new List <string>();
                        var parentLocation = locationService.Get(locationId);
                        while (parentLocation != null)
                        {
                            locationNames.Add(parentLocation.Name);
                            parentLocation = parentLocation.ParentLocation;
                        }

                        if (locationNames.Any())
                        {
                            locationNames.Reverse();
                            locationPaths.Add(locationId, locationNames.AsDelimited(" > "));
                        }
                        else
                        {
                            locationPaths.Add(locationId, string.Empty);
                        }
                    }

                    dataRow["LocationPath"] = locationPaths[locationId];
                }

                foreach (var field in gGroupLocationSchedule.Columns.OfType <CheckBoxEditableField>())
                {
                    int scheduleId = int.Parse(field.DataField.Replace("scheduleField_", string.Empty));
                    dataRow[field.DataField] = row.ScheduleIdList.Any(a => a == scheduleId);
                }

                dataTable.Rows.Add(dataRow);
            }

            gGroupLocationSchedule.EntityTypeId = EntityTypeCache.Get <GroupLocation>().Id;
            gGroupLocationSchedule.DataSource   = dataTable;
            gGroupLocationSchedule.DataBind();
        }
Exemple #27
0
        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            _tbNote                    = new RockTextBox();
            _hfNoteId                  = new HiddenFieldWithClass();
            _tbNote.Placeholder        = "Write a note...";
            _ddlNoteType               = new DropDownList();
            _hfHasUnselectableNoteType = new HiddenFieldWithClass();
            _cbAlert                   = new CheckBox();
            _cbPrivate                 = new CheckBox();
            _lbSaveNote                = new LinkButton();
            _aSecurity                 = new HtmlAnchor();
            _dtCreateDate              = new DateTimePicker();
            _hfParentNoteId            = new HiddenFieldWithClass();
            _mdEditWarning             = new ModalAlert();

            _hfNoteId.ID       = this.ID + "_hfNoteId";
            _hfNoteId.CssClass = "js-noteid";
            Controls.Add(_hfNoteId);

            _hfParentNoteId.ID       = this.ID + "_hfParentNoteId";
            _hfParentNoteId.CssClass = "js-parentnoteid";
            Controls.Add(_hfParentNoteId);

            string validationGroup = $"vgNoteEdit_{this.ID}";

            _vsEditNote    = new ValidationSummary();
            _vsEditNote.ID = this.ID + "_vsEditNote";
            _vsEditNote.ValidationGroup = validationGroup;
            _vsEditNote.CssClass        = "alert alert-validation";
            _vsEditNote.HeaderText      = "Please correct the following:";
            Controls.Add(_vsEditNote);

            _tbNote.ID                  = this.ID + "_tbNewNote";
            _tbNote.TextMode            = TextBoxMode.MultiLine;
            _tbNote.Rows                = 3;
            _tbNote.CssClass            = "js-notetext";
            _tbNote.ValidateRequestMode = ValidateRequestMode.Disabled;
            _tbNote.Required            = true;
            _tbNote.RequiredFieldValidator.ErrorMessage = "Note is required.";
            _tbNote.ValidationGroup = validationGroup;
            Controls.Add(_tbNote);

            _ddlNoteType.ID             = this.ID + "_ddlNoteType";
            _ddlNoteType.CssClass       = "form-control input-sm input-width-lg noteentry-notetype js-notenotetype";
            _ddlNoteType.DataValueField = "Id";
            _ddlNoteType.DataTextField  = "Name";
            Controls.Add(_ddlNoteType);

            _hfHasUnselectableNoteType.ID       = this.ID + "_hfHasUnselectableNoteType";
            _hfHasUnselectableNoteType.CssClass = "js-has-unselectable-notetype";
            Controls.Add(_hfHasUnselectableNoteType);

            _cbAlert.ID       = this.ID + "_cbAlert";
            _cbAlert.Text     = "Alert";
            _cbAlert.CssClass = "js-notealert";
            Controls.Add(_cbAlert);

            _cbPrivate.ID       = this.ID + "_cbPrivate";
            _cbPrivate.Text     = "Private";
            _cbPrivate.CssClass = "js-noteprivate";
            Controls.Add(_cbPrivate);

            _mdEditWarning.ID = this.ID + "_mdEditWarning";
            Controls.Add(_mdEditWarning);

            _lbSaveNote.ID = this.ID + "_lbSaveNote";
            _lbSaveNote.Attributes["class"] = "btn btn-primary btn-xs";
            _lbSaveNote.CausesValidation    = true;
            _lbSaveNote.ValidationGroup     = validationGroup;
            _lbSaveNote.Click += lbSaveNote_Click;

            Controls.Add(_lbSaveNote);

            _aSecurity.ID = "_aSecurity";
            _aSecurity.Attributes["class"] = "btn btn-security btn-xs btn-square security js-notesecurity";
            _aSecurity.Attributes["data-entitytype-id"] = EntityTypeCache.Get(typeof(Rock.Model.Note)).Id.ToString();
            _aSecurity.InnerHtml = "<i class='fa fa-lock'></i>";
            Controls.Add(_aSecurity);

            _dtCreateDate.ID    = this.ID + "_tbCreateDate";
            _dtCreateDate.Label = "Note Created Date";
            _dtCreateDate.AddCssClass("js-notecreateddate");
            Controls.Add(_dtCreateDate);
        }
        /// <summary>
        /// Handles the FileUploaded event of the fuTemplateBinaryFile 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 fuTemplateBinaryFile_FileUploaded(object sender, EventArgs e)
        {
            nbFileTypeWarning.Visible = false;
            var mergeTemplateEntityType = EntityTypeCache.Read(ddlMergeTemplateType.SelectedValue.AsInteger());
            var binaryFile = new BinaryFileService(new RockContext()).Get(fuTemplateBinaryFile.BinaryFileId ?? 0);

            if (binaryFile != null)
            {
                string fileExtension = Path.GetExtension(binaryFile.FileName);
                fileExtension = fileExtension.TrimStart('.');
                if (string.IsNullOrWhiteSpace(fileExtension))
                {
                    // nothing more to do
                    return;
                }

                MergeTemplateType mergeTemplateType = null;

                if (mergeTemplateEntityType != null)
                {
                    mergeTemplateType = MergeTemplateTypeContainer.GetComponent(mergeTemplateEntityType.Name);
                }
                else
                {
                    // if a merge template type isn't selected, automatically pick the first matching one
                    foreach (var item in MergeTemplateTypeContainer.Instance.Components.Values)
                    {
                        if (item.Value.IsActive)
                        {
                            var testMergeTemplateType = item.Value;
                            if (testMergeTemplateType.SupportedFileExtensions != null && testMergeTemplateType.SupportedFileExtensions.Any())
                            {
                                if (testMergeTemplateType.SupportedFileExtensions.Contains(fileExtension))
                                {
                                    mergeTemplateType = testMergeTemplateType;
                                    var entityType = EntityTypeCache.Read(mergeTemplateType.EntityType.Id);
                                    if (entityType != null)
                                    {
                                        ddlMergeTemplateType.SetValue(entityType.Id);
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }

                if (mergeTemplateType == null)
                {
                    // couldn't automatically pick one, so warn that they need to pick it
                    nbFileTypeWarning.Text        = "Warning: Please select a template type.";
                    nbFileTypeWarning.Visible     = true;
                    nbFileTypeWarning.Dismissable = true;
                    return;
                }

                if (mergeTemplateType.SupportedFileExtensions != null && mergeTemplateType.SupportedFileExtensions.Any())
                {
                    if (!mergeTemplateType.SupportedFileExtensions.Contains(fileExtension))
                    {
                        nbFileTypeWarning.Text = string.Format(
                            "Warning: The selected template type doesn't support '{0}' files. Please use a {1} file for this template type.",
                            fileExtension,
                            mergeTemplateType.SupportedFileExtensions.Select(a => a.Quoted()).ToList().AsDelimited(", ", " or "));
                        nbFileTypeWarning.Visible     = true;
                        nbFileTypeWarning.Dismissable = true;
                        return;
                    }
                }
            }

            if (binaryFile != null && string.IsNullOrWhiteSpace(tbName.Text))
            {
                tbName.Text = Path.GetFileNameWithoutExtension(binaryFile.FileName).SplitCase().ReplaceWhileExists("  ", " ");
            }
        }
Exemple #29
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string serverKey = GetAttributeValue("ServerKey");
                    var    sender    = new Sender(serverKey);

                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                try
                                {
                                    int personAlias = recipient.PersonAliasId;

                                    var           service = new PersonalDeviceService(recipientRockContext);
                                    List <string> devices = service.Queryable()
                                                            .Where(p => p.PersonAliasId.HasValue && p.PersonAliasId.Value == personAlias && p.NotificationsEnabled && !string.IsNullOrEmpty(p.DeviceRegistrationId))
                                                            .Select(p => p.DeviceRegistrationId)
                                                            .ToList();

                                    if (devices.Any())
                                    {
                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                        var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var title   = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var sound   = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                        var notification = new Message
                                        {
                                            RegistrationIds = devices.Distinct().ToList(),
                                            Notification    = new FCM.Net.Notification
                                            {
                                                Title = title,
                                                Body  = message,
                                                Sound = sound,
                                            },
                                        };

                                        ResponseContent response = Utility.AsyncHelpers.RunSync(() => sender.SendAsync(notification));

                                        bool failed = response.MessageResponse.Failure == devices.Count;
                                        var  status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered;

                                        if (failed)
                                        {
                                            recipient.StatusNote = "Firebase failed to notify devices";
                                        }
                                        else
                                        {
                                            recipient.SendDateTime = RockDateTime.Now;
                                        }

                                        recipient.Status = status;
                                        recipient.TransportEntityTypeName = this.GetType().FullName;
                                        recipient.UniqueMessageId         = response.MessageResponse.MulticastId;

                                        try
                                        {
                                            var historyService = new HistoryService(recipientRockContext);
                                            historyService.Add(new History
                                            {
                                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                EntityTypeId           = personEntityTypeId,
                                                CategoryId             = communicationCategoryId,
                                                EntityId            = recipient.PersonAlias.PersonId,
                                                Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                ValueName           = "Push Notification",
                                                Caption             = message.Truncate(200),
                                                RelatedEntityTypeId = communicationEntityTypeId,
                                                RelatedEntityId     = communication.Id
                                            });
                                        }
                                        catch (Exception ex)
                                        {
                                            ExceptionLogService.LogException(ex, null);
                                        }
                                    }
                                    else
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "No Personal Devices with Messaging Enabled";
                                    }
                                }
                                catch (Exception ex)
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "Firebase Exception: " + ex.Message;
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Handles the SaveClick event of the modalDetails 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 modalDetails_SaveClick(object sender, EventArgs e)
        {
            int categoryId = 0;

            if (hfIdValue.Value != string.Empty && !int.TryParse(hfIdValue.Value, out categoryId))
            {
                categoryId = 0;
            }

            var      rockContext = new RockContext();
            var      service     = new CategoryService(rockContext);
            Category category    = null;

            if (categoryId != 0)
            {
                CategoryCache.Flush(categoryId);
                category = service.Get(categoryId);
            }

            if (category == null)
            {
                category = new Category();
                category.EntityTypeId = EntityTypeCache.Read(typeof(Rock.Model.Attribute)).Id;
                category.EntityTypeQualifierColumn = "EntityTypeId";

                var lastCategory = GetUnorderedCategories(category.EntityTypeId)
                                   .OrderByDescending(c => c.Order).FirstOrDefault();
                category.Order = lastCategory != null ? lastCategory.Order + 1 : 0;

                service.Add(category);
            }

            category.Name        = tbName.Text;
            category.Description = tbDescription.Text;

            string QualifierValue = null;

            if ((entityTypePicker.SelectedEntityTypeId ?? 0) != 0)
            {
                QualifierValue = entityTypePicker.SelectedEntityTypeId.ToString();
            }
            category.EntityTypeQualifierValue = QualifierValue;

            category.IconCssClass   = tbIconCssClass.Text;
            category.HighlightColor = tbHighlightColor.Text;

            List <int> orphanedBinaryFileIdList = new List <int>();

            if (category.IsValid)
            {
                BinaryFileService binaryFileService = new BinaryFileService(rockContext);
                foreach (int binaryFileId in orphanedBinaryFileIdList)
                {
                    var binaryFile = binaryFileService.Get(binaryFileId);
                    if (binaryFile != null)
                    {
                        // marked the old images as IsTemporary so they will get cleaned up later
                        binaryFile.IsTemporary = true;
                    }
                }

                rockContext.SaveChanges();

                hfIdValue.Value = string.Empty;
                modalDetails.Hide();

                BindFilter();
                BindGrid();
            }
        }