This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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...
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user