Adds dynamic filtering to EntityService (post filtering for GetAll) - updated the insert macro dialog to ensure that it only shows macros flagged for the rte when in rte mode, otherwise shows all of them. adds unit tests for dynamic queryable stuff.
This commit is contained in:
@@ -57,5 +57,7 @@ namespace Umbraco.Core.Dynamics
|
||||
.Invoke(null, new object[] { source, lambda });
|
||||
return (IOrderedQueryable<T>)result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
162
src/Umbraco.Tests/Dynamics/QueryableExtensionTests.cs
Normal file
162
src/Umbraco.Tests/Dynamics/QueryableExtensionTests.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Web.Dynamics;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Tests.Dynamics
|
||||
{
|
||||
//NOTE: there's libraries in both Umbraco.Core.Dynamics and Umbraco.Web.Dynamics - the reason for this is that the Web.Dynamics
|
||||
// started with the razor macro implementation and is modified with hard coded references to dynamic node and dynamic null, though it seems
|
||||
// to still work for other regular classes I don't want to move it to the core without removing these references but that would require a lot of work.
|
||||
|
||||
[TestFixture]
|
||||
public class QueryableExtensionTests
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Order_By_Test_Int()
|
||||
{
|
||||
var items = new List<TestModel>
|
||||
{
|
||||
new TestModel {Age = 10, Name = "test1", Female = false},
|
||||
new TestModel {Age = 31, Name = "someguy", Female = true},
|
||||
new TestModel {Age = 11, Name = "test2", Female = true},
|
||||
new TestModel {Age = 20, Name = "anothertest", Female = false},
|
||||
new TestModel {Age = 55, Name = "blah", Female = false},
|
||||
new TestModel {Age = 12, Name = "test3", Female = false}
|
||||
};
|
||||
|
||||
var result = items.AsQueryable().OrderBy("Age").ToArray();
|
||||
|
||||
Assert.AreEqual(10, result.ElementAt(0).Age);
|
||||
Assert.AreEqual(11, result.ElementAt(1).Age);
|
||||
Assert.AreEqual(12, result.ElementAt(2).Age);
|
||||
Assert.AreEqual(20, result.ElementAt(3).Age);
|
||||
Assert.AreEqual(31, result.ElementAt(4).Age);
|
||||
Assert.AreEqual(55, result.ElementAt(5).Age);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Order_By_Test_String()
|
||||
{
|
||||
var items = new List<TestModel>
|
||||
{
|
||||
new TestModel {Age = 10, Name = "test1", Female = false},
|
||||
new TestModel {Age = 31, Name = "someguy", Female = true},
|
||||
new TestModel {Age = 11, Name = "test2", Female = true},
|
||||
new TestModel {Age = 20, Name = "anothertest", Female = false},
|
||||
new TestModel {Age = 55, Name = "blah", Female = false},
|
||||
new TestModel {Age = 12, Name = "test3", Female = false}
|
||||
};
|
||||
|
||||
var result = items.AsQueryable().OrderBy("Name").ToArray();
|
||||
|
||||
Assert.AreEqual("anothertest", result.ElementAt(0).Name);
|
||||
Assert.AreEqual("blah", result.ElementAt(1).Name);
|
||||
Assert.AreEqual("someguy", result.ElementAt(2).Name);
|
||||
Assert.AreEqual("test1", result.ElementAt(3).Name);
|
||||
Assert.AreEqual("test2", result.ElementAt(4).Name);
|
||||
Assert.AreEqual("test3", result.ElementAt(5).Name);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Test_String()
|
||||
{
|
||||
var items = new List<TestModel>
|
||||
{
|
||||
new TestModel {Age = 10, Name = "test1", Female = false},
|
||||
new TestModel {Age = 31, Name = "someguy", Female = true},
|
||||
new TestModel {Age = 11, Name = "test2", Female = true},
|
||||
new TestModel {Age = 20, Name = "anothertest", Female = false},
|
||||
new TestModel {Age = 55, Name = "blah", Female = false},
|
||||
new TestModel {Age = 12, Name = "test3", Female = false}
|
||||
};
|
||||
|
||||
var result = items.AsQueryable().Where("Name = \"test1\"").ToArray();
|
||||
|
||||
Assert.AreEqual(1, result.Count());
|
||||
Assert.AreEqual("test1", result.ElementAt(0).Name);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Test_String_With_Params()
|
||||
{
|
||||
var items = new List<TestModel>
|
||||
{
|
||||
new TestModel {Age = 10, Name = "test1", Female = false},
|
||||
new TestModel {Age = 31, Name = "someguy", Female = true},
|
||||
new TestModel {Age = 11, Name = "test2", Female = true},
|
||||
new TestModel {Age = 20, Name = "anothertest", Female = false},
|
||||
new TestModel {Age = 55, Name = "blah", Female = false},
|
||||
new TestModel {Age = 12, Name = "test3", Female = false}
|
||||
};
|
||||
|
||||
//NOTE: Currently the object query structure is not supported
|
||||
//var result = items.AsQueryable().Where("Name = @name", new {name = "test1"}).ToArray();
|
||||
var result = items.AsQueryable().Where("Name = @Name", new Dictionary<string, object> { { "Name", "test1" } }).ToArray();
|
||||
|
||||
Assert.AreEqual(1, result.Count());
|
||||
Assert.AreEqual("test1", result.ElementAt(0).Name);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Test_Int_With_Params()
|
||||
{
|
||||
var items = new List<TestModel>
|
||||
{
|
||||
new TestModel {Age = 10, Name = "test1", Female = false},
|
||||
new TestModel {Age = 31, Name = "someguy", Female = true},
|
||||
new TestModel {Age = 11, Name = "test2", Female = true},
|
||||
new TestModel {Age = 20, Name = "anothertest", Female = false},
|
||||
new TestModel {Age = 55, Name = "blah", Female = false},
|
||||
new TestModel {Age = 12, Name = "test3", Female = false}
|
||||
};
|
||||
|
||||
var result = items.AsQueryable().Where("Age = @Age", new Dictionary<string, object> { { "Age", 10 } }).ToArray();
|
||||
|
||||
Assert.AreEqual(1, result.Count());
|
||||
Assert.AreEqual("test1", result.ElementAt(0).Name);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_Test_Bool_With_Params()
|
||||
{
|
||||
var items = new List<TestModel>
|
||||
{
|
||||
new TestModel {Age = 10, Name = "test1", Female = false},
|
||||
new TestModel {Age = 31, Name = "someguy", Female = true},
|
||||
new TestModel {Age = 11, Name = "test2", Female = true},
|
||||
new TestModel {Age = 20, Name = "anothertest", Female = false},
|
||||
new TestModel {Age = 55, Name = "blah", Female = false},
|
||||
new TestModel {Age = 12, Name = "test3", Female = false}
|
||||
};
|
||||
|
||||
var result = items.AsQueryable().Where("Female = @Female", new Dictionary<string, object> { { "Female", true } }).ToArray();
|
||||
|
||||
Assert.AreEqual(2, result.Count());
|
||||
|
||||
|
||||
}
|
||||
|
||||
private class TestModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public bool Female { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -237,6 +237,7 @@
|
||||
<Compile Include="Controllers\WebApiEditors\FilterAllowedOutgoingContentAttributeTests.cs" />
|
||||
<Compile Include="Controllers\WebApiEditors\MediaControllerUnitTests.cs" />
|
||||
<Compile Include="CoreXml\FrameworkXmlTests.cs" />
|
||||
<Compile Include="Dynamics\QueryableExtensionTests.cs" />
|
||||
<Compile Include="Integration\CreateContent.cs" />
|
||||
<Compile Include="Macros\MacroParserTests.cs" />
|
||||
<Compile Include="Migrations\Upgrades\ValidateV7UpgradeTest.cs" />
|
||||
|
||||
@@ -128,16 +128,29 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* </pre>
|
||||
*
|
||||
* @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) {
|
||||
getAll: function (type, postFilter, postFilterParams) {
|
||||
|
||||
//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++;
|
||||
});
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetAll",
|
||||
[{type: type }])),
|
||||
query)),
|
||||
'Failed to retreive entity data for type ' + type);
|
||||
},
|
||||
|
||||
|
||||
@@ -216,6 +216,12 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou
|
||||
|
||||
}
|
||||
|
||||
/** when the contents load we need to find any macros declared and load in their content */
|
||||
editor.on("LoadContent", function(o) {
|
||||
var asdf = editor.getContent();
|
||||
alert(asdf);
|
||||
});
|
||||
|
||||
/** This prevents any other commands from executing when the current element is the macro so the content cannot be edited */
|
||||
editor.on('BeforeExecCommand', function (o) {
|
||||
if (isOnMacroElement) {
|
||||
@@ -310,7 +316,10 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou
|
||||
/** The insert macro button click event handler */
|
||||
onclick: function () {
|
||||
|
||||
var dialogData;
|
||||
var dialogData = {
|
||||
//flag for use in rte so we only show macros flagged for the editor
|
||||
richTextEditor: true
|
||||
};
|
||||
|
||||
//when we click we could have a macro already selected and in that case we'll want to edit the current parameters
|
||||
//so we'll need to extract them and submit them to the dialog.
|
||||
|
||||
@@ -104,8 +104,8 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi
|
||||
$scope.wizardStep = "paramSelect";
|
||||
}
|
||||
|
||||
//get the macro list
|
||||
entityResource.getAll("Macro")
|
||||
//get the macro list - pass in a filter if it is only for rte
|
||||
entityResource.getAll("Macro", ($scope.dialogData && $scope.dialogData.richTextEditor && $scope.dialogData.richTextEditor === true) ? "UseInEditor=true" : null)
|
||||
.then(function (data) {
|
||||
|
||||
$scope.macros = data;
|
||||
|
||||
@@ -11,6 +11,11 @@ using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
//TODO: Much of this can move to Umbraco.Core.Dynamics - but somehow need to remove all the hard coded references to things like
|
||||
// dynamicnull, etc...
|
||||
//NOTE: The OrderBy stuff here seems to be a bit hacked with hard references to umbraco node objects so don't think it can be
|
||||
// re-used which is why we have the OrderBy stuff that hasn't been hacked in teh Umbraco.Core.Dynamics
|
||||
|
||||
internal static class DynamicQueryable
|
||||
{
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
//SD: I wish all of this wasn't hacked and was just the original dynamic linq from MS... sigh. Just
|
||||
// means we can't really use it for anything other than dynamic node (i think)
|
||||
// I'm fairly sure it's just hte convert to dynamic null stuff... still seems to work for normal linq operations would love to make it
|
||||
// properly one day.
|
||||
|
||||
internal class ExpressionParser<T>
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@ using Constants = Umbraco.Core.Constants;
|
||||
using Examine;
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Examine.SearchCriteria;
|
||||
using Umbraco.Web.Dynamics;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -69,9 +70,9 @@ namespace Umbraco.Web.Editors
|
||||
return GetResultForAncestors(id, type);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityBasic> GetAll(UmbracoEntityTypes type)
|
||||
public IEnumerable<EntityBasic> GetAll(UmbracoEntityTypes type, string postFilter, [FromUri]IDictionary<string, object> postFilterParams)
|
||||
{
|
||||
return GetResultForAll(type);
|
||||
return GetResultForAll(type, postFilter, postFilterParams);
|
||||
}
|
||||
|
||||
private IEnumerable<EntityBasic> ExamineSearch(string query, bool isContent)
|
||||
@@ -147,20 +148,49 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<EntityBasic> GetResultForAll(UmbracoEntityTypes entityType)
|
||||
/// <summary>
|
||||
/// Gets the result for the entity list based on the type
|
||||
/// </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)
|
||||
{
|
||||
var objectType = ConvertToObjectType(entityType);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
return Services.EntityService.GetAll(objectType.Value).Select(Mapper.Map<EntityBasic>)
|
||||
.WhereNotNull();
|
||||
//TODO: Should we order this by something ?
|
||||
var entities = Services.EntityService.GetAll(objectType.Value).WhereNotNull().Select(Mapper.Map<EntityBasic>);
|
||||
|
||||
//if a post filter is assigned then try to execute it
|
||||
if (postFilter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
return postFilterParams == null
|
||||
? entities.AsQueryable().Where(postFilter).ToArray()
|
||||
: entities.AsQueryable().Where(postFilter, postFilterParams).ToArray();
|
||||
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
//now we need to convert the unknown ones
|
||||
switch (entityType)
|
||||
{
|
||||
case UmbracoEntityTypes.Macro:
|
||||
//Get all macros from the macro service
|
||||
return Services.MacroService.GetAll().OrderBy(x => x.Name).Select(Mapper.Map<EntityBasic>);
|
||||
var result = Services.MacroService.GetAll().WhereNotNull().OrderBy(x => x.Name).AsQueryable();
|
||||
|
||||
//if a post filter is assigned then try to execute it
|
||||
if (postFilter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
result = postFilterParams == null
|
||||
? result.Where(postFilter)
|
||||
: result.Where(postFilter, postFilterParams);
|
||||
|
||||
}
|
||||
|
||||
return result.Select(Mapper.Map<EntityBasic>);
|
||||
|
||||
case UmbracoEntityTypes.Domain:
|
||||
|
||||
case UmbracoEntityTypes.Language:
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace Umbraco.Web.Editors
|
||||
[PluginController("UmbracoApi")]
|
||||
public class MacroController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the macro parameters to be filled in for a particular macro
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user