diff --git a/server/AyaNova/Controllers/AttachmentController.cs b/server/AyaNova/Controllers/AttachmentController.cs index a3f717f7..3daaeb52 100644 --- a/server/AyaNova/Controllers/AttachmentController.cs +++ b/server/AyaNova/Controllers/AttachmentController.cs @@ -175,7 +175,7 @@ namespace AyaNova.Api.Controllers //Is it an attachable type of object? if (!badRequest) { - if (!attachToObject.IsAttachable) + if (!attachToObject.IsCoreBizObject) { badRequest = true; errorMessage = attachToObject.ObjectType.ToString() + " - AttachToObjectType does not support attachments"; diff --git a/server/AyaNova/Controllers/EnumPickListController.cs b/server/AyaNova/Controllers/EnumPickListController.cs index 355ddf09..71b66992 100644 --- a/server/AyaNova/Controllers/EnumPickListController.cs +++ b/server/AyaNova/Controllers/EnumPickListController.cs @@ -83,7 +83,7 @@ namespace AyaNova.Api.Controllers string name = t.ToString(); if (t.HasAttribute(typeof(CoreBizObjectAttribute))) { - name += " [Attachable]"; + name += " [CoreBizObject]"; } ReturnList.Add(new NameIdItem() { Name = name, Id = (long)t }); } diff --git a/server/AyaNova/PickList/AyaPickList.cs b/server/AyaNova/PickList/AyaPickList.cs index ca2cabc1..a03b489b 100644 --- a/server/AyaNova/PickList/AyaPickList.cs +++ b/server/AyaNova/PickList/AyaPickList.cs @@ -24,17 +24,17 @@ namespace AyaNova.PickList public AuthorizationRoles AllowedRoles { get; set; } public AyaType DefaultListObjectType { get; set; } - public string DefaultListView { get; set; } + public string DefaultTemplate { get; set; } //return array of field keys in list view - public List GetFieldListFromListView(JArray listViewArray) + public List GetFieldListFromTemplate(JArray template) { // [{key:"COLUMN UNIQUE KEY ID",sort:"-" or "+",filter:{any:true/false,items:[{FILTER OBJECT SEE BELOW}]} }, {key:"second column unique key"},{...etc...}] List ret = new List(); - for (int i = 0; i < listViewArray.Count; i++) + for (int i = 0; i < template.Count; i++) { - var cm = listViewArray[i]; + var cm = template[i]; ret.Add(cm["fld"].Value()); } return ret; @@ -42,10 +42,10 @@ namespace AyaNova.PickList - public Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromListView(JArray listViewArray) + public Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromTemplate(JArray template) { - var ListViewFieldKeys = GetFieldListFromListView(listViewArray); + var ListViewFieldKeys = GetFieldListFromTemplate(template); var CustomFieldDefinitions = GetCustomFieldDefinitionsForList(); //Generate JSON fragment to return with column definitions diff --git a/server/AyaNova/PickList/IAyaPickList.cs b/server/AyaNova/PickList/IAyaPickList.cs index 3e722582..56035aa5 100644 --- a/server/AyaNova/PickList/IAyaPickList.cs +++ b/server/AyaNova/PickList/IAyaPickList.cs @@ -19,10 +19,10 @@ namespace AyaNova.PickList AyaType DefaultListObjectType { get; set; } //Default / STOCK DataListView when none is specified - string DefaultListView { get; set; } + string DefaultTemplate { get; set; } - Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromListView(JArray listViewArray); - List GetFieldListFromListView(JArray listViewArray); + Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromTemplate(JArray listViewArray); + List GetFieldListFromTemplate(JArray listViewArray); } diff --git a/server/AyaNova/PickList/PickListFactory.cs b/server/AyaNova/PickList/PickListFactory.cs index dbe08a8e..89ca31d3 100644 --- a/server/AyaNova/PickList/PickListFactory.cs +++ b/server/AyaNova/PickList/PickListFactory.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using AyaNova.Biz; +using AyaNova.Models; namespace AyaNova.PickList @@ -19,20 +20,19 @@ namespace AyaNova.PickList return null; } - //List all the datalist types available - internal static List GetListOfAllPickListKeyNames() - { - //https://stackoverflow.com/a/42574373/8939 + //List all the PickList-able object types available + internal static List GetListOfAllPickListKeyNames() + { - List ret = new List(); - System.Reflection.Assembly ass = System.Reflection.Assembly.GetEntryAssembly(); - - foreach (System.Reflection.TypeInfo ti in ass.DefinedTypes) + List ret = new List(); + var values = System.Enum.GetValues(typeof(AyaType)); + foreach (AyaType t in values) { - if (!ti.IsAbstract && ti.ImplementedInterfaces.Contains(typeof(IAyaPickList))) + if (t.HasAttribute(typeof(CoreBizObjectAttribute))) { - ret.Add(ti.Name); + ret.Add(new NameIdItem() { Name = t.ToString(), Id = (long)t }); } + } return ret; } diff --git a/server/AyaNova/PickList/PickListFetcher.cs b/server/AyaNova/PickList/PickListFetcher.cs index 7db1dff2..39ed8838 100644 --- a/server/AyaNova/PickList/PickListFetcher.cs +++ b/server/AyaNova/PickList/PickListFetcher.cs @@ -9,73 +9,57 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using EnumsNET; + + namespace AyaNova.PickList { internal static class PickListFetcher { - internal static async Task GetResponseAsync(AyaType ayaType, string query, AuthorizationRoles userRoles) - //string PickListKey, AyContext ct, ListOptions listOptions, long UserId, AuthorizationRoles UserRoles) + internal static async Task> GetResponseAsync(AyaType ayaType, string query, AyContext ct, AuthorizationRoles userRoles) { - + var PickList = PickListFactory.GetAyaPickList(ayaType); //was the name not found as a list? if (PickList == null) { - throw new System.ArgumentOutOfRangeException($"PickList \"{PickListKey}\" specified does not exist"); + throw new System.ArgumentOutOfRangeException($"PickList for type \"{ayaType}\" specified does not exist"); } //check rights - if (!UserRoles.HasAnyFlags(PickList.AllowedRoles)) + if (!userRoles.HasAnyFlags(PickList.AllowedRoles)) throw new System.UnauthorizedAccessException("User roles insufficient for this datalist"); - //do we need to default the listView? - if (string.IsNullOrWhiteSpace(listOptions.ListView)) + //Template + string Template = null; + //Attempt to fetch custom template + var t = await ct.PickListTemplate.FirstOrDefaultAsync(m => m.Id == ((long)ayaType)); + if (t == null) { - listOptions.ListView = PickList.DefaultListView; + Template = PickList.DefaultTemplate; + } + else + { + Template = t.Template; } //parse the list view - var ListViewArray = JArray.Parse(listOptions.ListView); + var ListViewArray = JArray.Parse(Template); //Get the field key names in a list from the listview - List ListViewFieldList = PickList.GetFieldListFromListView(ListViewArray); + List ListViewFieldList = PickList.GetFieldListFromTemplate(ListViewArray); //BUILD THE QUERY - //SELECT FRAGMENT COLUMNS FROM TEMPLATE - var SelectBuild = PickListSqlSelectBuilder.Build(PickList.FieldDefinitions, ListViewFieldList); + + var q = PickListSqlBuilder.Build(PickList.FieldDefinitions, ListViewFieldList); - //FROM CLAUSE - var qFrom = PickList.SQLFrom; - - var qWhere = string.Empty; - var qOrderBy = string.Empty; - - //WHERE CLAUSE - FILTER - qWhere = PickListSqlFilterCriteriaBuilder.DataFilterToSQLCriteria(PickList.FieldDefinitions, ListViewArray, UserId); - - //ORDER BY CLAUSE - SORT - //BUILD ORDER BY - qOrderBy = PickListSqlFilterOrderByBuilder.DataFilterToSQLOrderBy(PickList.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; + + + //RETURN OBJECTS + var ret=new List(); + //QUERY THE DB using (var command = ct.Database.GetDbConnection().CreateCommand()) @@ -83,99 +67,85 @@ namespace AyaNova.PickList await ct.Database.OpenConnectionAsync(); //GET DATA RETURN ROWS - command.CommandText = qDataQuery; + command.CommandText = q; using (var dr = await command.ExecuteReaderAsync()) { while (dr.Read()) { - List row = new List(returnRowColumnCount); +// List row = new List(returnRowColumnCount); - //INSERT REMAINING FIELDS FROM TEMPLATE INTO THE RETURN ROWS LIST - foreach (string TemplateField in ListViewFieldList) - { +// //INSERT REMAINING FIELDS FROM TEMPLATE INTO THE RETURN ROWS LIST +// foreach (string TemplateField in ListViewFieldList) +// { - //get the AyaObjectFieldDefinition - AyaPickListFieldDefinition f = PickList.FieldDefinitions.FirstOrDefault(x => x.FieldKey == TemplateField); - if (f.IsCustomField) - { +// //get the AyaObjectFieldDefinition +// AyaPickListFieldDefinition f = PickList.FieldDefinitions.FirstOrDefault(x => x.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); - } +// 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; - /* - 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. +// row.Add(AyaField); +// } - 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 +// /* +// 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. - */ - } - else - { - AyaFieldData AyaField = new AyaFieldData(); - AyaField.v = dr.GetValue(SelectBuild.map[f.GetSqlValueColumnName()]); +// 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.SqlIdColumnName != null) - { - var ordinal = SelectBuild.map[f.SqlIdColumnName]; - if (!await dr.IsDBNullAsync(ordinal)) - AyaField.i = dr.GetInt64(ordinal); +// 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); +// } +// 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); - } - } + } - //BUILD THE COLUMNS RETURN PROPERTY JSON FRAGMENT - Newtonsoft.Json.Linq.JArray ColumnsJSON = null; - - ColumnsJSON = PickList.GenerateListColumnsJSONFromListView(ListViewArray); - - return new ApiPickListResponse(rows, totalRecordCount, ColumnsJSON); - + return ret; } diff --git a/server/AyaNova/PickList/PickListSqlBuilder.cs b/server/AyaNova/PickList/PickListSqlBuilder.cs new file mode 100644 index 00000000..4ab52a30 --- /dev/null +++ b/server/AyaNova/PickList/PickListSqlBuilder.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System; +using System.Globalization; +using System.Text; +using Newtonsoft.Json.Linq; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace AyaNova.PickList +{ + + internal static class PickListSqlBuilder + { + + //Build the SELECT portion of a list query based on the ListView fields + internal static string Build(List objectFieldsList, List listViewFieldList) + { + throw new System.NotImplementedException(); + +// StringBuilder sb = new StringBuilder(); +// sb.Append("SELECT "); + +// //DEPRECATED +// // //Default ID column for each row (always is aliased as df) +// // AyaPickListFieldDefinition def = objectFieldsList.FirstOrDefault(x => x.FieldKey == "df"); +// // if (def == null) +// // { +// // throw new System.ArgumentNullException("PickListSqlSelectBuilder: objectFieldList is missing the df default field"); +// // } +// // if (string.IsNullOrEmpty(def.SqlIdColumnName)) +// // { +// // sb.Append("id");//default when no alternate column is specified +// // } +// // else +// // { +// // sb.Append(def.SqlIdColumnName); +// // } + +// // sb.Append(" AS df"); + +// //keep track of which custom fields columns were added already +// //this ensures that if there is more than one set of custom fields like from two different objects in the list +// //only unique ones will be returned by query +// // Dictionary CustomFieldColumnsAddedToQuery = new Dictionary(); +// //map sql column name to ordinal name +// Dictionary map = new Dictionary(); + +// //DEPRECATED map.Add("df", 0); +// int nOrdinal = 0; + +// var firstColumnAdded = false; +// foreach (string ColumnName in listViewFieldList) +// { +// // //skip the df column, it's already been processed above +// // if (ColumnName == "df") +// // continue; +// AyaPickListFieldDefinition o = objectFieldsList.FirstOrDefault(x => x.FieldKey == ColumnName); +// #if (DEBUG) +// //Developers little helper +// if (o == null) +// { +// throw new System.ArgumentNullException($"DEV ERROR in PickListSqlSelectBuilder.cs: field {ColumnName} specified in template was NOT found in ObjectFields list"); +// } +// #endif +// if (o != null) +// {//Ignore missing fields in production + + +// if (o.IsCustomField) +// { //if any are custom field then add custom fields column to query +// var CustomFieldSqlColumnName = o.GetSqlValueColumnName(); +// //has it been added yet? +// if (!map.ContainsKey(CustomFieldSqlColumnName)) +// { //nope +// if (firstColumnAdded) +// sb.Append(", "); +// sb.Append(CustomFieldSqlColumnName); +// firstColumnAdded = true; +// map.Add(CustomFieldSqlColumnName, nOrdinal++); +// } +// //if it was already added then can just ignore it +// // else +// // { +// // map.Add(ColumnName, CustomFieldColumnsAddedToQuery[CustomFieldSqlColumnName]); +// // } + +// } +// else +// { +// var valueColumnName = o.GetSqlValueColumnName(); +// if (!map.ContainsKey(valueColumnName)) +// { +// if (firstColumnAdded) +// sb.Append(", "); +// sb.Append(valueColumnName); +// firstColumnAdded = true; +// map.Add(valueColumnName, nOrdinal++); +// } + +// //does it also have an ID column? +// var idColumnName = o.SqlIdColumnName; +// if (!string.IsNullOrWhiteSpace(idColumnName)) +// { +// if (!map.ContainsKey(idColumnName)) +// { +// if (firstColumnAdded) +// sb.Append(", "); +// sb.Append(idColumnName); +// firstColumnAdded = true; +// map.Add(idColumnName, nOrdinal++); +// } +// } + +// } + +// } +// } +// // return new SqlSelectBuilderResult() { map = map, Select = sb.ToString() }; + + + } + + + + }//eoc +}//ens diff --git a/server/AyaNova/PickList/WidgetPickList.cs b/server/AyaNova/PickList/WidgetPickList.cs index b6a25393..5334ad40 100644 --- a/server/AyaNova/PickList/WidgetPickList.cs +++ b/server/AyaNova/PickList/WidgetPickList.cs @@ -43,7 +43,7 @@ namespace AyaNova.PickList cm.fld = "username"; dlistView.Add(cm); - DefaultListView = dlistView.ToString(Newtonsoft.Json.Formatting.None); + DefaultTemplate = dlistView.ToString(Newtonsoft.Json.Formatting.None); diff --git a/server/AyaNova/biz/AyaTypeId.cs b/server/AyaNova/biz/AyaTypeId.cs index aba46575..948902d5 100644 --- a/server/AyaNova/biz/AyaTypeId.cs +++ b/server/AyaNova/biz/AyaTypeId.cs @@ -88,10 +88,10 @@ namespace AyaNova.Biz //Custom attribute checking /// - /// Is object attachable + /// Is object a core biz object /// /// - public bool IsAttachable + public bool IsCoreBizObject { get { diff --git a/server/AyaNova/biz/PickListBiz.cs b/server/AyaNova/biz/PickListBiz.cs index 3c7c9ebc..8d8d0ac0 100644 --- a/server/AyaNova/biz/PickListBiz.cs +++ b/server/AyaNova/biz/PickListBiz.cs @@ -56,11 +56,11 @@ namespace AyaNova.Biz //get picklist - internal async Task> GetPickListAsync(AyaType ayaType, string query, AuthorizationRoles userRoles) + internal async Task> GetPickListAsync(AyaType ayaType, string query, AuthorizationRoles userRoles) { - throw new System.NotImplementedException(); - // List items = await PickListFetcher.GetResponseAsync(ayaType, query, ct, UserId, userRoles); - // return items; + + List items = await PickListFetcher.GetResponseAsync(ayaType, query, ct, userRoles); + return items; }