using System.Linq; using System.Threading.Tasks; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Models; namespace AyaNova.Biz { internal class FormCustomBiz : BizObject { internal FormCustomBiz(AyContext dbcontext, long currentUserId, long userLocaleId, AuthorizationRoles UserRoles) { ct = dbcontext; UserId = currentUserId; UserLocaleId = userLocaleId; CurrentUserRoles = UserRoles; BizType = AyaType.FormCustom; } internal static FormCustomBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext) { return new FormCustomBiz(ct, UserIdFromContext.Id(httpContext.Items), UserLocaleIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); } //Version for internal use internal static FormCustomBiz GetBizInternal(AyContext ct) { return new FormCustomBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, AuthorizationRoles.BizAdminFull); } //////////////////////////////////////////////////////////////////////////////////////////////// //EXISTS internal async Task ExistsAsync(long id) { return await ct.FormCustom.AnyAsync(e => e.Id == id); } //////////////////////////////////////////////////////////////////////////////////////////////// /// GET internal async Task GetNoLogAsync(long fetchId) { //This is simple so nothing more here, but often will be copying to a different output object or some other ops return await ct.FormCustom.SingleOrDefaultAsync(m => m.Id == fetchId); } //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE internal async Task CreateAsync(FormCustom inObj) { Validate(inObj, true); if (HasErrors) return null; else { //do stuff with datafilter FormCustom outObj = inObj; outObj.OwnerId = UserId; await ct.FormCustom.AddAsync(outObj); await ct.SaveChangesAsync(); //Handle child and associated items: //EVENT LOG EventLogProcessor.LogEventToDatabase(new Event(UserId, outObj.Id, BizType, AyaEvent.Created), ct); //SEARCH INDEXING // Search.ProcessNewObjectKeywords(UserLocaleId, outObj.Id, BizType, outObj.Name, outObj.Name); return outObj; } } //////////////////////////////////////////////////////////////////////////////////////////////// /// GET //Get one internal async Task GetAsync(string formKey) { var ret = await ct.FormCustom.SingleOrDefaultAsync(m => m.FormKey == formKey); //Do not log this, it's going to be called a zillion times anyway return ret; } //////////////////////////////////////////////////////////////////////////////////////////////// //UPDATE // //put internal bool Put(FormCustom dbObj, FormCustom inObj) { //preserve the owner ID if none was specified if (inObj.OwnerId == 0) inObj.OwnerId = dbObj.OwnerId; //Replace the db object with the PUT object CopyObject.Copy(inObj, dbObj, "Id"); //Set "original" value of concurrency token to input token //this will allow EF to check it out ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken; Validate(dbObj, false); if (HasErrors) return false; //Log modification EventLogProcessor.LogEventToDatabase(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); //Update keywords // Search.ProcessUpdatedObjectKeywords(UserLocaleId, dbObj.Id, BizType, dbObj.Name, dbObj.Name); return true; } //NO DELETE, ONLY EDIT //////////////////////////////////////////////////////////////////////////////////////////////// //VALIDATION // //Can save or update? private void Validate(FormCustom inObj, bool isNew) { //OwnerId required if (!isNew) { if (inObj.OwnerId == 0) AddError(ValidationErrorType.RequiredPropertyEmpty, "OwnerId"); } // //Owner must be current user, there are no exceptions // if (inObj.OwnerId != UserId) // AddError(ValidationErrorType.InvalidValue, "OwnerId", "OwnerId must be current user Id"); //FormKey required if (string.IsNullOrWhiteSpace(inObj.FormKey)) AddError(ValidationErrorType.RequiredPropertyEmpty, "FormKey"); //FormKey must be less than 255 characters if (inObj.FormKey.Length > 255) AddError(ValidationErrorType.LengthExceeded, "FormKey", "255 max"); //If name is otherwise OK, check that name is unique if (!PropertyHasErrors("FormKey")) { //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false if (ct.FormCustom.Any(m => m.FormKey == inObj.FormKey && m.Id != inObj.Id)) { AddError(ValidationErrorType.NotUnique, "FormKey"); } } //Template json must parse if (!string.IsNullOrWhiteSpace(inObj.Template)) { try { var v = JArray.Parse(inObj.Template); /* Example: {template:[{fld:"ltkeyfieldname",hide:"true/false",required:"true/false", type:"bool"},{fld:"ltkeyfieldname",hide:"true/false",required:"true/false", type:"text"]} */ //Validate the following: //FormKey is valid value //All fields specified are valid values //Field is allowed to be hidden if hidden //Type is one of the valid types: /* public const string Date = "date"; public const string Text = "text"; public const string Integer = "int"; public const string Bool = "bool"; public const string Decimal = "decimal"; */ //TODO: validate the json /* - JSON FRAGMENT holds items that differ from stock, no "core" fields allowed - FieldKey - Hide - Required - Type (checkbox, date, date time, decimal, number, picklist(FUTURE), and text) */ // for (int i = 0; i < v.Count; i++) // { // var filterItem = v[i]; // if (filterItem["fld"] == null) // AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, object is missing required \"fld\" property "); // else // { // var fld = filterItem["fld"].Value(); // if (string.IsNullOrWhiteSpace(fld)) // AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, \"fld\" property is empty and required"); // //validate the field name if we can // if (ListValidFilterOptions != null) // { // if (!ListValidFilterOptions.Flds.Exists(x => x.Fld == fld)) // { // AddError(ValidationErrorType.InvalidValue, "Filter", $"Filter array item {i}, fld property value \"{fld}\" is not a valid value for ListKey specified"); // } // } // } // if (filterItem["op"] == null) // AddError(ValidationErrorType.RequiredPropertyEmpty, "Filter", $"Filter array item {i}, object is missing required \"op\" property "); // else // { // var opType = filterItem["op"].Value(); // if (!FilterComparisonOperator.Operators.Contains(opType)) // AddError(ValidationErrorType.InvalidValue, "Filter", $"Filter array item {i}, \"op\" property value of \"{opType}\" is not a valid FilterComparisonOperator type"); // } // if (filterItem["value"] == null) // AddError(ValidationErrorType.RequiredPropertyEmpty, "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())) // AddError(ValidationErrorType.RequiredPropertyEmpty, "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(ValidationErrorType.RequiredPropertyEmpty, "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(ValidationErrorType.InvalidValue, "Template", "Template is not valid JSON string: " + ex.Message); } } return; } // //Can delete? // private void ValidateCanDelete(FormCustom inObj) // { // //Leaving this off for now // } ///////////////////////////////////////////////////////////////////// }//eoc }//eons