diff --git a/server/AyaNova/Controllers/TagController.cs b/server/AyaNova/Controllers/TagController.cs index d88b8f1c..81cf20f2 100644 --- a/server/AyaNova/Controllers/TagController.cs +++ b/server/AyaNova/Controllers/TagController.cs @@ -70,9 +70,10 @@ namespace AyaNova.Api.Controllers } - ///////////////////////////////// + ///////////////////////////////////////////////////////////// //BULK OPS // + // /// /// Bulk add tags to list of object id's specified @@ -102,7 +103,6 @@ namespace AyaNova.Api.Controllers JObject o = JObject.FromObject(new { idList = idList, - op = "add-tag", tag = tag }); @@ -110,6 +110,7 @@ namespace AyaNova.Api.Controllers j.Name = JobName; j.ObjectType = ayaType; j.JobType = JobType.BulkCoreBizObjectOperation; + j.SubType = JobSubType.TagAdd; j.Exclusive = false; j.JobInfo = o.ToString(); await JobsBiz.AddJobAsync(j, ct); @@ -142,7 +143,6 @@ namespace AyaNova.Api.Controllers var JobName = $"Bulk operation: Add tag \"{tag}\" on any {ayaType}"; JObject o = JObject.FromObject(new { - op = "add-any-tag", tag = tag }); @@ -150,6 +150,7 @@ namespace AyaNova.Api.Controllers j.Name = JobName; j.ObjectType = ayaType; j.JobType = JobType.BulkCoreBizObjectOperation; + j.SubType = JobSubType.TagAddAny; j.Exclusive = false; j.JobInfo = o.ToString(); await JobsBiz.AddJobAsync(j, ct); @@ -184,8 +185,7 @@ namespace AyaNova.Api.Controllers var JobName = $"Bulk operation: Remove tag \"{tag}\" from {ayaType} ({idList.Count} specified)"; JObject o = JObject.FromObject(new { - idList = idList, - op = "remove-tag", + idList = idList, tag = tag }); @@ -193,6 +193,7 @@ namespace AyaNova.Api.Controllers j.Name = JobName; j.ObjectType = ayaType; j.JobType = JobType.BulkCoreBizObjectOperation; + j.SubType = JobSubType.TagRemove; j.Exclusive = false; j.JobInfo = o.ToString(); await JobsBiz.AddJobAsync(j, ct); @@ -226,13 +227,13 @@ namespace AyaNova.Api.Controllers var JobName = $"Bulk operation: Remove tag \"{tag}\" from any {ayaType}"; JObject o = JObject.FromObject(new { - op = "remove-any-tag", tag = tag }); OpsJob j = new OpsJob(); j.Name = JobName; j.ObjectType = ayaType; + j.SubType = JobSubType.TagRemoveAny; j.JobType = JobType.BulkCoreBizObjectOperation; j.Exclusive = false; j.JobInfo = o.ToString(); @@ -273,7 +274,6 @@ namespace AyaNova.Api.Controllers JObject o = JObject.FromObject(new { idList = idList, - op = "replace-tag", fromTag = fromTag, toTag = toTag }); @@ -282,6 +282,7 @@ namespace AyaNova.Api.Controllers j.ObjectType = ayaType; j.Name = JobName; j.JobType = JobType.BulkCoreBizObjectOperation; + j.SubType = JobSubType.TagReplace; j.Exclusive = false; j.JobInfo = o.ToString(); await JobsBiz.AddJobAsync(j, ct); @@ -319,7 +320,6 @@ namespace AyaNova.Api.Controllers var JobName = $"Bulk operation: Replace tag \"{fromTag}\" with tag \"{toTag}\" on any {ayaType}"; JObject o = JObject.FromObject(new { - op = "replace-any-tag", fromTag = fromTag, toTag = toTag }); @@ -328,6 +328,7 @@ namespace AyaNova.Api.Controllers j.Name = JobName; j.ObjectType = ayaType; j.JobType = JobType.BulkCoreBizObjectOperation; + j.SubType = JobSubType.TagReplaceAny; j.Exclusive = false; j.JobInfo = o.ToString(); await JobsBiz.AddJobAsync(j, ct); diff --git a/server/AyaNova/biz/JobType.cs b/server/AyaNova/biz/JobType.cs index bcc43988..31ffeaa9 100644 --- a/server/AyaNova/biz/JobType.cs +++ b/server/AyaNova/biz/JobType.cs @@ -9,11 +9,25 @@ namespace AyaNova.Biz { NotSet = 0, TestWidgetJob = 1,//test job for unit testing - CoreJobSweeper = 2, + CoreJobSweeper = 2, SeedTestData = 4, BulkCoreBizObjectOperation = 5 } + /// + /// SubTypes for jobs that have further distinctions + /// + public enum JobSubType : int + { + NotSet = 0, + TagAdd = 1, + TagAddAny = 2, + TagRemove = 4, + TagRemoveAny = 5, + TagReplace = 6, + TagReplaceAny = 7 + + } }//eons \ No newline at end of file diff --git a/server/AyaNova/biz/JobsBiz.cs b/server/AyaNova/biz/JobsBiz.cs index 45e5724a..08e1b70a 100644 --- a/server/AyaNova/biz/JobsBiz.cs +++ b/server/AyaNova/biz/JobsBiz.cs @@ -396,8 +396,11 @@ namespace AyaNova.Biz /// internal static async Task ProcessJobAsync(OpsJob job, AyContext ct) { + var JobDescription = $"{job.Name} {job.JobType.ToString()}"; + if (job.SubType!=JobSubType.NotSet) + JobDescription += $":{job.SubType}"; - log.LogDebug($"ProcessJobAsync -> Processing job {job.Name} (type {job.JobType.ToString()})"); + log.LogDebug($"ProcessJobAsync -> Processing job {JobDescription}"); IJobObject o = null; switch (job.JobType) @@ -408,7 +411,9 @@ namespace AyaNova.Biz case JobType.SeedTestData: o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.TrialSeeder, ct); break; - case JobType.BulkCoreBizObjectOperation: + case JobType.BulkCoreBizObjectOperation: + //bulk op, hand off to biz object to deal with + //note, convention is that there is an idList in job.jobinfo json if preselected else it's all objects of type o = (IJobObject)BizObjectFactory.GetBizObject(job.ObjectType, ct); break; default: @@ -416,7 +421,7 @@ namespace AyaNova.Biz } await o.HandleJobAsync(job); - log.LogDebug($"ProcessJobAsync -> Job completed {job.Name} (type {job.JobType.ToString()})"); + log.LogDebug($"ProcessJobAsync -> Job completed {JobDescription}"); } diff --git a/server/AyaNova/biz/WidgetBiz.cs b/server/AyaNova/biz/WidgetBiz.cs index f6c7b0eb..29f08a73 100644 --- a/server/AyaNova/biz/WidgetBiz.cs +++ b/server/AyaNova/biz/WidgetBiz.cs @@ -4,6 +4,8 @@ using EnumsNET; using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Models; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; namespace AyaNova.Biz { @@ -42,7 +44,7 @@ namespace AyaNova.Biz if (HasErrors) return null; else - { + { newObject.Tags = TagBiz.NormalizeTags(newObject.Tags); newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields); await ct.Widget.AddAsync(newObject); @@ -173,7 +175,7 @@ namespace AyaNova.Biz //RESTART SERIAL // internal async Task RestartSerial(long newSerial) - { + { using (var command = ct.Database.GetDbConnection().CreateCommand()) { command.CommandText = $"alter table awidget alter column serial restart with {newSerial}"; @@ -286,6 +288,9 @@ namespace AyaNova.Biz //basically any error condition during job processing should throw up an exception if it can't be handled switch (job.JobType) { + case JobType.BulkCoreBizObjectOperation: + await ProcessBulkJobAsync(job); + break; case JobType.TestWidgetJob: await ProcessTestJobAsync(job); break; @@ -304,18 +309,50 @@ namespace AyaNova.Biz var sleepTime = 30 * 1000; //Simulate a long running job here await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running, ct); - await JobsBiz.LogJobAsync(job.GId, $"WidgetBiz::ProcessTestJob started, sleeping for {sleepTime} seconds...", ct); + await JobsBiz.LogJobAsync(job.GId, $"Widget ProcessTestJob started, sleeping for {sleepTime} seconds...", ct); //Uncomment this to test if the job prevents other routes from running //result is NO it doesn't prevent other requests, so we are a-ok for now await Task.Delay(sleepTime); - await JobsBiz.LogJobAsync(job.GId, "WidgetBiz::ProcessTestJob done sleeping setting job to finished", ct); + await JobsBiz.LogJobAsync(job.GId, "Widget ProcessTestJob done sleeping setting job to finished", ct); await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed, ct); } - //Other job handlers here... + + private async Task ProcessBulkJobAsync(OpsJob job) + { + + //Simulate a long running job here + await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running, ct); + await JobsBiz.LogJobAsync(job.GId, $"Widget BulkJob {job.SubType} started...", ct); + + List idList = new List(); + + JObject jobData = JObject.Parse(job.JobInfo); + if (jobData.ContainsKey("idList")) + { + idList = jobData["idList"].Value>(); + } + else{ + //we need to fetch a list of them all because ALL items was selected + } + var seedLevel = (Seeder.SeedLevel)jobData["seedLevel"].Value(); + var timeZoneOffset = jobData["timeZoneOffset"].Value(); + + //either process an id list or fetch all objects and process + + //call out processor for each item in turn + switch (job.SubType) + { + case JobSubType.TagAdd: + } + + await JobsBiz.LogJobAsync(job.GId, $"Widget BulkJob {job.SubType} completed", ct); + await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed, ct); + + } ///////////////////////////////////////////////////////////////////// diff --git a/server/AyaNova/models/OpsJob.cs b/server/AyaNova/models/OpsJob.cs index 32567502..ace1f11e 100644 --- a/server/AyaNova/models/OpsJob.cs +++ b/server/AyaNova/models/OpsJob.cs @@ -17,7 +17,7 @@ namespace AyaNova.Models public DateTime Created { get; set; } public uint Concurrency { get; set; } - + [Required] public string Name { get; set; } @@ -27,10 +27,12 @@ namespace AyaNova.Models public DateTime StartAfter { get; set; } [Required] public JobType JobType { get; set; } + public JobSubType SubType { get; set; } public long ObjectId { get; set; } public AyaType ObjectType { get; set; } [Required] public JobStatus JobStatus { get; set; } + /// /// Json string of any required extra info for job /// @@ -45,6 +47,7 @@ namespace AyaNova.Models Exclusive = false; StartAfter = Created; JobType = JobType.NotSet; + SubType = JobSubType.NotSet; ObjectId = 0; ObjectType = AyaType.NoType; JobStatus = JobStatus.Sleeping; diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index 77c38571..bb5de7d4 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -22,7 +22,7 @@ namespace AyaNova.Util //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!! private const int DESIRED_SCHEMA_LEVEL = 11; - internal const long EXPECTED_COLUMN_COUNT = 305; + internal const long EXPECTED_COLUMN_COUNT = 306; internal const long EXPECTED_INDEX_COUNT = 134; //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!! @@ -270,7 +270,7 @@ namespace AyaNova.Util LogUpdateMessage(log); await ExecQueryAsync("CREATE TABLE aopsjob (gid uuid PRIMARY KEY, name text not null, created timestamp not null, exclusive bool not null, " + - "startafter timestamp not null, jobtype integer not null, objectid bigint null, objecttype integer null, jobstatus integer not null, jobinfo text null)"); + "startafter timestamp not null, jobtype integer not null, subtype integer null, objectid bigint null, objecttype integer null, jobstatus integer not null, jobinfo text null)"); await ExecQueryAsync("CREATE TABLE aopsjoblog (gid uuid PRIMARY KEY, jobid uuid not null REFERENCES aopsjob (gid), created timestamp not null, statustext text not null)"); await SetSchemaLevelAsync(++currentSchema);