using System.Collections.Generic; using System.Linq; using System.Text; using AyaNova.Models; using AyaNova.Biz; using Newtonsoft.Json.Linq; using Microsoft.EntityFrameworkCore; namespace AyaNova.DataList { /// /// DataList object base class /// internal abstract class DataListProcessingBase : IDataListProcessing { //CoreBizObject add here //well, not here exactly but add a new DATALIST class if it will be displayed as a list anywhere in the UI or reported on public DataListProcessingBase() { /* NOTE: all sql identifiers need to be explicitly identified as understood by postgres DefaultColumns = new List() { "XXX", "XXXX", "XXXX", "XXXX", "XXXX", "XXX", "XXXX", "XXXX", "XXXX", "XXXX" }; DefaultSortBy = new Dictionary() { { "XXXX", "+" }, { "XXXX", "-" } }; */ } public string SQLFrom { get; set; } public List FieldDefinitions { get; set; } public AuthorizationRoles AllowedRoles { get; set; } public AyaType DefaultListAType { get; set; } public long CurrentUserId { get; set; } public List DefaultColumns { get; set; } public Dictionary DefaultSortBy { get; set; } //set defaults if not provided in listOptions public void SetListOptionDefaultsIfNecessary(Models.DataListProcessingBase listOptions) { //columns, filter and sortby could all be null if (listOptions.Filter == null) listOptions.Filter = new List(); if (listOptions.SortBy == null) listOptions.SortBy = new Dictionary(); //Check Columns if (listOptions is DataListTableProcessingOptions) { var dlto = ((DataListTableProcessingOptions)listOptions); if (dlto.Columns == null) dlto.Columns = new List(); //if this doesn't work then just ditch this method in favor of local code, it's not really saving much if (dlto.Columns.Count == 0) dlto.Columns = DefaultColumns; } //Check SortBy if (listOptions.SortBy.Count == 0) listOptions.SortBy = DefaultSortBy; //Check filter if (listOptions.Filter == null) { } } public Newtonsoft.Json.Linq.JArray GenerateReturnListColumns(List columns) { var CustomFieldDefinitions = GetCustomFieldDefinitionsForList(); //Generate JSON fragment to return with column definitions StringBuilder sb = new StringBuilder(); sb.Append("["); bool FirstColumnAdded = false; foreach (string s in columns) { DataListFieldDefinition o = FieldDefinitions.FirstOrDefault(z => z.FieldKey == s); #if (DEBUG) //Developers little helper if (o == null) { throw new System.ArgumentNullException($"DEV ERROR in AyaDataList::GenerateReturnListColumns - field {s} specified in columns was NOT found in ObjectFields list"); } #endif if (o != null) {//Here is where we can vet the field name, if it doesn't exist. For production we'll just ignore those ones if (FirstColumnAdded) sb.Append(","); sb.Append("{"); //Build required part of column definition if (!o.IsCustomField) sb.Append($"\"cm\":\"{o.TKey}\",\"dt\":{(int)o.UiFieldDataType}"); else { //insert specific type for this custom field if (CustomFieldDefinitions.ContainsKey(o.TKey)) { var customFieldType = CustomFieldDefinitions[o.TKey]; sb.Append($"\"cm\":\"{o.TKey}\",\"dt\":{customFieldType}"); } else { //this is normal as there may not be a definition for a Custom field but it's been requested so just treat it like text sb.Append($"\"cm\":\"{o.TKey}\",\"dt\":{(int)UiFieldDataType.Text}"); } } //Has a AyAType? (linkable / openable) if (o.AType != 0) sb.Append($",\"ay\":{(int)o.AType}"); //Row ID column? if (o.IsRowId) { sb.Append($",\"rid\":1"); } //Has a Enumtype? if (!string.IsNullOrEmpty(o.EnumType)) sb.Append($",\"et\":\"{AyaNova.Util.StringUtil.TrimTypeName(o.EnumType)}\""); //field key needed for sorting etc sb.Append($",\"fk\":\"{o.FieldKey}\""); //Not Sortable? if (!o.IsSortable) sb.Append($",\"ns\":1"); //Not Filterable? if (!o.IsFilterable) sb.Append($",\"nf\":1"); //translate required? if (o.Translate) sb.Append($",\"tra\":1"); sb.Append("}"); FirstColumnAdded = true; } } sb.Append("]"); return JArray.Parse(sb.ToString()); } //Find and return a dictionary of all custom fields definitions for all types in list //used to build the column array and define specific type defined for custom fields so client datatable //knows how to format it private Dictionary GetCustomFieldDefinitionsForList() { //all keys and types can go in the same list since they are unique to each type of list //i.e. both users and widget custom fields can be in the same list Dictionary ret = new Dictionary(); List typesProcessed = new List(); //custom fields handling foreach (DataListFieldDefinition d in this.FieldDefinitions) { if (d.IsCustomField) { //this relies on the convention I'm using of AyaType name as the first part of all custom fields lT keys, e.g. //WidgetCustom1 -> Widget var ayatypename = d.TKey.Split("Custom")[0]; if (!typesProcessed.Contains(ayatypename)) { //make sure we do each type only once typesProcessed.Add(ayatypename); //fetch it and set it using (var ct = AyaNova.Util.ServiceProviderProvider.DBContext) { var fc = ct.FormCustom.AsNoTracking().SingleOrDefault(z => z.FormKey == ayatypename); //normal condition if (fc == null) continue; //iterate the fields and add each custom one with a type to the return dictionary var flds = JArray.Parse(fc.Template); foreach (JToken t in flds) { if (t["type"] != null) { ret.Add(t["fld"].Value(), t["type"].Value()); } } } } } } return ret; } }//eoc }//eons