From 84a8b7f05a3c5f59597f565d9fa79e2f3fc2b0ef Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Tue, 1 Sep 2020 17:59:01 +0000 Subject: [PATCH] --- .../AyaNova/Controllers/ReportController.cs | 31 ++- server/AyaNova/DataList/DataListFetcher.cs | 189 ++++++++++++++++++ server/AyaNova/DataList/ListOptions.cs | 7 +- 3 files changed, 218 insertions(+), 9 deletions(-) diff --git a/server/AyaNova/Controllers/ReportController.cs b/server/AyaNova/Controllers/ReportController.cs index f17aa4f0..af07a4b9 100644 --- a/server/AyaNova/Controllers/ReportController.cs +++ b/server/AyaNova/Controllers/ReportController.cs @@ -186,18 +186,28 @@ namespace AyaNova.Api.Controllers public class ObjectReportDataParameter { public AyaType ObjectType { get; set; } - public long[] ObjectIdArray { get; set; } + public long[] SelectedRowIds { get; set; } + public string DataListKey { get; set; } + public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList + } /// /// Get data from id list in format used by report designer /// - /// report id and object id values for object type specified in report template + /// Data required for report /// From route path /// [HttpPost("object-report-data")] public async Task GetReportData([FromBody] ObjectReportDataParameter reportDataParam, ApiVersion apiVersion) { + /*{ + public AyaType ObjectType { get; set; } + public long[] SelectedRowIds { get; set; } + public string DataListKey { get; set; } + public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList + + }*/ if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); ReportBiz biz = ReportBiz.GetBiz(ct, HttpContext); @@ -205,7 +215,22 @@ namespace AyaNova.Api.Controllers if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); - var reportData = await biz.GetReportData(reportDataParam.ObjectType, reportDataParam.ObjectIdArray); + Newtonsoft.Json.Linq.JArray reportData = null; + if (reportDataParam.SelectedRowIds.Length > 0) + { + //pre-selected id values + reportData = await biz.GetReportData(reportDataParam.ObjectType, reportDataParam.SelectedRowIds); + } + else + { + //get from datalist values + //get the list of id's from the data list view + var rowIds = await AyaNova.DataList.DataListFetcher.GetIdListResponseAsync(reportDataParam.DataListKey, reportDataParam.ListView, ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items), log); + //now get the report data + reportData = await biz.GetReportData(reportDataParam.ObjectType, rowIds); + } + + if (reportData == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else diff --git a/server/AyaNova/DataList/DataListFetcher.cs b/server/AyaNova/DataList/DataListFetcher.cs index 71762377..dcd6d76f 100644 --- a/server/AyaNova/DataList/DataListFetcher.cs +++ b/server/AyaNova/DataList/DataListFetcher.cs @@ -191,6 +191,195 @@ namespace AyaNova.DataList + //BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT + Newtonsoft.Json.Linq.JArray ColumnsJSON = null; + + ColumnsJSON = DataList.GenerateListColumnsJSONFromListView(ListViewArray); + + return new ApiDataListResponse(rows, totalRecordCount, ColumnsJSON); + + } + + +//Get a list of id's for reporting + internal static async Task GetIdListResponseAsync(string DataListKey, string ListView, AyContext ct, long UserId, AuthorizationRoles UserRoles, ILogger log) + { + + var DataList = DataListFactory.GetAyaDataList(DataListKey); + + //was the name not found as a list? + if (DataList == null) + { + throw new System.ArgumentOutOfRangeException($"DataList \"{DataListKey}\" specified does not exist"); + } + + //check rights + + if (!UserRoles.HasAnyFlags(DataList.AllowedRoles)) + throw new System.UnauthorizedAccessException("User roles insufficient for this datalist"); + + //do we need to default the listView? + if (string.IsNullOrWhiteSpace(listOptions.ListView)) + { + listOptions.ListView = DataList.DefaultListView; + } + + //parse the list view + var ListViewArray = JArray.Parse(listOptions.ListView); + + + //Get the field key names in a list from the listview + List ListViewFieldList = DataList.GetFieldListFromListView(ListViewArray); + + //BUILD THE QUERY + //SELECT FRAGMENT COLUMNS FROM TEMPLATE + var SelectBuild = DataListSqlSelectBuilder.Build(DataList.FieldDefinitions, ListViewFieldList); + + //FROM CLAUSE + var qFrom = DataList.SQLFrom; + + var qWhere = string.Empty; + var qOrderBy = string.Empty; + + //WHERE CLAUSE - FILTER + qWhere = DataListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(DataList.FieldDefinitions, ListViewArray, UserId); + + //ORDER BY CLAUSE - SORT + //BUILD ORDER BY + qOrderBy = DataListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(DataList.FieldDefinitions, ListViewArray); + + //LIMIT AND OFFSET CLAUSE - PAGING + listOptions.Offset = listOptions.Offset ?? ListOptions.DefaultOffset; + listOptions.Limit = listOptions.Limit ?? ListOptions.DefaultLimit; + var qLimitOffset = $"LIMIT {listOptions.Limit} OFFSET {listOptions.Offset}"; + + //PUT IT ALL TOGETHER + string qDataQuery = string.Empty; + string qTotalRecordsQuery = string.Empty; + + qDataQuery = $"{SelectBuild.Select} {qFrom} {qWhere} {qOrderBy} {qLimitOffset}".Replace(" ", " "); + qTotalRecordsQuery = $"SELECT COUNT(*) {qFrom} {qWhere}".Replace(" ", " "); + + //RETURN OBJECTS + int returnRowColumnCount = ListViewFieldList.Count(); + List> rows = new List>(); + long totalRecordCount = 0; + + //QUERY THE DB + using (var command = ct.Database.GetDbConnection().CreateCommand()) + { + await ct.Database.OpenConnectionAsync(); + + //GET DATA RETURN ROWS + command.CommandText = qDataQuery; + try + { + using (var dr = await command.ExecuteReaderAsync()) + { + while (dr.Read()) + { + List row = new List(returnRowColumnCount); + + + //INSERT REMAINING FIELDS FROM TEMPLATE INTO THE RETURN ROWS LIST + foreach (string TemplateField in ListViewFieldList) + { + + //get the AyaObjectFieldDefinition + AyaDataListFieldDefinition f = DataList.FieldDefinitions.FirstOrDefault(z => z.FieldKey == TemplateField); + if (f.IsCustomField) + { + + AyaFieldData AyaField = new AyaFieldData(); + var cust = dr.GetString(SelectBuild.map[f.GetSqlValueColumnName()]); + if (!string.IsNullOrWhiteSpace(cust)) + { + JObject j = JObject.Parse(cust); + //convert field name to cust name then get value + var InternalCustomFieldName = AyaFormFieldDefinitions.TranslateLTCustomFieldToInternalCustomFieldName(TemplateField); + //Sometimes a custom field is specified but doesn't exist in the collection so don't assume it's there + // AyaField.v = j[InternalCustomFieldName].Value(); + JToken o = j[InternalCustomFieldName]; + if (o != null) + AyaField.v = o.Value(); + else + AyaField.v = null; + + row.Add(AyaField); + } + + /* + TODO: Custom field handling + GetName works just not with multipart identifiers + I could force naming by making all fields and AS, or + I could map the ordinal when generating the Select fields so that I have a map to refer to here + mapping in advance actually makes a lot of sense, then no more of this fragility of going by pointer index and hoping for the best + it would just be premapped out. + + dr.GetOrdinal(f.SqlValueColumnName) + 'dr.GetOrdinal(f.SqlValueColumnName)' threw an exception of type 'System.IndexOutOfRangeException' + f.SqlValueColumnName + "awidget.customfields" + dr.GetName(nCurrentColumnPointer) + "customfields" + dr.GetOrdinal("customfields"); + 5 + + */ + } + else + { + AyaFieldData AyaField = new AyaFieldData(); + AyaField.v = dr.GetValue(SelectBuild.map[f.GetSqlValueColumnName()]); + + if (f.IsRowId) + { + AyaField.rid = true; + } + else + { + AyaField.rid = null; + } + + if (f.SqlIdColumnName != null) + { + var ordinal = SelectBuild.map[f.SqlIdColumnName]; + if (!await dr.IsDBNullAsync(ordinal)) + AyaField.i = dr.GetInt64(ordinal); + + } + row.Add(AyaField); + } + } + rows.Add(row); + } + } + + //GET TOTAL RECORD COUNT + command.CommandText = qTotalRecordsQuery; + using (var dr = await command.ExecuteReaderAsync()) + { + if (dr.Read()) + { + totalRecordCount = dr.GetInt64(0); + } + } + } + catch (Npgsql.PostgresException e) + { + //log out the exception and the query + log.LogInformation("DataList query failed unexpectedly. Data Query was:"); + log.LogInformation(qDataQuery); + log.LogInformation("Count Query was:"); + log.LogInformation(qTotalRecordsQuery); + log.LogInformation(e, "DB Exception"); + throw new System.Exception("DataListFetcher - Query failed see log"); + + } + } + + + //BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT Newtonsoft.Json.Linq.JArray ColumnsJSON = null; diff --git a/server/AyaNova/DataList/ListOptions.cs b/server/AyaNova/DataList/ListOptions.cs index e7615b8c..cb74d92d 100644 --- a/server/AyaNova/DataList/ListOptions.cs +++ b/server/AyaNova/DataList/ListOptions.cs @@ -15,17 +15,12 @@ namespace AyaNova.DataList [FromBody] public int? Limit { get; set; } - [FromBody, Required] public string DataListKey { get; set; } [FromBody] public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList - - - - - } + } } \ No newline at end of file