146 lines
5.9 KiB
C#
146 lines
5.9 KiB
C#
using System.Threading.Tasks;
|
|
using AyaNova.Util;
|
|
using AyaNova.Api.ControllerHelpers;
|
|
using AyaNova.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
using System;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.Linq;
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
|
|
// EXISTENCE CHECK
|
|
//iterate all records in chunks
|
|
bool moreRecords = true;
|
|
int skip = 0;
|
|
int chunkSize = 100;
|
|
do
|
|
{
|
|
var chunk = await ct.FileAttachment.AsNoTracking().OrderBy(z => z.Id).Skip(skip).Take(chunkSize).Select(z => new NameIdItem { Id = z.Id, Name = z.StoredFileName }).ToListAsync();
|
|
if (chunk.Count < chunkSize)
|
|
{
|
|
//we've reached the end
|
|
moreRecords = false;
|
|
}
|
|
skip += chunkSize;
|
|
foreach (NameIdItem i in chunk)
|
|
{
|
|
//Does file exists where it's supposed to be?
|
|
if (!FileUtil.AttachmentFileExists(i.Name))
|
|
{
|
|
var f = await ct.FileAttachment.FirstOrDefaultAsync(z => z.Id == i.Id);
|
|
if (f != null)
|
|
{
|
|
f.Exists = false;
|
|
await ct.SaveChangesAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (moreRecords);
|
|
// long totalRecs = await ct.FileAttachment.LongCountAsync();
|
|
|
|
var allAttachments = FileUtil.GetAllAttachmentFilePaths();
|
|
|
|
// iterate FileAttachment records, if physically present then flag as such
|
|
// make sure it has a short circuit that if there are NO files physically then all are out of sync
|
|
// this scenario is someone moving a db and not moving physical files
|
|
// ORPHANED FILES CHECK
|
|
// These should never be out of sync due to timing issues, the file would be deleted before teh db record
|
|
// iterate physical files, if not in db then make a FileAttachment record for it AyaType nothing id 0
|
|
// if user want's to move them, they can download and then attach and then remove the generated attachment (Nothing id 0) the holder of orphaned files
|
|
// (Or move feature)
|
|
// DE-ORPHANIZE ACTION
|
|
// iterate orphaned file attachments to NOTHING type, if found to be attached to any other object remove the orphaned object attachement
|
|
|
|
|
|
|
|
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
|
|
|