From 53d1456e6f6deb4d3cfd4f4aca997e3f5695eaba Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Wed, 13 May 2020 21:05:33 +0000 Subject: [PATCH] --- server/AyaNova/biz/CustomerBiz.cs | 162 ++++++++++++++--------------- server/AyaNova/biz/WorkOrderBiz.cs | 32 +++--- 2 files changed, 91 insertions(+), 103 deletions(-) diff --git a/server/AyaNova/biz/CustomerBiz.cs b/server/AyaNova/biz/CustomerBiz.cs index b7261873..948e6e27 100644 --- a/server/AyaNova/biz/CustomerBiz.cs +++ b/server/AyaNova/biz/CustomerBiz.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; - using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Models; @@ -22,10 +21,9 @@ namespace AyaNova.Biz internal static CustomerBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) { - if (httpContext != null) return new CustomerBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); - else//when called internally for internal ops there will be no context so need to set default values for that + else return new CustomerBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdminFull); } @@ -38,9 +36,6 @@ namespace AyaNova.Biz return await ct.Customer.AnyAsync(e => e.Id == id); } - - - //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE // @@ -62,13 +57,9 @@ namespace AyaNova.Biz } } - - - //////////////////////////////////////////////////////////////////////////////////////////////// //DUPLICATE // - internal async Task DuplicateAsync(long id) { Customer dbObject = await GetAsync(id, false); @@ -91,7 +82,7 @@ namespace AyaNova.Biz newObject.Id = 0; newObject.Concurrency = 0; await ct.Customer.AddAsync(newObject); - await ct.SaveChangesAsync(); + await ct.SaveChangesAsync(); await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); await SearchIndexAsync(newObject, true); await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); @@ -99,64 +90,96 @@ namespace AyaNova.Biz } //////////////////////////////////////////////////////////////////////////////////////////////// - /// GET - /// - /// - - internal async Task GetAsync(long fetchId, bool logTheGetEvent = true) + // GET + // + // + internal async Task GetAsync(long id, bool logTheGetEvent = true) { - //This is simple so nothing more here, but often will be copying to a different output object or some other ops - var ret = await ct.Customer.SingleOrDefaultAsync(m => m.Id == fetchId); + var ret = await ct.Customer.SingleOrDefaultAsync(m => m.Id == id); if (logTheGetEvent && ret != null) - { - //Log - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, fetchId, BizType, AyaEvent.Retrieved), ct); - } + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, AyaEvent.Retrieved), ct); return ret; } //////////////////////////////////////////////////////////////////////////////////////////////// //UPDATE // - - //put - internal async Task PutAsync(Customer dbObj, Customer inObj) + internal async Task PutAsync(Customer putObject) { - - //make a snapshot of the original for validation but update the original to preserve workflow + Customer dbObject = await ct.Customer.SingleOrDefaultAsync(m => m.Id == putObject.Id); + if (dbObject == null) + { + AddError(ApiErrorCode.NOT_FOUND, "id"); + return null; + } Customer SnapshotOfOriginalDBObj = new Customer(); - CopyObject.Copy(dbObj, SnapshotOfOriginalDBObj); - - //Replace the db object with the PUT object - CopyObject.Copy(inObj, dbObj, "Id"); - - dbObj.Tags = TagUtil.NormalizeTags(dbObj.Tags); - dbObj.CustomFields = JsonUtil.CompactJson(dbObj.CustomFields); - - //Set "original" value of concurrency token to input token - //this will allow EF to check it out - ct.Entry(dbObj).OriginalValues["Concurrency"] = inObj.Concurrency; - - - await ValidateAsync(dbObj, SnapshotOfOriginalDBObj); - if (HasErrors) - return false; - - //Log event and save context - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); - await SearchIndexAsync(dbObj, false); - await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, dbObj.Tags, SnapshotOfOriginalDBObj.Tags); - - return true; + CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj); + CopyObject.Copy(putObject, dbObject, "Id"); + dbObject.Tags = TagUtil.NormalizeTags(dbObject.Tags); + dbObject.CustomFields = JsonUtil.CompactJson(dbObject.CustomFields); + ct.Entry(dbObject).OriginalValues["Concurrency"] = putObject.Concurrency; + await ValidateAsync(dbObject, SnapshotOfOriginalDBObj); + if (HasErrors) return null; + try + { + await ct.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!await ExistsAsync(putObject.Id)) + AddError(ApiErrorCode.NOT_FOUND); + else + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); + return null; + } + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); + await SearchIndexAsync(dbObject, false); + await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, dbObject.Tags, SnapshotOfOriginalDBObj.Tags); + return dbObject; } + //////////////////////////////////////////////////////////////////////////////////////////////// + //DELETE + // + internal async Task DeleteAsync(long id) + { + using (var transaction = await ct.Database.BeginTransactionAsync()) + { + try + { + Customer dbObject = await ct.Customer.SingleOrDefaultAsync(m => m.Id == id); + ValidateCanDelete(dbObject); + if (HasErrors) + return false; + if (HasErrors) + return false; + ct.Customer.Remove(dbObject); + await ct.SaveChangesAsync(); + + //Log event + await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct); + await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType); + await TagUtil.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags); + //all good do the commit + await transaction.CommitAsync(); + } + catch + { + //Just re-throw for now, let exception handler deal, but in future may want to deal with this more here + throw; + } + return true; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // SEARCH + // private async Task SearchIndexAsync(Customer obj, bool isNew) { - //SEARCH INDEXING var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType); SearchParams.AddText(obj.Notes).AddText(obj.Name).AddText(obj.Wiki).AddText(obj.Tags).AddCustomFields(obj.CustomFields); - if (isNew) await Search.ProcessNewObjectKeywordsAsync(SearchParams); else @@ -172,38 +195,14 @@ namespace AyaNova.Biz return SearchParams; } - //////////////////////////////////////////////////////////////////////////////////////////////// - //DELETE - // - internal async Task DeleteAsync(Customer dbObj) - { - //Determine if the object can be deleted, do the deletion tentatively - //Probably also in here deal with tags and associated search text etc - - //NOT REQUIRED NOW BUT IF IN FUTURE ValidateCanDelete(dbObj); - if (HasErrors) - return false; - ct.Customer.Remove(dbObj); - await ct.SaveChangesAsync(); - - //Log event - await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObj.Id, dbObj.Name, ct); - await Search.ProcessDeletedObjectKeywordsAsync(dbObj.Id, BizType); - await TagUtil.ProcessDeleteTagsInRepositoryAsync(ct, dbObj.Tags); - return true; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// //VALIDATION // - //Can save or update? private async Task ValidateAsync(Customer proposedObj, Customer currentObj) { - //run validation and biz rules bool isNew = currentObj == null; //Name required @@ -240,13 +239,10 @@ namespace AyaNova.Biz } - - //Can delete? - // private void ValidateCanDelete(Customer inObj) - // { - // //whatever needs to be check to delete this object - // } - + private void ValidateCanDelete(Customer inObj) + { + //whatever needs to be check to delete this object + } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs index 45160e35..1ff365b9 100644 --- a/server/AyaNova/biz/WorkOrderBiz.cs +++ b/server/AyaNova/biz/WorkOrderBiz.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Models; @@ -74,7 +73,6 @@ namespace AyaNova.Biz } } - //////////////////////////////////////////////////////////////////////////////////////////////// //DUPLICATE // @@ -99,8 +97,6 @@ namespace AyaNova.Biz return newObject; } - - //////////////////////////////////////////////////////////////////////////////////////////////// // GET // @@ -139,21 +135,17 @@ namespace AyaNova.Biz return ret; } - - //////////////////////////////////////////////////////////////////////////////////////////////// //UPDATE // internal async Task WorkOrderPutAsync(dtWorkOrder dtPutObject) { - WorkOrder dbObject = await ct.WorkOrder.SingleOrDefaultAsync(m => m.Id == dtPutObject.Id); if (dbObject == null) { AddError(ApiErrorCode.NOT_FOUND, "id"); return null; } - // make a snapshot of the original for validation but update the original to preserve workflow WorkOrder SnapshotOfOriginalDBObj = new WorkOrder(); CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj); @@ -184,7 +176,7 @@ namespace AyaNova.Biz if (!await WorkOrderExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); @@ -428,7 +420,7 @@ namespace AyaNova.Biz if (!await ItemExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItem, AyaEvent.Modified), ct); @@ -491,7 +483,7 @@ namespace AyaNova.Biz foreach (long ItemId in UnitIds) if (!await UnitDeleteAsync(ItemId)) return false; - + ct.WorkOrderItem.Remove(dbObject); await ct.SaveChangesAsync(); @@ -677,7 +669,7 @@ namespace AyaNova.Biz if (!await ExpenseExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemExpense, AyaEvent.Modified), ct); @@ -866,7 +858,7 @@ namespace AyaNova.Biz if (!await LaborExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemLabor, AyaEvent.Modified), ct); @@ -1054,7 +1046,7 @@ namespace AyaNova.Biz if (!await LoanExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemLoan, AyaEvent.Modified), ct); @@ -1243,7 +1235,7 @@ namespace AyaNova.Biz if (!await PartExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemPart, AyaEvent.Modified), ct); @@ -1429,7 +1421,7 @@ namespace AyaNova.Biz if (!await PartRequestExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemPartRequest, AyaEvent.Modified), ct); @@ -1618,7 +1610,7 @@ namespace AyaNova.Biz if (!await ScheduledUserExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemScheduledUser, AyaEvent.Modified), ct); @@ -1807,7 +1799,7 @@ namespace AyaNova.Biz if (!await TaskExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemTask, AyaEvent.Modified), ct); @@ -1996,7 +1988,7 @@ namespace AyaNova.Biz if (!await TravelExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemTravel, AyaEvent.Modified), ct); @@ -2185,7 +2177,7 @@ namespace AyaNova.Biz if (!await UnitExistsAsync(dtPutObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else - new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT); + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, AyaType.WorkOrderItemUnit, AyaEvent.Modified), ct);