/// <summary> /// Checks to see if the person is authorized to VIEW /// </summary> /// <param name="securedModel">The secured model.</param> /// <param name="person">The person.</param> /// <exception cref="System.Web.Http.HttpResponseException"> /// </exception> protected virtual void CheckCanView(ISecured securedModel, Person person) { if (securedModel != null) { if (IsProxy(securedModel)) { if (!securedModel.IsAuthorized(Rock.Security.Authorization.VIEW, person)) { throw new HttpResponseException(HttpStatusCode.Unauthorized); } } else { // Need to reload using service with a proxy enabled so that if model has custom // parent authorities, those properties can be lazy-loaded and checked for authorization SetProxyCreation(true); ISecured reloadedModel = (ISecured)Service.Get(securedModel.Id); if (reloadedModel != null && !reloadedModel.IsAuthorized(Rock.Security.Authorization.VIEW, person)) { throw new HttpResponseException(HttpStatusCode.Unauthorized); } } } }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Init" /> event. /// </summary> /// <param name="e">An <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnInit(EventArgs e) { int? entityTypeId = PageParameter("EntityTypeId").AsIntegerOrNull(); string entityTypeName = string.Empty; Type type = null; // Get Entity Type if (entityTypeId.HasValue) { var entityType = EntityTypeCache.Read(entityTypeId.Value); if (entityType != null) { entityTypeName = entityType.FriendlyName; type = entityType.GetEntityType(); } } // Get Entity Id int entityId = PageParameter("EntityId").AsIntegerOrNull() ?? 0; // Get object type if (type != null) { if (entityId == 0) { iSecured = (ISecured)Activator.CreateInstance(type); } else { // Get the context type since this may be for a non-rock core object Type contextType = null; var contexts = Rock.Reflection.SearchAssembly(type.Assembly, typeof(Rock.Data.DbContext)); if (contexts.Any()) { contextType = contexts.First().Value; } else { contextType = typeof(RockContext); } Type serviceType = typeof(Rock.Data.Service <>); Type[] modelType = { type }; Type service = serviceType.MakeGenericType(modelType); var getMethod = service.GetMethod("Get", new Type[] { typeof(int) }); var context = Activator.CreateInstance(contextType); var serviceInstance = Activator.CreateInstance(service, new object[] { context }); iSecured = getMethod.Invoke(serviceInstance, new object[] { entityId }) as ISecured; } var block = iSecured as Rock.Model.Block; if (block != null) { // If the entity is a block, get any actions that were updated or added by the block type using // one or more SecurityActionAttributes. var blockCache = BlockCache.Read(block.Id); if (blockCache != null && blockCache.BlockType != null) { foreach (var action in BlockCache.Read(block.Id).BlockType.SecurityActions) { if (block.SupportedActions.ContainsKey(action.Key)) { block.SupportedActions[action.Key] = action.Value; } else { block.SupportedActions.Add(action.Key, action.Value); } } } iSecured = block; } if (iSecured != null) { if (iSecured.IsAuthorized(Authorization.ADMINISTRATE, CurrentPerson)) { if (iSecured.SupportedActions.Any()) { lActionDescription.Text = iSecured.SupportedActions.FirstOrDefault().Value; } rptActions.DataSource = iSecured.SupportedActions; rptActions.DataBind(); rGrid.DataKeyNames = new string[] { "Id" }; rGrid.GridReorder += new GridReorderEventHandler(rGrid_GridReorder); rGrid.GridRebind += new GridRebindEventHandler(rGrid_GridRebind); rGrid.RowDataBound += new GridViewRowEventHandler(rGrid_RowDataBound); rGrid.ShowHeaderWhenEmpty = false; rGrid.EmptyDataText = string.Empty; rGrid.ShowActionRow = false; rGridParentRules.DataKeyNames = new string[] { "Id" }; rGridParentRules.ShowHeaderWhenEmpty = false; rGridParentRules.EmptyDataText = string.Empty; rGridParentRules.ShowActionRow = false; BindRoles(); string scriptFormat = @" Sys.Application.add_load(function () {{ $('#modal-popup div.modal-header h3 small', window.parent.document).html('{0}'); }}); "; string script = string.Format(scriptFormat, HttpUtility.JavaScriptStringEncode(iSecured.ToString())); this.Page.ClientScript.RegisterStartupScript(this.GetType(), string.Format("set-html-{0}", this.ClientID), script, true); } else { nbMessage.Text = "Unfortunately, you are not able to edit security because you do not belong to a role that has been configured to allow administration of this item."; } } else { nbMessage.Text = "The item you are trying to secure does not exist or does not implement ISecured."; } } else { nbMessage.Text = string.Format("The requested entity type ('{0}') could not be loaded to determine security attributes.", entityTypeName); } base.OnInit(e); }
/// <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; var modelName = string.Empty; // get a service for the entity based off it's friendly name if (_entityName == "business") { modelName = "Rock.Model.Person"; } else { modelName = "Rock.Model." + _entityName; } // Check first to see if this is a core model. use the createIfNotFound = false option var entityTypeCache = EntityTypeCache.Get(modelName, false); if (entityTypeCache == null) { var entityTypes = EntityTypeCache.All(); // If not, look for first plug-in model that has same friendly name 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) { modelName = _entityName.Replace('_', '.'); entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, modelName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); } } if (entityTypeCache != null) { Type entityType = entityTypeCache.GetEntityType(); if (entityType != null) { // Get the appropriate database context for this entity type. // Note that this may be different from the standard RockContext if the entity is sourced from a plug-in. var dbContext = Reflection.GetDbContextForEntityType(entityType); // Check if there is a RockContext in the Lava context. If so then use the RockContext passed in. if (dbContext is RockContext) { var lavaContext = context.Registers["RockContext"]; if (lavaContext.IsNotNull()) { dbContext = (DbContext)lavaContext; } } // Disable change-tracking for this data context to improve performance - objects supplied to a Lava context are read-only. dbContext.Configuration.AutoDetectChangesEnabled = false; // Create an instance of the entity's service 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. /* [2020-10-08] DL * "Get" is intentionally used here rather than "GetNoTracking" to allow lazy-loading of navigation properties from the Lava context. * (Refer https://github.com/SparkDevNetwork/Rock/issues/4293) */ MethodInfo getMethod = serviceInstance.GetType().GetMethod("Get", new Type[] { typeof(ParameterExpression), typeof(Expression), typeof(Rock.Web.UI.Controls.SortProperty), typeof(int?) }); if (getMethod != null) { // get a listing of ids and build it into the query expression if (parms.Any(p => p.Key == "ids")) { List <int> value = parms["ids"].ToString().Split(',').Select(int.Parse).ToList(); MemberExpression propertyExpression = Expression.Property(paramExpression, "Id"); ConstantExpression constantExpression = Expression.Constant(value, typeof(List <int>)); Expression containsExpression = Expression.Call(constantExpression, typeof(List <int>).GetMethod("Contains", new Type[] { typeof(int) }), propertyExpression); if (queryExpression != null) { queryExpression = Expression.AndAlso(queryExpression, containsExpression); } else { queryExpression = containsExpression; } hasFilter = true; } var getResult = getMethod.Invoke(serviceInstance, new object[] { paramExpression, queryExpression, null, null }); var queryResult = getResult 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; } 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 attribute in AttributeCache.GetByEntityType(entityTypeCache.Id)) { if (attribute.Key == propertyName) { attributeId = attribute.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"; } } // 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."); } // 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 if enabled and entity is not a person (we do not check security on people) if (parms["securityenabled"].AsBoolean() && _entityName != "person") { 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); /* * 8/13/2020 - JME * It might seem logical to break out of the loop if there is limit parameter provided once the * limit is reached. This though has two issues. * * FIRST * Depending how it was implemented it can have the effect of breaking when an offset is * provided. * {% contentchannelitem where:'ContentChannelId == 1' limit:'3' %} * {% for item in contentchannelitemItems %} * {{ item.Id }} - {{ item.Title }}<br> * {% endfor %} * {% endcontentchannelitem %} * Returns 3 items (correct) * * {% contentchannelitem where:'ContentChannelId == 1' limit:'3' offset:'1' %} * {% for item in contentchannelitemItems %} * {{ item.Id }} - {{ item.Title }}<br> * {% endfor %} * {% endcontentchannelitem %} * Returns only 2 items (incorrect) - because of the offset * * SECOND * If the limit is moved before the security check it's possible that the security checks * will remove items and will therefore not give you the amount of items that you asked for. * * Unfortunately this has to be an inefficent process to ensure pagination works. I will also * add a detailed note to the documentation to encourage people to disable security checks, * especially when used with pagination, in the Lava docs. */ } } 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); } 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); }
protected override void OnInit(EventArgs e) { string entityParam = PageParameter("EntityTypeId"); Type type = null; // Get Entity Type int entityTypeId = 0; if (Int32.TryParse(entityParam, out entityTypeId)) { var entityType = EntityTypeCache.Read(entityTypeId); if (entityType != null) { entityParam = entityType.FriendlyName; type = entityType.GetEntityType(); } } // Get Entity Id int entityId = 0; if (!Int32.TryParse(PageParameter("EntityId"), out entityId)) { entityId = 0; } // Get object type if (type != null) { if (entityId == 0) { iSecured = (ISecured)Activator.CreateInstance(type); } else { // Get the context type since this may be for a non-rock core object Type contextType = null; var contexts = Rock.Reflection.SearchAssembly(type.Assembly, typeof(System.Data.Entity.DbContext)); if (contexts.Any()) { contextType = contexts.First().Value; } Type serviceType = typeof(Rock.Data.Service <>); Type[] modelType = { type }; Type service = serviceType.MakeGenericType(modelType); var getMethod = service.GetMethod("Get", new Type[] { typeof(int) }); if (contextType != null) { var context = Activator.CreateInstance(contextType); var serviceInstance = Activator.CreateInstance(service, new object[] { context }); iSecured = getMethod.Invoke(serviceInstance, new object[] { entityId }) as ISecured; } else { var serviceInstance = Activator.CreateInstance(service); iSecured = getMethod.Invoke(serviceInstance, new object[] { entityId }) as ISecured; } } var block = iSecured as Rock.Model.Block; if (block != null) { // If the entity is a block, get the cachedblock's supported action, as the RockPage may have // added additional actions when the cache was created. foreach (var action in BlockCache.Read(block.Id).SupportedActions) { if (!block.SupportedActions.Contains(action)) { block.SupportedActions.Add(action); } } iSecured = block; } if (iSecured != null && iSecured.IsAuthorized("Administrate", CurrentPerson)) { rptActions.DataSource = iSecured.SupportedActions; rptActions.DataBind(); rGrid.DataKeyNames = new string[] { "id" }; rGrid.GridReorder += new GridReorderEventHandler(rGrid_GridReorder); rGrid.GridRebind += new GridRebindEventHandler(rGrid_GridRebind); rGrid.RowDataBound += new GridViewRowEventHandler(rGrid_RowDataBound); rGrid.ShowHeaderWhenEmpty = false; rGrid.EmptyDataText = string.Empty; rGrid.ShowActionRow = false; rGridParentRules.DataKeyNames = new string[] { "id" }; rGridParentRules.ShowHeaderWhenEmpty = false; rGridParentRules.EmptyDataText = string.Empty; rGridParentRules.ShowActionRow = false; BindRoles(); string script = string.Format(@" Sys.Application.add_load(function () {{ $('#modal-popup div.modal-header h3 small', window.parent.document).html('{0}'); }}); ", HttpUtility.JavaScriptStringEncode(iSecured.ToString())); this.Page.ClientScript.RegisterStartupScript(this.GetType(), string.Format("set-html-{0}", this.ClientID), script, true); } else { rGrid.Visible = false; rGridParentRules.Visible = false; nbMessage.Text = "Unfortunately, you are not able to edit security because you do not belong to a role that has been configured to allow administration of this item."; nbMessage.Visible = true; } } else { rGrid.Visible = false; rGridParentRules.Visible = false; nbMessage.Text = string.Format("The requested entity type ('{0}') could not be loaded to determine security attributes.", entityParam); nbMessage.Visible = true; } base.OnInit(e); }
/// <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 plugin 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 Type contextType = null; Rock.Data.DbContext dbContext = null; var contexts = Rock.Reflection.SearchAssembly(entityType.Assembly, typeof(Rock.Data.DbContext)); if (contexts.Any()) { contextType = contexts.First().Value; dbContext = Activator.CreateInstance(contextType) as Rock.Data.DbContext; } if (dbContext == null) { dbContext = _rockContext; } // create an instance of the entity's service Type[] modelType = { entityType }; Type genericServiceType = typeof(Rock.Data.Service <>); Type modelServiceType = genericServiceType.MakeGenericType(modelType); Rock.Data.IService serviceInstance = Activator.CreateInstance(modelServiceType, new object[] { dbContext }) as IService; 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(PropertyComparisonConverstion("==").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; } } if (attributeId.HasValue) { // get AttributeValue queryable and parameter var attributeValues = _rockContext.Set <AttributeValue>(); 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); } } 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); }
protected override void OnInit(EventArgs e) { // Read parameter values string entityName = Authorization.DecodeEntityTypeName(PageParameter("EntityType")); int entityId = 0; if (!Int32.TryParse(PageParameter("EntityId"), out entityId)) { entityId = 0; } // Get object type Type type = Type.GetType(entityName); if (type != null) { if (entityId == 0) { iSecured = (ISecured)Activator.CreateInstance(type); } else { iSecured = type.InvokeMember("Read", System.Reflection.BindingFlags.InvokeMethod, null, type, new object[] { entityId }) as ISecured; } if (iSecured.IsAuthorized("Administrate", CurrentPerson)) { rptActions.DataSource = iSecured.SupportedActions; rptActions.DataBind(); rGrid.DataKeyNames = new string[] { "id" }; rGrid.GridReorder += new GridReorderEventHandler(rGrid_GridReorder); rGrid.GridRebind += new GridRebindEventHandler(rGrid_GridRebind); rGrid.RowDataBound += new GridViewRowEventHandler(rGrid_RowDataBound); rGrid.ShowHeaderWhenEmpty = false; rGrid.EmptyDataText = string.Empty; rGrid.ShowActionRow = false; rGridParentRules.DataKeyNames = new string[] { "id" }; rGridParentRules.ShowHeaderWhenEmpty = false; rGridParentRules.EmptyDataText = string.Empty; rGridParentRules.ShowActionRow = false; BindRoles(); string script = string.Format(@" Sys.Application.add_load(function () {{ $('#modal-popup div.modal-header h3 small', window.parent.document).html('{0}'); }}); ", iSecured.ToString()); this.Page.ClientScript.RegisterStartupScript(this.GetType(), string.Format("set-html-{0}", this.ClientID), script, true); } } else { rGrid.Visible = false; rGridParentRules.Visible = false; nbMessage.Text = string.Format("Could not load the requested entity type ('{0}') to determine security attributes", entityName); nbMessage.Visible = true; } base.OnInit(e); }