This commit is contained in:
2020-01-22 16:37:50 +00:00
parent 070688265b
commit f2898b8149
8 changed files with 67 additions and 276 deletions

View File

@@ -33,6 +33,8 @@ TEST CHANGES
- Must use numeric instead of text values now - Must use numeric instead of text values now
- Test datatypes enum picklist - Test datatypes enum picklist
- New routes for lists - New routes for lists
- Test validation code for custom template with bad one (field not exists)
- Test insufficient roles to fetch test widget datalist (outside staff)
TODO: REFACTOR GetNoLogAsync function is used in many places redundantly when the logging version could do the same thing but not log it with an optional bool switch so refactor that shit TODO: REFACTOR GetNoLogAsync function is used in many places redundantly when the logging version could do the same thing but not log it with an optional bool switch so refactor that shit

View File

@@ -186,10 +186,7 @@ namespace AyaNova.Api.Controllers
//does attach to object exist? //does attach to object exist?
if (!badRequest) if (!badRequest)
{ {
//check if object exists //check if object exists
//Updated code: this used to check if the o wnerId was -1 to see if it didn't exist, but since ow nerId zapped this seems like the next best way to do it
//Not sure at all what the ow nerid check was doing before that verified it's existance, the code is long gone now and I can't be arsed to look it up in the repo history
//If the tests pass then it's fine :)
if (!BizObjectExistsInDatabase.Exists(attachToObject)) if (!BizObjectExistsInDatabase.Exists(attachToObject))
{ {
badRequest = true; badRequest = true;

View File

@@ -1,70 +1,70 @@
// using System.Linq; using System.Linq;
// using System.Threading.Tasks; using System.Threading.Tasks;
// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
// using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
// using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.JsonPatch;
// using EnumsNET; using EnumsNET;
// using AyaNova.Util; using AyaNova.Util;
// using AyaNova.Api.ControllerHelpers; using AyaNova.Api.ControllerHelpers;
// using AyaNova.Biz; using AyaNova.Biz;
// using AyaNova.Models; using AyaNova.Models;
// namespace AyaNova.Biz namespace AyaNova.Biz
// { {
// //TODO: UNTESTED, UNUSED (SO FAR)CODE //THIS IS USED BY THE ATTACHMENT CONTROLLER
// //This was just blocked out because I know I will need it in future //IN THEORY WE ONLY NEED TO CHECK FOR ATTACHABLE TYPES, BUT I CAN SEE IT'S POTENTIAL USEFULNESS DOWN THE ROAD FOR OTHER THINGS
//REALLY? I"M BALLS DEEP IN THIS AND HAVEN'T SEEN A NEED FOR IT YET, not updating or maintaining until I see a need internal static class BizObjectExistsInDatabase
// internal static class BizObjectExistsInDatabase {
// {
// internal static bool Exists(AyaTypeId tid) //THIS IS THE METHOD CALLED BY THE ATTACHMENT CONTROLLER
// { internal static bool Exists(AyaTypeId tid)
// return Exists(tid.ObjectType, tid.ObjectId); {
// } return Exists(tid.ObjectType, tid.ObjectId);
}
// //Returns existance status of object type and id specified in database //Returns existance status of object type and id specified in database
// internal static bool Exists(AyaType aytype, long id, AyContext ct = null) internal static bool Exists(AyaType aytype, long id, AyContext ct = null)
// { {
// //new up a context?? //new up a context??
// if (ct == null) if (ct == null)
// { {
// ct = ServiceProviderProvider.DBContext; ct = ServiceProviderProvider.DBContext;
// } }
// switch (aytype) switch (aytype)
// { {
// case AyaType.User: case AyaType.User:
// return ct.User.Any(m => m.Id == id); return ct.User.Any(m => m.Id == id);
// case AyaType.Widget: case AyaType.Widget:
// return ct.Widget.Any(m => m.Id == id); return ct.Widget.Any(m => m.Id == id);
// case AyaType.FileAttachment: case AyaType.FileAttachment:
// return ct.FileAttachment.Any(m => m.Id == id); return ct.FileAttachment.Any(m => m.Id == id);
// case AyaType.DataListFilter: case AyaType.DataListFilter:
// return ct.DataListFilter.Any(m => m.Id == id); return ct.DataListFilter.Any(m => m.Id == id);
// case AyaType.DataListTemplate: case AyaType.DataListTemplate:
// return ct.DataListTemplate.Any(m => m.Id == id); return ct.DataListTemplate.Any(m => m.Id == id);
// case AyaType.FormCustom: case AyaType.FormCustom:
// return ct.FormCustom.Any(m => m.Id == id); return ct.FormCustom.Any(m => m.Id == id);
// default: default:
// throw new System.NotSupportedException($"AyaNova.BLL.BizObjectExistsInDatabase::Exists type {aytype.ToString()} is not supported"); throw new System.NotSupportedException($"AyaNova.Biz.BizObjectExistsInDatabase::Exists type {aytype.ToString()} is not supported");
// } }
// } }
// ///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// }//eoc }//eoc
// }//eons }//eons

View File

@@ -172,7 +172,7 @@ namespace AyaNova.Biz
if (HasErrors) if (HasErrors)
return false; return false;
//Log modification //Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
//Update keywords //Update keywords

View File

@@ -77,11 +77,14 @@ namespace AyaNova.Biz
//this will allow EF to check it out //this will allow EF to check it out
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken; ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
Validate(dbObj, false); if (!dataList.ValidateTemplate(dbObj.Template))
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template");
}
if (HasErrors) if (HasErrors)
return false; return false;
//Log modification //Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
return true; return true;
@@ -93,232 +96,21 @@ namespace AyaNova.Biz
// //
internal bool Delete(DataListTemplate dbObj) internal bool Delete(DataListTemplate dbObj)
{ {
//Determine if the object can be deleted, do the deletion tentatively //no validation required, we have defaults so this is ok anytime
//Probably also in here deal with tags and associated search text etc
ValidateCanDelete(dbObj);
if (HasErrors)
return false;
ct.DataListTemplate.Remove(dbObj); ct.DataListTemplate.Remove(dbObj);
ct.SaveChanges(); ct.SaveChanges();
//Delete sibling objects
//Event log process delete //Event log process delete
EventLogProcessor.DeleteObject(UserId, BizType, dbObj.Id, dbObj.DataListKey, ct); EventLogProcessor.DeleteObject(UserId, BizType, dbObj.Id, dbObj.DataListKey, ct);
ct.SaveChanges(); ct.SaveChanges();
//Delete search index
//Search.ProcessDeletedObjectKeywords(dbObj.Id, BizType);
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
//VALIDATION //VALIDATION
// // nothing special required here, it's all tightly controlled and datalist has validation code built in
//Can save or update?
private void Validate(DataListTemplate inObj, bool isNew)
{
//UserId required
if (!isNew)
{
if (inObj.UserId == 0)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "UserId");
}
//Name required
if (string.IsNullOrWhiteSpace(inObj.Name))
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name");
//Name must be less than 255 characters
if (inObj.Name.Length > 255)
AddError(ApiErrorCode.VALIDATION_LENGTH_EXCEEDED, "Name", "255 max");
//If name is otherwise OK, check that name is unique
if (!PropertyHasErrors("Name"))
{
//Use Any command is efficient way to check existance, it doesn't return the record, just a true or false
if (ct.DataListTemplate.Any(m => m.Name == inObj.Name && m.Id != inObj.Id))
{
AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name");
}
}
if (string.IsNullOrWhiteSpace(inObj.ListKey))
AddError(ApiErrorCode.VALIDATION_REQUIRED, "ListKey");
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)
AddError(ApiErrorCode.VALIDATION_LENGTH_EXCEEDED, "ListKey", "255 max");
//Filter json must parse
if (!string.IsNullOrWhiteSpace(inObj.Filter))
{
try
{
var v = JArray.Parse(inObj.Filter);
for (int i = 0; i < v.Count; i++)
{
var filterItem = v[i];
if (filterItem["fld"] == null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing required \"fld\" property ");
else
{
var fld = filterItem["fld"].Value<string>();
if (string.IsNullOrWhiteSpace(fld))
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, \"fld\" property is empty and required");
//validate the field name if we can
if (DataList != null)
{
var TheField = DataList.FieldDefinitions.SingleOrDefault(x => x.FieldKey.ToLowerInvariant() == fld);
if (TheField == null)
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Filter", $"Filter array item {i}, fld property value \"{fld}\" is not a valid value for ListKey specified");
}
else if (TheField.IsFilterable == false)
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Filter", $"Filter array item {i}, fld property value \"{fld}\" is not filterable");
}
}
}
if (filterItem["op"] == null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing required \"op\" property ");
else
{
var opType = filterItem["op"].Value<string>();
if (!DataListTemplateComparisonOperator.Operators.Contains(opType))
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Filter", $"Filter array item {i}, \"op\" property value of \"{opType}\" is not a valid FilterComparisonOperator type");
}
if (filterItem["value"] == null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property ");
else
{
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 ");
if (filterItem["value"].Type == JTokenType.Array && filterItem["value"].Count() == 0)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Filter", $"Filter array item {i}, object is missing or is empty the required \"value\" property ARRAY ");
}
//NOTE: value of nothing, null or empty is a valid value so no checking for it here
}
}
catch (Newtonsoft.Json.JsonReaderException ex)
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Filter", "Filter is not valid JSON string: " + ex.Message);
}
}
//VALIDATE SORT
//Filter json must parse
if (!string.IsNullOrWhiteSpace(inObj.Sort))
{
try
{
var v = JArray.Parse(inObj.Sort);
for (int i = 0; i < v.Count; i++)
{
var sortItem = v[i];
if (sortItem["fld"] == null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Sort", $"Sort array item {i}, object is missing required \"fld\" property ");
else
{
var fld = sortItem["fld"].Value<string>();
if (string.IsNullOrWhiteSpace(fld))
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Sort", $"Sort array item {i}, \"fld\" property is empty and required");
//validate the field name if we can
if (DataList != null)
{
if (!DataList.FieldDefinitions.Exists(x => x.FieldKey.ToLowerInvariant() == fld && x.IsFilterable))
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Sort", $"Sort array item {i}, fld property value \"{fld}\" is not a valid value for ListKey specified");
}
}
}
if (sortItem["dir"] == null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Sort", $"Sort array item {i}, object is missing required \"dir\" sort direction property ");
else
{
var sortDir = sortItem["dir"].Value<string>();
if (sortDir != "+" && sortDir != "-")
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Sort", $"Sort array item {i}, \"dir\" property value of \"{sortDir}\" is not a valid sort direction value, must be \"+\" or \"-\" only");
}
//NOTE: value of nothing, null or empty is a valid value so no checking for it here
}
}
catch (Newtonsoft.Json.JsonReaderException ex)
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Sort", "Sort is not valid JSON string: " + ex.Message);
}
}
return;
}
//Can delete?
private void ValidateCanDelete(DataListTemplate inObj)
{
//Leaving this off for now
}
// ////////////////////////////////////////////////////////////////////////////////////////////////
// //JOB / OPERATIONS
// //
// public async Task HandleJobAsync(OpsJob job)
// {
// //Hand off the particular job to the corresponding processing code
// //NOTE: If this code throws an exception the caller (JobsBiz::ProcessJobsAsync) will automatically set the job to failed and log the exeption so
// //basically any error condition during job processing should throw up an exception if it can't be handled
// switch (job.JobType)
// {
// case JobType.TestDataFilterJob:
// await ProcessTestJobAsync(job);
// break;
// default:
// throw new System.ArgumentOutOfRangeException($"DataFilterBiz.HandleJob-> Invalid job type{job.JobType.ToString()}");
// }
// }
//Other job handlers here...
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////

