Merge pull request #4210 from umbraco/temp8-fixme-get-all-entities-with-postfilter

Fixme - Handle not implemented exception on pick of macro
This commit is contained in:
Shannon Deminick
2019-01-31 14:51:55 +11:00
committed by GitHub
10 changed files with 222 additions and 113 deletions
@@ -254,22 +254,13 @@ function entityResource($q, $http, umbRequestHelper) {
*
* @param {string} type Object type name
* @param {string} postFilter optional filter expression which will execute a dynamic where clause on the server
* @param {string} postFilterParams optional parameters for the postFilter expression
* @returns {Promise} resourcePromise object containing the entity.
*
*/
getAll: function (type, postFilter, postFilterParams) {
getAll: function (type, postFilter) {
//need to build the query string manually
var query = "type=" + type + "&postFilter=" + (postFilter ? postFilter : "");
if (postFilter && postFilterParams) {
var counter = 0;
_.each(postFilterParams, function(val, key) {
query += "&postFilterParams[" + counter + "].key=" + key + "&postFilterParams[" + counter + "].value=" + val;
counter++;
});
}
var query = "type=" + type + "&postFilter=" + (postFilter ? encodeURIComponent(postFilter) : "");
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
@@ -130,6 +130,10 @@ function macroService() {
var paramDictionary = {};
var macroAlias = macro.alias;
if (!macroAlias) {
throw "The macro object does not contain an alias";
}
var syntax;
_.each(macroParams, function (item) {
@@ -1346,7 +1346,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
dialogData: dialogData,
submit: function (model) {
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, dialogData.renderingEngine);
self.insertMacroInEditor(args.editor, macroObject, $scope);
self.insertMacroInEditor(args.editor, macroObject);
editorService.close();
},
close: function () {
@@ -88,7 +88,7 @@
type="button"
button-style="success"
label-key="general_submit"
action="selectMacro(model)">
action="selectMacro(model.selectedMacro)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
+103 -28
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Web.Http;
using AutoMapper;
@@ -11,11 +10,10 @@ using Umbraco.Web.Mvc;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Reflection;
using Umbraco.Core.Models;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using System.Web.Http.Controllers;
using Examine;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
@@ -24,12 +22,14 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Core.Xml;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.Models.TemplateQuery;
using Umbraco.Web.Search;
using Umbraco.Web.Services;
using Umbraco.Web.Trees;
using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Editors
{
/// <summary>
@@ -242,7 +242,7 @@ namespace Umbraco.Web.Editors
};
}
/// <summary>
/// Gets an entity by a xpath query
/// </summary>
@@ -863,9 +863,15 @@ namespace Umbraco.Web.Editors
}
}
public IEnumerable<EntityBasic> GetAll(UmbracoEntityTypes type, string postFilter, [FromUri]IDictionary<string, object> postFilterParams)
/// <summary>
///
/// </summary>
/// <param name="type">The type of entity.</param>
/// <param name="postFilter">Optional filter - Format like: "BoolVariable==true&IntVariable>=6". Invalid filters are ignored.</param>
/// <returns></returns>
public IEnumerable<EntityBasic> GetAll(UmbracoEntityTypes type, string postFilter)
{
return GetResultForAll(type, postFilter, postFilterParams);
return GetResultForAll(type, postFilter);
}
/// <summary>
@@ -873,29 +879,28 @@ namespace Umbraco.Web.Editors
/// </summary>
/// <param name="entityType"></param>
/// <param name="postFilter">A string where filter that will filter the results dynamically with linq - optional</param>
/// <param name="postFilterParams">the parameters to fill in the string where filter - optional</param>
/// <returns></returns>
private IEnumerable<EntityBasic> GetResultForAll(UmbracoEntityTypes entityType, string postFilter = null, IDictionary<string, object> postFilterParams = null)
private IEnumerable<EntityBasic> GetResultForAll(UmbracoEntityTypes entityType, string postFilter = null)
{
var objectType = ConvertToObjectType(entityType);
if (objectType.HasValue)
{
// TODO: Should we order this by something ?
var entities = Services.EntityService.GetAll(objectType.Value).WhereNotNull().Select(Mapper.Map<EntityBasic>);
return ExecutePostFilter(entities, postFilter, postFilterParams);
return ExecutePostFilter(entities, postFilter);
}
//now we need to convert the unknown ones
switch (entityType)
{
case UmbracoEntityTypes.Template:
var templates = Services.FileService.GetTemplates();
var filteredTemplates = ExecutePostFilter(templates, postFilter, postFilterParams);
var filteredTemplates = ExecutePostFilter(templates, postFilter);
return filteredTemplates.Select(Mapper.Map<EntityBasic>);
case UmbracoEntityTypes.Macro:
//Get all macros from the macro service
var macros = Services.MacroService.GetAll().WhereNotNull().OrderBy(x => x.Name);
var filteredMacros = ExecutePostFilter(macros, postFilter, postFilterParams);
var filteredMacros = ExecutePostFilter(macros, postFilter);
return filteredMacros.Select(Mapper.Map<EntityBasic>);
case UmbracoEntityTypes.PropertyType:
@@ -906,7 +911,7 @@ namespace Umbraco.Web.Editors
.ToArray()
.SelectMany(x => x.PropertyTypes)
.DistinctBy(composition => composition.Alias);
var filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter, postFilterParams);
var filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter);
return Mapper.Map<IEnumerable<PropertyType>, IEnumerable<EntityBasic>>(filteredPropertyTypes);
case UmbracoEntityTypes.PropertyGroup:
@@ -917,32 +922,32 @@ namespace Umbraco.Web.Editors
.ToArray()
.SelectMany(x => x.PropertyGroups)
.DistinctBy(composition => composition.Name);
var filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter, postFilterParams);
var filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter);
return Mapper.Map<IEnumerable<PropertyGroup>, IEnumerable<EntityBasic>>(filteredpropertyGroups);
case UmbracoEntityTypes.User:
var users = Services.UserService.GetAll(0, int.MaxValue, out _);
var filteredUsers = ExecutePostFilter(users, postFilter, postFilterParams);
var filteredUsers = ExecutePostFilter(users, postFilter);
return Mapper.Map<IEnumerable<IUser>, IEnumerable<EntityBasic>>(filteredUsers);
case UmbracoEntityTypes.Stylesheet:
if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0))
if (!postFilter.IsNullOrWhiteSpace())
throw new NotSupportedException("Filtering on stylesheets is not currently supported");
return Services.FileService.GetStylesheets().Select(Mapper.Map<EntityBasic>);
case UmbracoEntityTypes.Language:
if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0))
if (!postFilter.IsNullOrWhiteSpace() )
throw new NotSupportedException("Filtering on languages is not currently supported");
return Services.LocalizationService.GetAllLanguages().Select(Mapper.Map<EntityBasic>);
case UmbracoEntityTypes.DictionaryItem:
if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0))
throw new NotSupportedException("Filtering on languages is not currently supported");
if (!postFilter.IsNullOrWhiteSpace())
throw new NotSupportedException("Filtering on dictionary items is not currently supported");
return GetAllDictionaryItems();
@@ -952,20 +957,90 @@ namespace Umbraco.Web.Editors
}
}
private IEnumerable<T> ExecutePostFilter<T>(IEnumerable<T> entities, string postFilter, IDictionary<string, object> postFilterParams)
private IEnumerable<T> ExecutePostFilter<T>(IEnumerable<T> entities, string postFilter)
{
// if a post filter is assigned then try to execute it
if (postFilter.IsNullOrWhiteSpace() == false)
if (postFilter.IsNullOrWhiteSpace()) return entities;
var postFilterConditions = postFilter.Split('&');
foreach (var postFilterCondition in postFilterConditions)
{
// FIXME: task/critical - trouble is, we've killed the dynamic Where thing!
throw new NotImplementedException("oops");
//return postFilterParams == null
// ? entities.AsQueryable().Where(postFilter).ToArray()
// : entities.AsQueryable().Where(postFilter, postFilterParams).ToArray();
var queryCondition = BuildQueryCondition<T>(postFilterCondition);
if (queryCondition != null)
{
var whereClauseExpression = queryCondition.BuildCondition<T>("x");
entities = entities.Where(whereClauseExpression.Compile());
}
}
return entities;
}
private static QueryCondition BuildQueryCondition<T>(string postFilter)
{
var postFilterParts = postFilter.Split(new[]
{
"=",
"==",
"!=",
"<>",
">",
"<",
">=",
"<="
}, 2, StringSplitOptions.RemoveEmptyEntries);
if (postFilterParts.Length != 2)
{
return null;
}
var propertyName = postFilterParts[0];
var constraintValue = postFilterParts[1];
var stringOperator = postFilter.Substring(propertyName.Length,
postFilter.Length - propertyName.Length - constraintValue.Length);
Operator binaryOperator;
try
{
binaryOperator = OperatorFactory.FromString(stringOperator);
}
catch (ArgumentException)
{
// unsupported operators are ignored
return null;
}
var type = typeof(T);
var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (property == null)
{
return null;
}
var queryCondition = new QueryCondition()
{
Term = new OperatorTerm()
{
Operator = binaryOperator
},
ConstraintValue = constraintValue,
Property = new PropertyModel()
{
Alias = propertyName,
Name = propertyName,
Type = property.PropertyType.Name
}
};
return queryCondition;
}
#region Methods to get all dictionary items
private IEnumerable<EntityBasic> GetAllDictionaryItems()
@@ -993,7 +1068,7 @@ namespace Umbraco.Web.Editors
GetChildItemsForList(childItem, list);
}
}
}
#endregion
}
@@ -118,7 +118,7 @@ namespace Umbraco.Web.Editors
foreach (var condition in model.Filters.Where(x => !x.ConstraintValue.IsNullOrWhiteSpace()))
{
//x is passed in as the parameter alias for the linq where statement clause
var operation = condition.BuildCondition("x", contents, Properties);
var operation = condition.BuildCondition<IPublishedContent>("x");
//for review - this uses a tonized query rather then the normal linq query.
contents = contents.Where(operation.Compile());
@@ -0,0 +1,32 @@
using System;
namespace Umbraco.Web.Models.TemplateQuery
{
internal static class OperatorFactory
{
public static Operator FromString(string stringOperator)
{
if (stringOperator == null) throw new ArgumentNullException(nameof(stringOperator));
switch (stringOperator)
{
case "=":
case "==":
return Operator.Equals;
case "!=":
case "<>":
return Operator.NotEquals;
case "<":
return Operator.LessThan;
case "<=":
return Operator.LessThanEqualTo;
case ">":
return Operator.GreaterThan;
case ">=":
return Operator.GreaterThanEqualTo;
default:
throw new ArgumentException($"A operator cannot be created from the specified string '{stringOperator}'", nameof(stringOperator));
}
}
}
}
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Generic;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models.TemplateQuery
@@ -12,70 +9,4 @@ namespace Umbraco.Web.Models.TemplateQuery
public OperatorTerm Term { get; set; }
public string ConstraintValue { get; set; }
}
internal static class QueryConditionExtensions
{
private static Lazy<MethodInfo> StringContainsMethodInfo =>
new Lazy<MethodInfo>(() => typeof(string).GetMethod("Contains", new[] {typeof(string)}));
public static Expression<Func<IPublishedContent, bool>> BuildCondition(this QueryCondition condition,
string parameterAlias, IEnumerable<IPublishedContent> contents, IEnumerable<PropertyModel> properties)
{
object constraintValue;
switch (condition.Property.Type)
{
case "string":
constraintValue = condition.ConstraintValue;
break;
case "datetime":
constraintValue = DateTime.Parse(condition.ConstraintValue);
break;
default:
constraintValue = Convert.ChangeType(condition.ConstraintValue, typeof(int));
break;
}
var parameterExpression = Expression.Parameter(typeof(IPublishedContent), parameterAlias);
var propertyExpression = Expression.Property(parameterExpression, condition.Property.Alias);
var valueExpression = Expression.Constant(constraintValue);
Expression bodyExpression;
switch (condition.Term.Operator)
{
case Operator.NotEquals:
bodyExpression = Expression.NotEqual(propertyExpression, valueExpression);
break;
case Operator.GreaterThan:
bodyExpression = Expression.GreaterThan(propertyExpression, valueExpression);
break;
case Operator.GreaterThanEqualTo:
bodyExpression = Expression.GreaterThanOrEqual(propertyExpression, valueExpression);
break;
case Operator.LessThan:
bodyExpression = Expression.LessThan(propertyExpression, valueExpression);
break;
case Operator.LessThanEqualTo:
bodyExpression = Expression.LessThanOrEqual(propertyExpression, valueExpression);
break;
case Operator.Contains:
bodyExpression = Expression.Call(propertyExpression, StringContainsMethodInfo.Value,
valueExpression);
break;
case Operator.NotContains:
var tempExpression = Expression.Call(propertyExpression, StringContainsMethodInfo.Value,
valueExpression);
bodyExpression = Expression.Equal(tempExpression, Expression.Constant(false));
break;
default:
case Operator.Equals:
bodyExpression = Expression.Equal(propertyExpression, valueExpression);
break;
}
var predicate =
Expression.Lambda<Func<IPublishedContent, bool>>(bodyExpression.Reduce(), parameterExpression);
return predicate;
}
}
}
@@ -0,0 +1,74 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Umbraco.Web.Models.TemplateQuery
{
internal static class QueryConditionExtensions
{
private static Lazy<MethodInfo> StringContainsMethodInfo =>
new Lazy<MethodInfo>(() => typeof(string).GetMethod("Contains", new[] {typeof(string)}));
public static Expression<Func<T, bool>> BuildCondition<T>(this QueryCondition condition, string parameterAlias)
{
object constraintValue;
switch (condition.Property.Type.ToLowerInvariant())
{
case "string":
constraintValue = condition.ConstraintValue;
break;
case "datetime":
constraintValue = DateTime.Parse(condition.ConstraintValue);
break;
case "boolean":
constraintValue = Boolean.Parse(condition.ConstraintValue);
break;
default:
constraintValue = Convert.ChangeType(condition.ConstraintValue, typeof(int));
break;
}
var parameterExpression = Expression.Parameter(typeof(T), parameterAlias);
var propertyExpression = Expression.Property(parameterExpression, condition.Property.Alias);
var valueExpression = Expression.Constant(constraintValue);
Expression bodyExpression;
switch (condition.Term.Operator)
{
case Operator.NotEquals:
bodyExpression = Expression.NotEqual(propertyExpression, valueExpression);
break;
case Operator.GreaterThan:
bodyExpression = Expression.GreaterThan(propertyExpression, valueExpression);
break;
case Operator.GreaterThanEqualTo:
bodyExpression = Expression.GreaterThanOrEqual(propertyExpression, valueExpression);
break;
case Operator.LessThan:
bodyExpression = Expression.LessThan(propertyExpression, valueExpression);
break;
case Operator.LessThanEqualTo:
bodyExpression = Expression.LessThanOrEqual(propertyExpression, valueExpression);
break;
case Operator.Contains:
bodyExpression = Expression.Call(propertyExpression, StringContainsMethodInfo.Value,
valueExpression);
break;
case Operator.NotContains:
var tempExpression = Expression.Call(propertyExpression, StringContainsMethodInfo.Value,
valueExpression);
bodyExpression = Expression.Equal(tempExpression, Expression.Constant(false));
break;
default:
case Operator.Equals:
bodyExpression = Expression.Equal(propertyExpression, valueExpression);
break;
}
var predicate =
Expression.Lambda<Func<T, bool>>(bodyExpression.Reduce(), parameterExpression);
return predicate;
}
}
}
+2
View File
@@ -182,10 +182,12 @@
<Compile Include="Models\ContentEditing\LinkDisplay.cs" />
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
<Compile Include="Models\TemplateQuery\QueryConditionExtensions.cs" />
<Compile Include="Services\DashboardService.cs" />
<Compile Include="Services\IDashboardService.cs" />
<Compile Include="Models\Link.cs" />
<Compile Include="Models\LinkType.cs" />
<Compile Include="Models\TemplateQuery\OperatorFactory.cs" />
<Compile Include="Mvc\OnlyLocalRequestsAttribute.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerConfiguration.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerConfigurationEditor.cs" />