diff --git a/server/AyaNova/Controllers/AttachmentController.cs b/server/AyaNova/Controllers/AttachmentController.cs
index 5da0efc0..964e1ddd 100644
--- a/server/AyaNova/Controllers/AttachmentController.cs
+++ b/server/AyaNova/Controllers/AttachmentController.cs
@@ -471,6 +471,7 @@ namespace AyaNova.Api.Controllers
//TODO: notify OPSNOTIFY
//TODO: notify this should trigger some kind of notification to the ops people
//and a red light on the dashboard
+ //TODO: this should reset the validity
var errText = $"Physical file {dbObj.StoredFileName} not found despite attachment record, this file is missing";
log.LogError(errText);
diff --git a/server/AyaNova/biz/AttachmentBiz.cs b/server/AyaNova/biz/AttachmentBiz.cs
new file mode 100644
index 00000000..09217c3c
--- /dev/null
+++ b/server/AyaNova/biz/AttachmentBiz.cs
@@ -0,0 +1,109 @@
+using System.Threading.Tasks;
+using AyaNova.Util;
+using AyaNova.Api.ControllerHelpers;
+using AyaNova.Models;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using AyaNova.Models;
+using AyaNova.Biz;
+using Microsoft.Extensions.Logging;
+using Bogus;
+using AyaNova.Api.ControllerHelpers;
+using System.Diagnostics;
+
+
+namespace AyaNova.Biz
+{
+
+
+ ///
+ /// Handle attachment file related cleanup and checking
+ ///
+ internal class AttachmentBiz : BizObject, IJobObject
+ {
+ internal AttachmentBiz(AyContext dbcontext, long currentUserId, AuthorizationRoles userRoles)
+ {
+ ct = dbcontext;
+ UserId = currentUserId;
+ CurrentUserRoles = userRoles;
+ BizType = AyaType.FileAttachment;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ //JOB / OPERATIONS
+ //
+ public async Task HandleJobAsync(OpsJob job)
+ {
+ //Hand off the particular job to the corresponding processing code
+ //NOTE: If this code throws an exception the caller (JobsBiz::ProcessJobsAsync) will automatically set the job to failed and log the exeption so
+ //basically any error condition during job processing should throw up an exception if it can't be handled
+
+ //There might be future other job types so doing it like this for all biz job handlers for now
+ switch (job.JobType)
+ {
+ case JobType.AttachmentMaintenance:
+ await ProcessAttachmentMaintenanceAsync(job);
+ break;
+ default:
+ throw new System.ArgumentOutOfRangeException($"AttachmentBiz.HandleJobAsync -> Invalid job type{job.JobType.ToString()}");
+ }
+ }
+
+
+ ///
+ /// Handle the job
+ ///
+ ///
+ private async Task ProcessAttachmentMaintenanceAsync(OpsJob job)
+ {
+ ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("AttachmentMaintenanceJob");
+ ApiServerState apiServerState = (ApiServerState)ServiceProviderProvider.Provider.GetService(typeof(ApiServerState));
+
+ //get the current server state so can set back to it later
+ ApiServerState.ServerState wasServerState = apiServerState.GetState();
+ string wasReason = apiServerState.Reason;
+ try
+ {
+ await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running);
+ await JobsBiz.LogJobAsync(job.GId, $"Starting...");
+ apiServerState.SetOpsOnly("Attachment file maintenance");
+
+ //JObject jobData = JObject.Parse(job.JobInfo);
+ // var seedLevel = (Seeder.Level.SeedLevel)jobData["seedLevel"].Value();
+ // var timeZoneOffset = jobData["timeZoneOffset"].Value();
+ // var seed = new Util.Seeder();
+ // await seed.SeedDatabaseAsync(seedLevel, job.GId, timeZoneOffset);
+
+
+ await JobsBiz.LogJobAsync(job.GId, "Finished.");
+ await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed);
+ }
+ catch (Exception ex)
+ {
+ log.LogError(ex, "AttachmentMaintenanceJob error during ops");
+
+ await JobsBiz.LogJobAsync(job.GId, $"AttachmentMaintenanceJob error during ops\r\n{ex.Message}");
+ throw ex;
+ }
+ finally
+ {
+ log.LogInformation($"AttachmentMaintenanceJob: setting server state back to {wasServerState.ToString()}");
+ apiServerState.SetState(wasServerState, wasReason);
+ }
+ }
+
+
+
+ //Other job handlers here...
+
+
+
+ /////////////////////////////////////////////////////////////////////
+
+ }//eoc
+
+
+}//eons
+
diff --git a/server/AyaNova/biz/JobType.cs b/server/AyaNova/biz/JobType.cs
index 1a02f375..bc97402c 100644
--- a/server/AyaNova/biz/JobType.cs
+++ b/server/AyaNova/biz/JobType.cs
@@ -12,7 +12,8 @@ namespace AyaNova.Biz
CoreJobSweeper = 2,
SeedTestData = 4,
BulkCoreBizObjectOperation = 5,
- Backup = 6
+ Backup = 6,
+ AttachmentMaintenance=7
}
diff --git a/server/AyaNova/biz/JobsBiz.cs b/server/AyaNova/biz/JobsBiz.cs
index 6c60c35e..46e2d0bf 100644
--- a/server/AyaNova/biz/JobsBiz.cs
+++ b/server/AyaNova/biz/JobsBiz.cs
@@ -284,6 +284,9 @@ namespace AyaNova.Biz
case JobType.SeedTestData:
o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.TrialSeeder, ct);
break;
+ case JobType.AttachmentMaintenance:
+ o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.FileAttachment, ct);
+ break;
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
diff --git a/server/AyaNova/models/FileAttachment.cs b/server/AyaNova/models/FileAttachment.cs
index 4b7908c8..7ca4f76f 100644
--- a/server/AyaNova/models/FileAttachment.cs
+++ b/server/AyaNova/models/FileAttachment.cs
@@ -7,9 +7,11 @@ namespace AyaNova.Models
public class FileAttachment
{
- public FileAttachment(){
+ public FileAttachment()
+ {
//all start out as synchronized
- InSync=true;
+ Exists = true;
+
}
public long Id { get; set; }
public uint Concurrency { get; set; }
@@ -30,6 +32,8 @@ namespace AyaNova.Models
public DateTime LastModified { get; set; }
public string Notes { get; set; }
- public bool InSync {get;set;}//was on disk last sync check
+ [Required]
+ public bool Exists { get; set; }//was on disk last sync check
+
}
}
\ No newline at end of file
diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs
index aec0604b..2e5db660 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 = 326;
+ internal const long EXPECTED_COLUMN_COUNT = 327;
internal const long EXPECTED_INDEX_COUNT = 134;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!
@@ -268,9 +268,9 @@ namespace AyaNova.Util
//await ExecQueryAsync("CREATE INDEX asearchkey_typeid_idx ON asearchkey (objectid, objecttype );");
//This is what is needed during Searching
- //search does a lot of hits on searchkey looking for the wordid and optionally objecttype
- //In testing this did not pan out, in fact it was much faster to search both with and without a objecttype specified to simply have an index on wordid
- // await ExecQueryAsync("CREATE INDEX asearchkey_wordid_otype_idx ON asearchkey (wordid, objecttype);");
+ //search does a lot of hits on searchkey looking for the wordid and optionally objecttype
+ //In testing this did not pan out, in fact it was much faster to search both with and without a objecttype specified to simply have an index on wordid
+ // await ExecQueryAsync("CREATE INDEX asearchkey_wordid_otype_idx ON asearchkey (wordid, objecttype);");
await ExecQueryAsync("CREATE INDEX asearchkey_wordid_idx ON asearchkey (wordid);");
//Search indexing stored procedure
@@ -391,7 +391,7 @@ $BODY$;
await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, " +
"attachtoobjectid bigint not null, attachtoobjecttype integer not null, " +
- "storedfilename text not null, displayfilename text not null, contenttype text, lastmodified timestamp not null, notes text, insync bool)");
+ "storedfilename text not null, displayfilename text not null, contenttype text, lastmodified timestamp not null, notes text, exists bool not null)");
//index required for ops that need to check if file already in db (delete, count refs etc)
//LOOKAT: isn't this useless without the ID as well or is that not fetched?
diff --git a/server/AyaNova/util/FileUtil.cs b/server/AyaNova/util/FileUtil.cs
index c33834fc..ea52351a 100644
--- a/server/AyaNova/util/FileUtil.cs
+++ b/server/AyaNova/util/FileUtil.cs
@@ -424,13 +424,13 @@ namespace AyaNova.Util
///
///
///
- internal static async Task DeleteFileAttachmentAsync(FileAttachment fileAttachmentToBeDeleted, AyContext ct)
+ internal static async Task DeleteFileAttachmentAsync(FileAttachment fileAttachmentToBeDeleted, AyContext ct)
{
//check ref count of file
var count = await ct.FileAttachment.LongCountAsync(z => z.StoredFileName == fileAttachmentToBeDeleted.StoredFileName);
- //Store in DB
+ //Remove from the DB
ct.FileAttachment.Remove(fileAttachmentToBeDeleted);
await ct.SaveChangesAsync();
@@ -448,7 +448,7 @@ namespace AyaNova.Util
}
//Return AyFileInfo object
- return fileAttachmentToBeDeleted;
+ return;
}