View File

@@ -140,7 +140,7 @@ namespace AyaNova.Biz
dbObj.Template = JsonUtil.CompactJson(dbObj.Template); dbObj.Template = JsonUtil.CompactJson(dbObj.Template);
//Log modification //Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
//Update keywords //Update keywords

View File

@@ -300,7 +300,7 @@ namespace AyaNova.Biz
return false; return false;
//Log modification //Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
SearchIndex(dbObj, false); SearchIndex(dbObj, false);
@@ -337,7 +337,7 @@ namespace AyaNova.Biz
if (HasErrors) if (HasErrors)
return false; return false;
//Log modification //Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
SearchIndex(dbObj, false); SearchIndex(dbObj, false);

View File

@@ -186,7 +186,7 @@ namespace AyaNova.Biz
if (HasErrors) if (HasErrors)
return false; return false;
//Associated items //Log event and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
SearchIndex(dbObj, false); SearchIndex(dbObj, false);
TagUtil.ProcessUpdateTagsInRepository(ct, dbObj.Tags, SnapshotOfOriginalDBObj.Tags); TagUtil.ProcessUpdateTagsInRepository(ct, dbObj.Tags, SnapshotOfOriginalDBObj.Tags);
@@ -216,7 +216,7 @@ namespace AyaNova.Biz
if (HasErrors) if (HasErrors)
return false; return false;
//Associated items //Log event and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
SearchIndex(dbObj, false); SearchIndex(dbObj, false);
@@ -254,7 +254,7 @@ namespace AyaNova.Biz
ct.Widget.Remove(dbObj); ct.Widget.Remove(dbObj);
ct.SaveChanges(); ct.SaveChanges();
//Associated items //Log event and save context
EventLogProcessor.DeleteObject(UserId, BizType, dbObj.Id, dbObj.Name, ct); EventLogProcessor.DeleteObject(UserId, BizType, dbObj.Id, dbObj.Name, ct);
ct.SaveChanges(); ct.SaveChanges();
Search.ProcessDeletedObjectKeywords(dbObj.Id, BizType); Search.ProcessDeletedObjectKeywords(dbObj.Id, BizType);