This commit is contained in:
22
server/AyaNova/ControllerHelpers/ApiDataListResponse.cs
Normal file
22
server/AyaNova/ControllerHelpers/ApiDataListResponse.cs
Normal file
@@ -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
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AyaNova.Api.ControllerHelpers
|
||||
{
|
||||
|
||||
|
||||
|
||||
public class ApiOkWithPagingResponse<T>
|
||||
{
|
||||
|
||||
public object Data { get; }
|
||||
public object Paging { get; }
|
||||
|
||||
public ApiOkWithPagingResponse(ApiPagedResponse<T> 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
|
||||
@@ -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<T>
|
||||
{
|
||||
// // public class ApiPagedResponse<T>
|
||||
// // {
|
||||
|
||||
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
|
||||
// }//eons
|
||||
@@ -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; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
// }));
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return paging data suitable for API return
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Object PagingLinksObject()
|
||||
{
|
||||
return new
|
||||
{
|
||||
Count = TotalRecordCount,
|
||||
Offset = PagingOptions.Offset,
|
||||
Limit = PagingOptions.Limit,
|
||||
First = FirstPage,
|
||||
Previous = PreviousPage,
|
||||
Next = NextPage,
|
||||
Last = LastPage
|
||||
};
|
||||
}
|
||||
// /// <summary>
|
||||
// /// Return paging data suitable for API return
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// public Object PagingLinksObject()
|
||||
// {
|
||||
// return new
|
||||
// {
|
||||
// Count = TotalRecordCount,
|
||||
// Offset = PagingOptions.Offset,
|
||||
// Limit = PagingOptions.Limit,
|
||||
// First = FirstPage,
|
||||
// Previous = PreviousPage,
|
||||
// Next = NextPage,
|
||||
// Last = LastPage
|
||||
// };
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
// }
|
||||
@@ -48,8 +48,8 @@ namespace AyaNova.Api.Controllers
|
||||
/// </summary>
|
||||
/// <param name="listOptions">List key, Paging, filtering and sorting options</param>
|
||||
/// <returns>Collection with paging data</returns>
|
||||
[HttpGet("List", Name = nameof(List))]
|
||||
public async Task<IActionResult> List([FromQuery] ListOptions listOptions)
|
||||
[HttpPost("List", Name = nameof(List))]
|
||||
public async Task<IActionResult> 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)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace AyaNova.DataList
|
||||
{
|
||||
internal static class DataListFetcher
|
||||
{
|
||||
internal static async Task<ApiPagedResponse> GetResponseAsync(string DataListKey, AyContext ct, IUrlHelper Url,
|
||||
internal static async Task<ApiDataListResponse> 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace AyaNova.DataList
|
||||
{
|
||||
public static class DataListSqlFilterCriteriaBuilder
|
||||
{
|
||||
public static string DataFilterToSQLCriteria(List<AyaDataListFieldDefinition> objectFieldsList, AyaNova.Models.DataListFilter dataFilter, List<AyaDataListFieldDefinition> objectFields, long userId)
|
||||
public static string DataFilterToSQLCriteria(List<AyaDataListFieldDefinition> objectFieldsList, string filterJson, List<AyaDataListFieldDefinition> 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++)
|
||||
{
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ namespace AyaNova.DataList
|
||||
|
||||
// public static string DefaultPickListOrderBy => "ORDER BY NAME ASC";
|
||||
|
||||
public static string DataFilterToSQLOrderBy(List<AyaDataListFieldDefinition> objectFieldsList, AyaNova.Models.DataListFilter dataFilter)
|
||||
public static string DataFilterToSQLOrderBy(List<AyaDataListFieldDefinition> 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++)
|
||||
{
|
||||
|
||||
|
||||
@@ -220,16 +220,12 @@ namespace AyaNova.Biz
|
||||
|
||||
|
||||
var DataList = DataListFactory.GetAyaDataList(inObj.ListKey);
|
||||
// List<AyaDataListFieldDefinition> 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<string>()))
|
||||
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property ");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user