/// <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"); } }
/// <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(); }
/// <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); } }
/// <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)); } }
/// <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(); } }
/// <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>"; } }
/// <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; }
/// <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(); }
/// <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; } }
/// <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); }
/// <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); }
/// <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(); }
/// <summary> /// Gets the index result template. /// </summary> /// <value> /// The index result template. /// </value> public static string GetIndexResultTemplate() { return(EntityTypeCache.Get(typeof(T)).IndexResultTemplate); }
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()); }
/// <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(); }
/// <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(" ", " "); } }
/// <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(); } }