This commit is contained in:
@@ -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);
|
||||
|
||||
109
server/AyaNova/biz/AttachmentBiz.cs
Normal file
109
server/AyaNova/biz/AttachmentBiz.cs
Normal file
@@ -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
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle attachment file related cleanup and checking
|
||||
/// </summary>
|
||||
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()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle the job
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
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<int>();
|
||||
// var timeZoneOffset = jobData["timeZoneOffset"].Value<decimal>();
|
||||
// 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
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace AyaNova.Biz
|
||||
CoreJobSweeper = 2,
|
||||
SeedTestData = 4,
|
||||
BulkCoreBizObjectOperation = 5,
|
||||
Backup = 6
|
||||
Backup = 6,
|
||||
AttachmentMaintenance=7
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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?
|
||||
|
||||
@@ -424,13 +424,13 @@ namespace AyaNova.Util
|
||||
/// <param name="fileAttachmentToBeDeleted"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
internal static async Task<FileAttachment> 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user