This commit is contained in:
@@ -13,9 +13,21 @@ and also lists all the fields filterable, their type and the locale key to displ
|
|||||||
- e.g.: {list:"widget",fields:[{fld:"name",lt:"WidgetName",type:"text"},{fld:"dollarAmount",lt:"WidgetDollarAmount",type:"currency"}]}
|
- e.g.: {list:"widget",fields:[{fld:"name",lt:"WidgetName",type:"text"},{fld:"dollarAmount",lt:"WidgetDollarAmount",type:"currency"}]}
|
||||||
Certain types have extended abilities, for example dates have the classic floating AyaNova date ranges pre-defined or specific dates
|
Certain types have extended abilities, for example dates have the classic floating AyaNova date ranges pre-defined or specific dates
|
||||||
Filters are saved to the database:
|
Filters are saved to the database:
|
||||||
- Filter: Name, OwnerId, Public, ListKey, Filter (Json string) (column names to be determined)
|
- Filter: Name, OwnerId, Public, ListKey, Filter (Json string)
|
||||||
- i.e. "My widget filter", 1, true, "widget", "[{fld:"name",comparisonoperator:"Like",value:"Bob*"},{fld:"tags",comparisonoperator:"Eq",value:"[23,456,54]"}]
|
- Filter format:
|
||||||
- means all widgets that start with the name "Bob" and are tagged with tags with id values 23, 456 and 54
|
- Array [{fld:"fieldname",op:"See filtercomparisonoperator class",value:"compareValue"},...] these are all AND in sql, no OR
|
||||||
|
- fld=name of field to filter by
|
||||||
|
- Straight up field name like "name"
|
||||||
|
- Could be compound for joins like "table.name" (no a prepends the table name)
|
||||||
|
- Special indirect values such as "[TAGS]" which means cross filter with tags
|
||||||
|
- op=one of the values specified in the FilterComparisonOperator class in Biz namespace
|
||||||
|
- value= straight up direct comparison value
|
||||||
|
- If string then a string fragment, case is sensitive
|
||||||
|
- If date then iso style date
|
||||||
|
- could be whole number or decimal number
|
||||||
|
- Could be a special "macro" filter value like "[THIS_MONTH]" (always surrounded by square brackets, no need to disambiguate with a string because only applies to non string values)
|
||||||
|
- Could be a series of id values like this "[23,45,56,123]" as in tag id's or something related to that case.
|
||||||
|
|
||||||
Upon user selecting a filter to use the list query string has the regular paging info but also the filter id as a query parameter
|
Upon user selecting a filter to use the list query string has the regular paging info but also the filter id as a query parameter
|
||||||
- Server loads the filter if it's public or has the user ID if it's personal only
|
- Server loads the filter if it's public or has the user ID if it's personal only
|
||||||
- If list not found then it will return a 404 instead of the list
|
- If list not found then it will return a 404 instead of the list
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.JsonPatch;
|
using Microsoft.AspNetCore.JsonPatch;
|
||||||
using EnumsNET;
|
using EnumsNET;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using AyaNova.Util;
|
using AyaNova.Util;
|
||||||
using AyaNova.Api.ControllerHelpers;
|
using AyaNova.Api.ControllerHelpers;
|
||||||
using AyaNova.Biz;
|
using AyaNova.Biz;
|
||||||
@@ -221,9 +222,9 @@ namespace AyaNova.Biz
|
|||||||
AddError(ValidationErrorType.RequiredPropertyEmpty, "OwnerId");
|
AddError(ValidationErrorType.RequiredPropertyEmpty, "OwnerId");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Owner must be current user, there are no exceptions
|
// //Owner must be current user, there are no exceptions
|
||||||
if (inObj.OwnerId != UserId)
|
// if (inObj.OwnerId != UserId)
|
||||||
AddError(ValidationErrorType.InvalidValue, "OwnerId", "OwnerId must be current user Id");
|
// AddError(ValidationErrorType.InvalidValue, "OwnerId", "OwnerId must be current user Id");
|
||||||
|
|
||||||
//Name required
|
//Name required
|
||||||
if (string.IsNullOrWhiteSpace(inObj.Name))
|
if (string.IsNullOrWhiteSpace(inObj.Name))
|
||||||
@@ -249,6 +250,30 @@ namespace AyaNova.Biz
|
|||||||
if (inObj.ListKey.Length > 255)
|
if (inObj.ListKey.Length > 255)
|
||||||
AddError(ValidationErrorType.LengthExceeded, "ListKey", "255 max");
|
AddError(ValidationErrorType.LengthExceeded, "ListKey", "255 max");
|
||||||
|
|
||||||
|
//Filter json must parse
|
||||||
|
if (!string.IsNullOrWhiteSpace(inObj.Filter))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var v = JArray.Parse(inObj.Filter);
|
||||||
|
for (int i = 0; i < v.Count; i++)
|
||||||
|
{
|
||||||
|
var filterItem = v[i];
|
||||||
|
if (filterItem["fld"] == null)
|
||||||
|
AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, object is missing required \"fld\" property ");
|
||||||
|
if (filterItem["op"] == null)
|
||||||
|
AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, object is missing required \"op\" property ");
|
||||||
|
if (filterItem["value"] == null)
|
||||||
|
AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, object is missing required \"value\" property ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Newtonsoft.Json.JsonReaderException ex)
|
||||||
|
{
|
||||||
|
AddError(ValidationErrorType.InvalidValue, "Filter", "Filter is not valid JSON string: " + ex.Message);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,97 +17,91 @@ namespace raven_integration
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void CRUD()
|
public async void CRUD()
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
{
|
|
||||||
"id": 0,
|
|
||||||
"concurrencyToken": 0,
|
|
||||||
"ownerId": 0,
|
|
||||||
"name": "string",
|
|
||||||
"public": true,
|
|
||||||
"listKey": "string",
|
|
||||||
"filter": "string"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//CREATE
|
//CREATE
|
||||||
dynamic d = new JObject();
|
dynamic d = new JObject();
|
||||||
d.name = Util.Uniquify("Test DataFilter");
|
d.name = Util.Uniquify("Test DataFilter");
|
||||||
d.ownerId = 1L;
|
// d.ownerId = 1L;
|
||||||
d.listKey="Widget";
|
d["public"] = true;
|
||||||
d.filter="";
|
d.listKey = "Widget";
|
||||||
|
|
||||||
ApiResponse a = await Util.PostAsync("Tag", await Util.GetTokenAsync("BizAdminFull"), d.ToString());
|
//"[{fld:"name",op:"!=",value:"Notequaltothis"},{fld:"tags",op:"Eq",value:"[23,456,54]"}]
|
||||||
|
dynamic dfilter = new JArray();
|
||||||
|
dynamic df = new JObject();
|
||||||
|
df.fld = "name";
|
||||||
|
df.op = "%-";
|
||||||
|
df.value = "Generic";//lots of seed widgets start with Generic
|
||||||
|
dfilter.Add(df);
|
||||||
|
|
||||||
|
d.filter=dfilter.ToString();//it expects it to be a json string, not actual json
|
||||||
|
|
||||||
|
ApiResponse a = await Util.PostAsync("DataFilter", await Util.GetTokenAsync("BizAdminFull"), d.ToString());
|
||||||
Util.ValidateDataReturnResponseOk(a);
|
Util.ValidateDataReturnResponseOk(a);
|
||||||
long tagId = a.ObjectResponse["data"]["id"].Value<long>();
|
|
||||||
string tagName = a.ObjectResponse["data"]["name"].Value<string>();
|
long Id = a.ObjectResponse["data"]["id"].Value<long>();
|
||||||
tagName.Should().StartWith("testtag");
|
string Name = a.ObjectResponse["data"]["name"].Value<string>();
|
||||||
|
Name.Should().StartWith("Test DataFilter");
|
||||||
|
|
||||||
|
|
||||||
//RETRIEVE
|
// // //RETRIEVE
|
||||||
/*
|
// // /*
|
||||||
{
|
// // {
|
||||||
"data": {
|
// // "data": {
|
||||||
"id": 24,
|
// // "id": 24,
|
||||||
"created": "2018-03-28T21:07:41.9703503Z",
|
// // "created": "2018-03-28T21:07:41.9703503Z",
|
||||||
"concurrencyToken": 9502,
|
// // "concurrencyToken": 9502,
|
||||||
"ownerId": 1,
|
// // "ownerId": 1,
|
||||||
"name": "یونیکُد چیست؟"
|
// // "name": "یونیکُد چیست؟"
|
||||||
}
|
// // }
|
||||||
}
|
// // }
|
||||||
*/
|
// // */
|
||||||
//Get one
|
// // //Get one
|
||||||
a = await Util.GetAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
// // a = await Util.GetAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
||||||
Util.ValidateDataReturnResponseOk(a);
|
// // Util.ValidateDataReturnResponseOk(a);
|
||||||
a.ObjectResponse["data"]["name"].Value<string>().Should().StartWith("testtag");
|
// // a.ObjectResponse["data"]["name"].Value<string>().Should().StartWith("testtag");
|
||||||
|
|
||||||
//UPDATE
|
// // //UPDATE
|
||||||
|
|
||||||
//PUT
|
// // //PUT
|
||||||
d.Id = tagId;
|
// // d.Id = tagId;
|
||||||
d.name = Util.Uniquify("PutTestTag");
|
// // d.name = Util.Uniquify("PutTestTag");
|
||||||
d.created = DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
|
// // d.created = DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
|
||||||
d.concurrencyToken = a.ObjectResponse["data"]["concurrencyToken"].Value<uint>();
|
// // d.concurrencyToken = a.ObjectResponse["data"]["concurrencyToken"].Value<uint>();
|
||||||
d.OwnerId = 1L;
|
// // d.OwnerId = 1L;
|
||||||
|
|
||||||
|
|
||||||
ApiResponse PUTTestResponse = await Util.PutAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"), d.ToString());
|
// // ApiResponse PUTTestResponse = await Util.PutAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"), d.ToString());
|
||||||
Util.ValidateHTTPStatusCode(PUTTestResponse, 200);
|
// // Util.ValidateHTTPStatusCode(PUTTestResponse, 200);
|
||||||
|
|
||||||
|
// // //check PUT worked
|
||||||
|
// // ApiResponse checkPUTWorked = await Util.GetAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
||||||
|
// // Util.ValidateNoErrorInResponse(checkPUTWorked);
|
||||||
|
// // checkPUTWorked.ObjectResponse["data"]["name"].Value<string>().Should().Be(d.name.ToString().ToLowerInvariant().Replace(" ", "-"));
|
||||||
|
// // uint concurrencyToken = PUTTestResponse.ObjectResponse["data"]["concurrencyToken"].Value<uint>();
|
||||||
|
|
||||||
|
// // //PATCH
|
||||||
|
// // var newName = Util.Uniquify("PatchUpdate");
|
||||||
|
// // string patchJson = "[{\"value\": \"" + newName + "\",\"path\": \"/name\",\"op\": \"replace\"}]";
|
||||||
|
// // ApiResponse PATCHTestResponse = await Util.PatchAsync("Tag/" + tagId.ToString() + "/" + concurrencyToken.ToString(), await Util.GetTokenAsync("BizAdminFull"), patchJson);
|
||||||
|
// // Util.ValidateHTTPStatusCode(PATCHTestResponse, 200);
|
||||||
|
|
||||||
|
// // //check PATCH worked
|
||||||
|
// // ApiResponse checkPATCHWorked = await Util.GetAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
||||||
|
// // Util.ValidateNoErrorInResponse(checkPATCHWorked);
|
||||||
|
// // checkPATCHWorked.ObjectResponse["data"]["name"].Value<string>().Should().Be(newName.ToLowerInvariant().Replace(" ", "-"));
|
||||||
|
|
||||||
|
// // // //DELETE
|
||||||
|
// // ApiResponse DELETETestResponse = await Util.DeleteAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
||||||
|
// // Util.ValidateHTTPStatusCode(DELETETestResponse, 204);
|
||||||
|
|
||||||
//check PUT worked
|
|
||||||
ApiResponse checkPUTWorked = await Util.GetAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
|
||||||
Util.ValidateNoErrorInResponse(checkPUTWorked);
|
|
||||||
checkPUTWorked.ObjectResponse["data"]["name"].Value<string>().Should().Be(d.name.ToString().ToLowerInvariant().Replace(" ", "-"));
|
|
||||||
uint concurrencyToken = PUTTestResponse.ObjectResponse["data"]["concurrencyToken"].Value<uint>();
|
|
||||||
|
|
||||||
//PATCH
|
|
||||||
var newName = Util.Uniquify("PatchUpdate");
|
|
||||||
string patchJson = "[{\"value\": \"" + newName + "\",\"path\": \"/name\",\"op\": \"replace\"}]";
|
|
||||||
ApiResponse PATCHTestResponse = await Util.PatchAsync("Tag/" + tagId.ToString() + "/" + concurrencyToken.ToString(), await Util.GetTokenAsync("BizAdminFull"), patchJson);
|
|
||||||
Util.ValidateHTTPStatusCode(PATCHTestResponse, 200);
|
|
||||||
|
|
||||||
//check PATCH worked
|
|
||||||
ApiResponse checkPATCHWorked = await Util.GetAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
|
||||||
Util.ValidateNoErrorInResponse(checkPATCHWorked);
|
|
||||||
checkPATCHWorked.ObjectResponse["data"]["name"].Value<string>().Should().Be(newName.ToLowerInvariant().Replace(" ", "-"));
|
|
||||||
|
|
||||||
// //DELETE
|
|
||||||
ApiResponse DELETETestResponse = await Util.DeleteAsync("Tag/" + tagId.ToString(), await Util.GetTokenAsync("BizAdminFull"));
|
|
||||||
Util.ValidateHTTPStatusCode(DELETETestResponse, 204);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==================================================
|
//==================================================
|
||||||
|
|
||||||
}//eoc
|
}//eoc
|
||||||
|
|||||||
Reference in New Issue
Block a user