From 3bc821d074744f21270324c568d47d2ae8195f87 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Fri, 30 Nov 2018 19:37:15 +0000 Subject: [PATCH] --- devdocs/coding-standards.txt | 3 ++ ...-list-graph-datatable-filtering-paging.txt | 6 +++- server/AyaNova/biz/DataFilterBiz.cs | 20 ++++++++++--- .../AyaNova/biz/FilterOptionsFromListKey.cs | 30 +++++++++++++++++++ server/AyaNova/biz/WidgetBiz.cs | 16 +++++----- .../DataFilter/DataFilterCrud.cs | 2 +- 6 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 server/AyaNova/biz/FilterOptionsFromListKey.cs diff --git a/devdocs/coding-standards.txt b/devdocs/coding-standards.txt index 0ed58c95..5331bc21 100644 --- a/devdocs/coding-standards.txt +++ b/devdocs/coding-standards.txt @@ -33,6 +33,9 @@ JAVASCRIPT https://google.github.io/styleguide/javascriptguide.xml?showone=Naming#Naming In general, use functionNamesLikeThis, variableNamesLikeThis, ClassNamesLikeThis, EnumNamesLikeThis, methodNamesLikeThis, CONSTANT_VALUES_LIKE_THIS, foo.namespaceNamesLikeThis.bar, and filenameslikethis.js. +C# Naming +https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions + OLDER STUFF =-=-=-=-=-= diff --git a/devdocs/specs/core-list-graph-datatable-filtering-paging.txt b/devdocs/specs/core-list-graph-datatable-filtering-paging.txt index cadb4a90..0fa67c0c 100644 --- a/devdocs/specs/core-list-graph-datatable-filtering-paging.txt +++ b/devdocs/specs/core-list-graph-datatable-filtering-paging.txt @@ -7,16 +7,20 @@ User creates filters in separate UI from the actual list, i.e. clicks on the fil Two types of filters Named or Default: User can save a filter with a name for later selection or it will always default to "Default" (localized) if not edited but will always require saving to server. Generic "default" filter is always personal, not public / shared + - This is a client issue, Server doesn't care what the filters are called adn has no special processing for default filters Named filters can be made public or personal. If public then all users with rights to that object can see them, personal are always only personal. Filter is constructed from an FILTEROPTIONS object fetched from the server list route that has a list type name which is unique to that list route and also lists all the fields filterable, their type and the locale key to display it - - e.g.: {list:"widget",fields:[{fld:"name",lt:"WidgetName",type:"text"},{fld:"dollarAmount",lt:"WidgetDollarAmount",type:"currency"}]} + - e.g.: {ListKey:"widget",fields:[{fld:"name",lt:"WidgetName",type:"text"},{fld:"dollarAmount",lt:"WidgetDollarAmount",type:"currency"}]} + - List key 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: - Filter: Name, OwnerId, Public, ListKey, Filter (Json string) + - ListKey is always lower case to match biz object list key name - Filter format: - Array [{fld:"fieldname",op:"See filtercomparisonoperator class",value:"compareValue"},...] these are all AND in sql, no OR - fld=name of field to filter by + - always all lower case - 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 diff --git a/server/AyaNova/biz/DataFilterBiz.cs b/server/AyaNova/biz/DataFilterBiz.cs index 7b4d86ab..809c5b47 100644 --- a/server/AyaNova/biz/DataFilterBiz.cs +++ b/server/AyaNova/biz/DataFilterBiz.cs @@ -251,6 +251,12 @@ namespace AyaNova.Biz if (string.IsNullOrWhiteSpace(inObj.ListKey)) AddError(ValidationErrorType.RequiredPropertyEmpty, "ListKey"); + FilterOptions ListValidFilterOptions = FilterOptionsFromListKey.Get(inObj.ListKey); + if (ListValidFilterOptions == null) + { + AddError(ValidationErrorType.InvalidValue, "ListKey", $"ListKey \"{inObj.ListKey}\" is empty or in-valid"); + } + if (inObj.ListKey.Length > 255) AddError(ValidationErrorType.LengthExceeded, "ListKey", "255 max"); @@ -270,11 +276,17 @@ namespace AyaNova.Biz var fld = filterItem["fld"].Value(); if (string.IsNullOrWhiteSpace(fld)) AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, \"fld\" property is empty and required"); - //NOTE: have decided not to validate the field names are actually valid as that would involve a lot of fuckery that would probably be unproductive at this point - //as this datafilter normally would come straight from our client software that recieves its' list of fields directly from the object anyway - //maybe in future it will be more of an issue when it comes to modifications to objects or fields dropped but those errors should be caught by integration tests anyway - //and the rest are just outside users + //validate the field name if we can + if (ListValidFilterOptions != null) + { + + if (!ListValidFilterOptions.Flds.Exists(x => x.Fld == fld)) + { + AddError(ValidationErrorType.InvalidValue, "Filter", $"Filter array item {i}, fld property value \"{fld}\" is not a valid value for ListKey specified"); + } + + } } if (filterItem["op"] == null) AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, object is missing required \"op\" property "); diff --git a/server/AyaNova/biz/FilterOptionsFromListKey.cs b/server/AyaNova/biz/FilterOptionsFromListKey.cs new file mode 100644 index 00000000..58e3e26a --- /dev/null +++ b/server/AyaNova/biz/FilterOptionsFromListKey.cs @@ -0,0 +1,30 @@ +namespace AyaNova.Biz +{ + internal static class FilterOptionsFromListKey + { + internal static FilterOptions Get(string listKey) + { + if (string.IsNullOrWhiteSpace(listKey)) + return null; + + switch (listKey) + { + //All listkeys are always lower case + + case "widget": + return WidgetBiz.FilterOptions(); + + default: + return null;//not found + } + + } + + + ///////////////////////////////////////////////////////////////////// + + }//eoc + + +}//eons + diff --git a/server/AyaNova/biz/WidgetBiz.cs b/server/AyaNova/biz/WidgetBiz.cs index e8bed684..21cde0df 100644 --- a/server/AyaNova/biz/WidgetBiz.cs +++ b/server/AyaNova/biz/WidgetBiz.cs @@ -17,14 +17,16 @@ namespace AyaNova.Biz { public static FilterOptions FilterOptions(long localizeToLocaleId = 0) { - FilterOptions f = new FilterOptions("Widget"); + //NOTE: All column names are lowercase to conform with Postgres AyaNova DB which uses lowercase for all identifiers + //Also all list keys are lower case for consistency + FilterOptions f = new FilterOptions("widget"); f. - AddField("Name", "WidgetName", AyDataType.Text). - AddField("Serial", "WidgetSerial", AyDataType.Text). - AddField("DollarAmount", "WidgetDollarAmount", AyDataType.Decimal). - AddField("Active", "WidgetActive", AyDataType.Bool). - AddField("StartDate", "WidgetStartDate", AyDataType.Date). - AddField("EndDate", "WidgetEndDate", AyDataType.Date); + AddField("name", "WidgetName", AyDataType.Text). + AddField("serial", "WidgetSerial", AyDataType.Text). + AddField("dollaramount", "WidgetDollarAmount", AyDataType.Decimal). + AddField("active", "WidgetActive", AyDataType.Bool). + AddField("startdate", "WidgetStartDate", AyDataType.Date). + AddField("enddate", "WidgetEndDate", AyDataType.Date); if (localizeToLocaleId != 0) f.Localize(localizeToLocaleId); diff --git a/test/raven-integration/DataFilter/DataFilterCrud.cs b/test/raven-integration/DataFilter/DataFilterCrud.cs index 1aa4118e..9c3a7a32 100644 --- a/test/raven-integration/DataFilter/DataFilterCrud.cs +++ b/test/raven-integration/DataFilter/DataFilterCrud.cs @@ -22,7 +22,7 @@ namespace raven_integration d.name = Util.Uniquify("Test DataFilter"); // d.ownerId = 1L; d["public"] = true; - d.listKey = "Widget"; + d.listKey = "widget"; //"[{fld:"name",op:"!=",value:"Notequaltothis"},{fld:"tags",op:"Eq",value:"[23,456,54]"}] dynamic dfilter = new JArray();