diff --git a/server/AyaNova/ControllerHelpers/ApiDataListResponse.cs b/server/AyaNova/ControllerHelpers/ApiDataListResponse.cs new file mode 100644 index 00000000..d77b2b21 --- /dev/null +++ b/server/AyaNova/ControllerHelpers/ApiDataListResponse.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace AyaNova.Api.ControllerHelpers +{ + + public class ApiDataListResponse + { + + public object Data { get; } + public long TotalRecordCount { get; } + public object Columns {get;} + + public ApiDataListResponse(object returnItems, long totalRecordCount, Newtonsoft.Json.Linq.JArray columns) + { + Data = returnItems; + TotalRecordCount = totalRecordCount; + Columns = columns; + + } + }//eoc + +}//eons \ No newline at end of file diff --git a/server/AyaNova/ControllerHelpers/ApiOkWithPagingResponse.cs b/server/AyaNova/ControllerHelpers/ApiOkWithPagingResponse.cs deleted file mode 100644 index fe80a287..00000000 --- a/server/AyaNova/ControllerHelpers/ApiOkWithPagingResponse.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; - -namespace AyaNova.Api.ControllerHelpers -{ - - - - public class ApiOkWithPagingResponse - { - - public object Data { get; } - public object Paging { get; } - - public ApiOkWithPagingResponse(ApiPagedResponse pr) - { - Data = pr.items; - Paging = pr.PageLinks; - - } - }//eoc - - public class ApiOkWithPagingResponse - { - - public object Data { get; } - public object Paging { get; } - public object Columns {get;} - - public ApiOkWithPagingResponse(ApiPagedResponse pr) - { - Data = pr.items; - Paging = pr.PageLinks; - Columns = pr.Columns; - - } - }//eoc - -}//eons \ No newline at end of file diff --git a/server/AyaNova/ControllerHelpers/ApiPagedResponse.cs b/server/AyaNova/ControllerHelpers/ApiPagedResponse.cs index bac55b21..10ad9000 100644 --- a/server/AyaNova/ControllerHelpers/ApiPagedResponse.cs +++ b/server/AyaNova/ControllerHelpers/ApiPagedResponse.cs @@ -1,42 +1,42 @@ -using System.Collections.Generic; -using AyaNova.Models; +// using System.Collections.Generic; +// using AyaNova.Models; -namespace AyaNova.Api.ControllerHelpers -{ +// namespace AyaNova.Api.ControllerHelpers +// { - public class ApiPagedResponse - { +// // public class ApiPagedResponse +// // { - public T[] items { get; } - public object PageLinks { get; } - public object Columns { get; } +// // public T[] items { get; } +// // public object PageLinks { get; } +// // public object Columns { get; } - public ApiPagedResponse(T[] returnItems, object pageLinks, object columns = null) - { - items = returnItems; - PageLinks = pageLinks; - Columns = Columns; +// // public ApiPagedResponse(T[] returnItems, object pageLinks, object columns = null) +// // { +// // items = returnItems; +// // PageLinks = pageLinks; +// // Columns = Columns; - } - }//eoc +// // } +// // }//eoc - public class ApiPagedResponse - { +// public class ApiPagedResponse +// { - public object items { get; } - public object PageLinks { get; } - public Newtonsoft.Json.Linq.JArray Columns { get; } +// public object items { get; } +// public object PageLinks { get; } +// public Newtonsoft.Json.Linq.JArray Columns { get; } - public ApiPagedResponse(object returnItems, object pageLinks, Newtonsoft.Json.Linq.JArray columns) - { - items = returnItems; - PageLinks = pageLinks; - Columns = columns; +// public ApiPagedResponse(object returnItems, object pageLinks, Newtonsoft.Json.Linq.JArray columns) +// { +// items = returnItems; +// PageLinks = pageLinks; +// Columns = columns; - } - }//eoc +// } +// }//eoc -}//eons \ No newline at end of file +// }//eons \ No newline at end of file diff --git a/server/AyaNova/ControllerHelpers/ListOptions.cs b/server/AyaNova/ControllerHelpers/ListOptions.cs index 8665adc2..230f09d6 100644 --- a/server/AyaNova/ControllerHelpers/ListOptions.cs +++ b/server/AyaNova/ControllerHelpers/ListOptions.cs @@ -10,25 +10,31 @@ namespace AyaNova.Api.ControllerHelpers public const int DefaultOffset = 0; public const int DefaultLimit = 25; - [FromQuery] + [FromBody] [Range(0, int.MaxValue)] public int? Offset { get; set; } - [FromQuery] + [FromBody] [Range(1, MaxPageSize, ErrorMessage = "Limit must be greater than 0 and less than 1000.")] public int? Limit { get; set; } - //Data filter id to use with this list query - //0 or less means no filter - [FromQuery] - public long DataFilterId { get; set; } + // //Data filter id to use with this list query + // //0 or less means no filter + // [FromBody] + // public long DataFilterId { get; set; } - [FromQuery] + [FromBody] public bool Mini { get; set; } - [FromQuery, Required] + [FromBody, Required] public string DataListKey { get; set; } + [FromBody] + public string FilterJson { get; set; } + + [FromBody] + public string SortJson { get; set; } + } diff --git a/server/AyaNova/ControllerHelpers/PaginationLinkBuilder.cs b/server/AyaNova/ControllerHelpers/PaginationLinkBuilder.cs index cae1d5ac..7b8a3196 100644 --- a/server/AyaNova/ControllerHelpers/PaginationLinkBuilder.cs +++ b/server/AyaNova/ControllerHelpers/PaginationLinkBuilder.cs @@ -1,89 +1,89 @@ -using System; -using Microsoft.AspNetCore.Routing; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; +// using System; +// using Microsoft.AspNetCore.Routing; +// using Microsoft.AspNetCore.Mvc; +// using Newtonsoft.Json; -namespace AyaNova.Api.ControllerHelpers -{ +// namespace AyaNova.Api.ControllerHelpers +// { - public class PaginationLinkBuilder - { //adapted from //https://www.jerriepelser.com/blog/paging-in-aspnet-webapi-pagination-links/ - public Uri FirstPage { get; private set; } - public Uri LastPage { get; private set; } - public Uri NextPage { get; private set; } - public Uri PreviousPage { get; private set; } - public ListOptions PagingOptions { get; } - public long TotalRecordCount { get; } +// public class PaginationLinkBuilder +// { //adapted from //https://www.jerriepelser.com/blog/paging-in-aspnet-webapi-pagination-links/ +// public Uri FirstPage { get; private set; } +// public Uri LastPage { get; private set; } +// public Uri NextPage { get; private set; } +// public Uri PreviousPage { get; private set; } +// public ListOptions PagingOptions { get; } +// public long TotalRecordCount { get; } - public PaginationLinkBuilder(IUrlHelper urlHelper, string routeName, object routeValues, ListOptions pagingOptions, long totalRecordCount) - { - PagingOptions = pagingOptions; - TotalRecordCount = totalRecordCount; +// public PaginationLinkBuilder(IUrlHelper urlHelper, string routeName, object routeValues, ListOptions pagingOptions, long totalRecordCount) +// { +// PagingOptions = pagingOptions; +// TotalRecordCount = totalRecordCount; - // Determine total number of pages - var pageCount = totalRecordCount > 0 - ? (int)Math.Ceiling(totalRecordCount / (double)pagingOptions.Limit) - : 0; +// // Determine total number of pages +// var pageCount = totalRecordCount > 0 +// ? (int)Math.Ceiling(totalRecordCount / (double)pagingOptions.Limit) +// : 0; - // Create page links +// // Create page links - FirstPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) - { - {"pageNo", 1}, - {"pageSize", pagingOptions.Limit} - })); +// FirstPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) +// { +// {"pageNo", 1}, +// {"pageSize", pagingOptions.Limit} +// })); - LastPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) - { - {"pageNo", pageCount}, - {"pageSize", pagingOptions.Limit} - })); +// LastPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) +// { +// {"pageNo", pageCount}, +// {"pageSize", pagingOptions.Limit} +// })); - if (pagingOptions.Offset > 1) - { - PreviousPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) - { - {"pageNo", pagingOptions.Offset - 1}, - {"pageSize", pagingOptions.Limit} - })); - } +// if (pagingOptions.Offset > 1) +// { +// PreviousPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) +// { +// {"pageNo", pagingOptions.Offset - 1}, +// {"pageSize", pagingOptions.Limit} +// })); +// } - if (pagingOptions.Offset < pageCount) - { - NextPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) - { - {"pageNo", pagingOptions.Offset + 1}, - {"pageSize", pagingOptions.Limit} - })); - } +// if (pagingOptions.Offset < pageCount) +// { +// NextPage = new Uri(urlHelper.Link(routeName, new RouteValueDictionary(routeValues) +// { +// {"pageNo", pagingOptions.Offset + 1}, +// {"pageSize", pagingOptions.Limit} +// })); +// } - } +// } - /// - /// Return paging data suitable for API return - /// - /// - public Object PagingLinksObject() - { - return new - { - Count = TotalRecordCount, - Offset = PagingOptions.Offset, - Limit = PagingOptions.Limit, - First = FirstPage, - Previous = PreviousPage, - Next = NextPage, - Last = LastPage - }; - } +// /// +// /// Return paging data suitable for API return +// /// +// /// +// public Object PagingLinksObject() +// { +// return new +// { +// Count = TotalRecordCount, +// Offset = PagingOptions.Offset, +// Limit = PagingOptions.Limit, +// First = FirstPage, +// Previous = PreviousPage, +// Next = NextPage, +// Last = LastPage +// }; +// } - } +// } -} \ No newline at end of file +// } \ No newline at end of file diff --git a/server/AyaNova/Controllers/DataListController.cs b/server/AyaNova/Controllers/DataListController.cs index 8e8e288b..cfaa24e2 100644 --- a/server/AyaNova/Controllers/DataListController.cs +++ b/server/AyaNova/Controllers/DataListController.cs @@ -48,8 +48,8 @@ namespace AyaNova.Api.Controllers /// /// List key, Paging, filtering and sorting options /// Collection with paging data - [HttpGet("List", Name = nameof(List))] - public async Task List([FromQuery] ListOptions listOptions) + [HttpPost("List", Name = nameof(List))] + public async Task List([FromBody] ListOptions listOptions) { if (serverState.IsClosed) return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); @@ -62,8 +62,8 @@ namespace AyaNova.Api.Controllers try { - ApiPagedResponse pr = await DataListFetcher.GetResponseAsync(listOptions.DataListKey, ct, Url, nameof(List), listOptions, UserId, UserRoles); - return Ok(new ApiOkWithPagingResponse(pr)); + ApiDataListResponse r = await DataListFetcher.GetResponseAsync(listOptions.DataListKey, ct, Url, nameof(List), listOptions, UserId, UserRoles); + return Ok(r); } catch (System.UnauthorizedAccessException) { diff --git a/server/AyaNova/DataList/DataListFetcher.cs b/server/AyaNova/DataList/DataListFetcher.cs index 92e309ac..7b2f3198 100644 --- a/server/AyaNova/DataList/DataListFetcher.cs +++ b/server/AyaNova/DataList/DataListFetcher.cs @@ -13,7 +13,7 @@ namespace AyaNova.DataList { internal static class DataListFetcher { - internal static async Task GetResponseAsync(string DataListKey, AyContext ct, IUrlHelper Url, + internal static async Task GetResponseAsync(string DataListKey, AyContext ct, IUrlHelper Url, string routeName, ListOptions listOptions, long UserId, AuthorizationRoles UserRoles) { @@ -78,15 +78,19 @@ namespace AyaNova.DataList DataListFilter TheFilter = null; var qWhere = string.Empty; var qOrderBy = string.Empty; - if (listOptions.DataFilterId > 0) + if (!string.IsNullOrWhiteSpace(listOptions.FilterJson)) { - TheFilter = await ct.DataListFilter.FirstOrDefaultAsync(x => x.Id == listOptions.DataFilterId); //WHERE CLAUSE - FILTER - qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(DataList.FieldDefinitions, TheFilter, DataList.FieldDefinitions, UserId); + qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(DataList.FieldDefinitions, listOptions.FilterJson, DataList.FieldDefinitions, UserId); + } + if (!string.IsNullOrWhiteSpace(listOptions.SortJson)) + { //ORDER BY CLAUSE - SORT //BUILD ORDER BY - qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, TheFilter); - }else{ + qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, listOptions.SortJson); + } + else + { //BUILD DEFAULT ORDER BY IF POSSIBLE qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, null); } @@ -180,38 +184,41 @@ namespace AyaNova.DataList } } + //RES.PAGING.COUNT is all I need so the rest is moot, particularly since it's a post method now to get a datalist not a GET with query parameters + //below commented stuff can go once it tests + //BUILD THE PAGING LINKS PORTION //var pageLinks = new PaginationLinkBuilder(Url, routeName, null, listOptions, totalRecordCount).PagingLinksObject(); //http://localhost:7575/api/v8/DataList/List?Offset=2&Limit=3&DataFilterId=2&Mini=true&DataListKey=TestWidgetDataList - object routeValues = null; - //no data filter? - if (listOptions.DataFilterId == 0) - { - if (listOptions.Mini) - { - routeValues = new { DataListKey = DataListKey, Mini = listOptions.Mini }; - } - else - { - routeValues = new { DataListKey = DataListKey }; - } - } - else - { - if (listOptions.Mini) - { - routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId, Mini = listOptions.Mini }; - } - else - { - routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId }; - } - } + // object routeValues = null; + // //no data filter? + // if (listOptions.DataFilterId == 0) + // { + // if (listOptions.Mini) + // { + // routeValues = new { DataListKey = DataListKey, Mini = listOptions.Mini }; + // } + // else + // { + // routeValues = new { DataListKey = DataListKey }; + // } + // } + // else + // { + // if (listOptions.Mini) + // { + // routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId, Mini = listOptions.Mini }; + // } + // else + // { + // routeValues = new { DataListKey = DataListKey, DataFilterId = listOptions.DataFilterId }; + // } + // } - var pageLinks = new PaginationLinkBuilder(Url, routeName, routeValues, listOptions, totalRecordCount).PagingLinksObject(); + // var pageLinks = new PaginationLinkBuilder(Url, routeName, routeValues, listOptions, totalRecordCount).PagingLinksObject(); //BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT Newtonsoft.Json.Linq.JArray ColumnsJSON = null; @@ -225,8 +232,8 @@ namespace AyaNova.DataList } - ApiPagedResponse pr = new ApiPagedResponse(rows, pageLinks, ColumnsJSON); - return pr; + return new ApiDataListResponse(rows, totalRecordCount, ColumnsJSON); + } diff --git a/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs b/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs index 89b142d1..63c30525 100644 --- a/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlFilterCriteriaBuilder.cs @@ -11,10 +11,10 @@ namespace AyaNova.DataList { public static class DataListSqlFilterCriteriaBuilder { - public static string DataFilterToSQLCriteria(List objectFieldsList, AyaNova.Models.DataListFilter dataFilter, List objectFields, long userId) + public static string DataFilterToSQLCriteria(List objectFieldsList, string filterJson, List objectFields, long userId) { - if (string.IsNullOrWhiteSpace(dataFilter.Filter)) + if (string.IsNullOrWhiteSpace(filterJson)) { return ""; } @@ -22,7 +22,7 @@ namespace AyaNova.DataList StringBuilder sb = new StringBuilder(); //iterate the datafilter and concatenate a sql query from it - var FilterArray = JArray.Parse(dataFilter.Filter); + var FilterArray = JArray.Parse(filterJson); for (int i = 0; i < FilterArray.Count; i++) { diff --git a/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs b/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs index 1f591701..42f327a5 100644 --- a/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs @@ -12,10 +12,10 @@ namespace AyaNova.DataList // public static string DefaultPickListOrderBy => "ORDER BY NAME ASC"; - public static string DataFilterToSQLOrderBy(List objectFieldsList, AyaNova.Models.DataListFilter dataFilter) + public static string DataFilterToSQLOrderBy(List objectFieldsList, string SortJson) { - if (dataFilter == null || string.IsNullOrWhiteSpace(dataFilter.Sort)) + if ( string.IsNullOrWhiteSpace(SortJson)) { //sort by default field descending which should in theory always be the id column of the main object in the list //which should return the results to user with most recent records at the top if no sort order was specified @@ -33,7 +33,7 @@ namespace AyaNova.DataList StringBuilder sb = new StringBuilder(); //iterate the datafilter and concatenate a sql query from it - var SortArray = JArray.Parse(dataFilter.Sort); + var SortArray = JArray.Parse(SortJson); for (int i = 0; i < SortArray.Count; i++) { diff --git a/server/AyaNova/biz/DataListFilterBiz.cs b/server/AyaNova/biz/DataListFilterBiz.cs index 1f483bcb..fc62f735 100644 --- a/server/AyaNova/biz/DataListFilterBiz.cs +++ b/server/AyaNova/biz/DataListFilterBiz.cs @@ -220,16 +220,12 @@ namespace AyaNova.Biz var DataList = DataListFactory.GetAyaDataList(inObj.ListKey); - // List FieldList = null; - //if (!AyaFormFieldDefinitions.IsValidFormFieldDefinitionKey(inObj.ListKey)) + if (DataList == null) { AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "ListKey", $"ListKey \"{inObj.ListKey}\" DataListKey is not valid"); } - // else - // { - // FieldList = AyaDataListFieldDefinition.AyaObjectFields(inObj.ListKey); - // } + if (inObj.ListKey.Length > 255) @@ -284,6 +280,8 @@ namespace AyaNova.Biz AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property "); else { + //check if the value is present, not what it is exactly, just that it's present + //value also could contain relative date tokens, not that it checks them anyway but just noting it here if (filterItem["value"].Type == JTokenType.String && string.IsNullOrWhiteSpace(filterItem["value"].Value())) AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property ");