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(string formKey) { return await ct.FormCustom.AnyAsync(x => x.FormKey == formKey); } //////////////////////////////////////////////////////////////////////////////////////////////// /// GET internal async Task GetNoLogAsync(string formKey) { //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(x => x.FormKey == formKey); } //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE internal async Task CreateAsync(FormCustom inObj) { Validate(inObj, true); if (HasErrors) return null; else { //do stuff with object FormCustom outObj = inObj; 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) { //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) { //FormKey required and must be valid if (string.IsNullOrWhiteSpace(inObj.FormKey)) AddError(ApiErrorCode.VALIDATION_REQUIRED, "FormKey"); else { if (!FormAvailableFields.IsValidFormKey(inObj.FormKey)) { AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "FormKey"); } } //FormKey must be less than 255 characters if (inObj.FormKey.Length > 255) AddError(ApiErrorCode.VALIDATION_LENGTH_EXCEEDED, "FormKey", "255 max"); //If name is otherwise OK, check that name is unique if (!PropertyHasErrors("FormKey") && isNew) { //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(ApiErrorCode.VALIDATION_NOT_UNIQUE, "FormKey"); } } //Template json must parse if ((!PropertyHasErrors("FormKey") && !string.IsNullOrWhiteSpace(inObj.Template))) { var ValidCustomFieldTypes = AyDataType.ValidCustomFieldTypes; var ValidFormFields = FormAvailableFields.FormFields(inObj.FormKey); try { //Parse the json, expecting something like this: //[{fld:"ltkeyfieldname",hide:"true/false",required:"true/false", type:"bool"},{fld:"ltkeyfieldname",hide:"true/false",required:"true/false", type:"text"] //Array at root is valid json and saves a bit of bandwidth so minimal is best var v = JArray.Parse(inObj.Template); for (int i = 0; i < v.Count; i++) { FormField MasterFormField = null; var formFieldItem = v[i]; if (formFieldItem["fld"] == null) AddError(ApiErrorCode.VALIDATION_REQUIRED, "Template", $"Template array item {i}, object is missing required \"fld\" property "); else { var fldKey = formFieldItem["fld"].Value(); if (string.IsNullOrWhiteSpace(fldKey)) AddError(ApiErrorCode.VALIDATION_REQUIRED, "Template", $"Template array item {i}, \"fld\" property is empty and required"); //validate the field name if we can if (ValidFormFields != null) { if (!ValidFormFields.Exists(x => x.Key == fldKey)) { AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template", $"Template array item {i}, fld property value \"{fldKey}\" is not a valid form field value for formKey specified"); } else { MasterFormField = ValidFormFields.FirstOrDefault(x => x.Key == fldKey); } } } if (MasterFormField != null) { if (formFieldItem["hide"] != null) { var fieldHideValue = formFieldItem["hide"].Value(); if (!MasterFormField.Hideable && fieldHideValue == true) AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template", $"Template array item {i}, \"hide\" property value of \"{fieldHideValue}\" is not valid, this field is core and cannot be hidden"); } if (formFieldItem["type"] != null) { if (!MasterFormField.Custom) AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template", $"Template array item {i}, \"type\" property value is not valid, only Custom fields can have types specified"); else {//It is a custom field, is it a valid type value var templateFieldCustomTypeValue = formFieldItem["type"].Value(); if (!ValidCustomFieldTypes.Contains(templateFieldCustomTypeValue)) AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template", $"Template array item {i}, \"type\" property value of \"{templateFieldCustomTypeValue}\" is not a valid custom field type"); } } } if (formFieldItem["required"] == null) AddError(ApiErrorCode.VALIDATION_REQUIRED, "Template", $"Template array item {i}, object is missing required \"required\" property "); //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, "Template", "Template is not valid JSON string: " + ex.Message); } } return; } // //Can delete? // private void ValidateCanDelete(FormCustom inObj) // { // //Leaving this off for now // } ///////////////////////////////////////////////////////////////////// }//eoc }//eons