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
- Test datatypes enum picklist
- 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

View File

@@ -186,10 +186,7 @@ namespace AyaNova.Api.Controllers
//does attach to object exist?
if (!badRequest)
{
//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 :)
//check if object exists
if (!BizObjectExistsInDatabase.Exists(attachToObject))
{
badRequest = true;

View File

@@ -1,70 +1,70 @@
// using System.Linq;
// using System.Threading.Tasks;
// using Microsoft.EntityFrameworkCore;
// using Microsoft.AspNetCore.Mvc;
// using Microsoft.AspNetCore.JsonPatch;
// using EnumsNET;
// using AyaNova.Util;
// using AyaNova.Api.ControllerHelpers;
// using AyaNova.Biz;
// using AyaNova.Models;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.JsonPatch;
using EnumsNET;
using AyaNova.Util;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Biz;
using AyaNova.Models;
// namespace AyaNova.Biz
// {
namespace AyaNova.Biz
{
// //TODO: UNTESTED, UNUSED (SO FAR)CODE
// //This was just blocked out because I know I will need it in future
//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
// {
//THIS IS USED BY THE ATTACHMENT CONTROLLER
//IN THEORY WE ONLY NEED TO CHECK FOR ATTACHABLE TYPES, BUT I CAN SEE IT'S POTENTIAL USEFULNESS DOWN THE ROAD FOR OTHER THINGS
internal static class BizObjectExistsInDatabase
{
// internal static bool Exists(AyaTypeId tid)
// {
// return Exists(tid.ObjectType, tid.ObjectId);
// }
//THIS IS THE METHOD CALLED BY THE ATTACHMENT CONTROLLER
internal static bool Exists(AyaTypeId tid)
{
return Exists(tid.ObjectType, tid.ObjectId);
}
// //Returns existance status of object type and id specified in database
// internal static bool Exists(AyaType aytype, long id, AyContext ct = null)
// {
// //new up a context??
// if (ct == null)
// {
// ct = ServiceProviderProvider.DBContext;
// }
// switch (aytype)
// {
// case AyaType.User:
// return ct.User.Any(m => m.Id == id);
// case AyaType.Widget:
// return ct.Widget.Any(m => m.Id == id);
// case AyaType.FileAttachment:
// return ct.FileAttachment.Any(m => m.Id == id);
// case AyaType.DataListFilter:
// return ct.DataListFilter.Any(m => m.Id == id);
// case AyaType.DataListTemplate:
// return ct.DataListTemplate.Any(m => m.Id == id);
// case AyaType.FormCustom:
// return ct.FormCustom.Any(m => m.Id == id);
//Returns existance status of object type and id specified in database
internal static bool Exists(AyaType aytype, long id, AyContext ct = null)
{
//new up a context??
if (ct == null)
{
ct = ServiceProviderProvider.DBContext;
}
switch (aytype)
{
case AyaType.User:
return ct.User.Any(m => m.Id == id);
case AyaType.Widget:
return ct.Widget.Any(m => m.Id == id);
case AyaType.FileAttachment:
return ct.FileAttachment.Any(m => m.Id == id);
case AyaType.DataListFilter:
return ct.DataListFilter.Any(m => m.Id == id);
case AyaType.DataListTemplate:
return ct.DataListTemplate.Any(m => m.Id == id);
case AyaType.FormCustom:
return ct.FormCustom.Any(m => m.Id == id);
// default:
// throw new System.NotSupportedException($"AyaNova.BLL.BizObjectExistsInDatabase::Exists type {aytype.ToString()} is not supported");
// }
default:
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)
return false;
//Log modification
//Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
//Update keywords

View File

@@ -77,11 +77,14 @@ namespace AyaNova.Biz
//this will allow EF to check it out
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
Validate(dbObj, false);
if (!dataList.ValidateTemplate(dbObj.Template))
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template");
}
if (HasErrors)
return false;
//Log modification
//Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
return true;
@@ -93,232 +96,21 @@ namespace AyaNova.Biz
//
internal bool Delete(DataListTemplate dbObj)
{
//Determine if the object can be deleted, do the deletion tentatively
//Probably also in here deal with tags and associated search text etc
ValidateCanDelete(dbObj);
if (HasErrors)
return false;
//no validation required, we have defaults so this is ok anytime
ct.DataListTemplate.Remove(dbObj);
ct.SaveChanges();
//Delete sibling objects
//Event log process delete
EventLogProcessor.DeleteObject(UserId, BizType, dbObj.Id, dbObj.DataListKey, ct);
ct.SaveChanges();
//Delete search index
//Search.ProcessDeletedObjectKeywords(dbObj.Id, BizType);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//VALIDATION
//
//Can save or update?
private void Validate(DataListTemplate inObj, bool isNew)
{
//UserId required
if (!isNew)
{
if (inObj.UserId == 0)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "UserId");
}
// nothing special required here, it's all tightly controlled and datalist has validation code built in
//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);
//Log modification
//Log modification and save context
EventLogProcessor.LogEventToDatabaseAndSaveEntireContext(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
//Update keywords

View File

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

View File

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