diff --git a/.vscode/launch.json b/.vscode/launch.json index 0e2049e9..8fd97968 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -53,7 +53,7 @@ "AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles", "AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles", "AYANOVA_FOLDER_TEMPORARY_SERVER_FILES": "c:\\temp\\RavenTestData\\tempfiles", - "AYANOVA_SERVER_TEST_MODE": "false", + "AYANOVA_SERVER_TEST_MODE": "true", "AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small", "AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7", "AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\" diff --git a/server/AyaNova/Controllers/JobOperationsController.cs b/server/AyaNova/Controllers/JobOperationsController.cs index 0dce6404..0c0007cd 100644 --- a/server/AyaNova/Controllers/JobOperationsController.cs +++ b/server/AyaNova/Controllers/JobOperationsController.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using AyaNova.Models; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; +using Newtonsoft.Json.Linq; namespace AyaNova.Api.Controllers @@ -177,6 +178,59 @@ namespace AyaNova.Api.Controllers return Accepted(new { JobId = j.GId });//202 accepted } + + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // EXTENSION BULK JOBS + // + // + + + /// + /// Bulk DELETE list of object id's specified + /// + /// + /// Job Id + [HttpPost("bulk-delete")] + public async Task BulkAdd([FromBody] DataListSelection dataListSelection) + { + if (!serverState.IsOpen) + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); + + if (dataListSelection.IsEmpty) + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, null, "DataListSelection is required")); + + + if (!Authorized.HasDeleteRole(HttpContext.Items, dataListSelection.ObjectType)) + return StatusCode(403, new ApiNotAuthorizedResponse()); + + + await dataListSelection.RehydrateIdList(ct, UserRolesFromContext.Roles(HttpContext.Items), log); + if (dataListSelection.SelectedRowIds.Length == 0) + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, null, "List of ids")); + + var JobName = $"Bulk operation: DELETE on {dataListSelection.ObjectType} ({dataListSelection.SelectedRowIds.LongLength} specified)"; + JObject o = JObject.FromObject(new + { + idList = dataListSelection.SelectedRowIds + }); + + OpsJob j = new OpsJob(); + j.Name = JobName; + j.ObjectType = dataListSelection.ObjectType; + j.JobType = JobType.BulkCoreBizObjectOperation; + j.SubType = JobSubType.Delete; + j.Exclusive = false; + j.JobInfo = o.ToString(); + await JobsBiz.AddJobAsync(j); + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.ServerJob, AyaEvent.Created, JobName), ct); + return Accepted(new { JobId = j.GId }); + } + + //------------ diff --git a/server/AyaNova/Controllers/TagController.cs b/server/AyaNova/Controllers/TagController.cs index 623bf4d0..02dfb163 100644 --- a/server/AyaNova/Controllers/TagController.cs +++ b/server/AyaNova/Controllers/TagController.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; diff --git a/server/AyaNova/biz/JobType.cs b/server/AyaNova/biz/JobType.cs index bc97402c..78687625 100644 --- a/server/AyaNova/biz/JobType.cs +++ b/server/AyaNova/biz/JobType.cs @@ -13,7 +13,7 @@ namespace AyaNova.Biz SeedTestData = 4, BulkCoreBizObjectOperation = 5, Backup = 6, - AttachmentMaintenance=7 + AttachmentMaintenance = 7 } @@ -28,7 +28,8 @@ namespace AyaNova.Biz TagRemove = 3, TagRemoveAny = 4, TagReplace = 5, - TagReplaceAny = 6 + TagReplaceAny = 6, + Delete = 7 } }//eons \ No newline at end of file diff --git a/server/AyaNova/biz/WidgetBiz.cs b/server/AyaNova/biz/WidgetBiz.cs index c3537a7d..316d2cb9 100644 --- a/server/AyaNova/biz/WidgetBiz.cs +++ b/server/AyaNova/biz/WidgetBiz.cs @@ -154,7 +154,8 @@ namespace AyaNova.Biz try { Widget dbObject = await ct.Widget.SingleOrDefaultAsync(z => z.Id == id); - if (dbObject == null){ + if (dbObject == null) + { AddError(ApiErrorCode.NOT_FOUND); return false; } @@ -230,9 +231,9 @@ namespace AyaNova.Biz // private async Task ValidateAsync(Widget proposedObj) { - //skip validation if seeding - if(ServerBootConfig.SEEDING) return; - + //skip validation if seeding + if (ServerBootConfig.SEEDING) return; + //NOTE: In DB schema only name and serial are not nullable //run validation and biz rules @@ -403,7 +404,10 @@ namespace AyaNova.Biz { SaveIt = false; ClearErrors(); - var o = await GetAsync(id, false); + Widget o = null; + //save a fetch if it's a delete + if (job.SubType != JobSubType.Delete) + o = await GetAsync(id, false); switch (job.SubType) { case JobSubType.TagAddAny: @@ -414,6 +418,11 @@ namespace AyaNova.Biz case JobSubType.TagReplace: SaveIt = TagBiz.ProcessBulkTagOperation(o.Tags, (string)jobData["tag"], jobData.ContainsKey("toTag") ? (string)jobData["toTag"] : null, job.SubType); break; + case JobSubType.Delete: + if(!await DeleteAsync(id)){ + await JobsBiz.LogJobAsync(job.GId, $"Error processing item {id}: {GetErrorsAsString()}"); + } + break; default: throw new System.ArgumentOutOfRangeException($"ProcessBulkJob -> Invalid job Subtype{job.SubType}"); }