diff --git a/server/AyaNova/Controllers/AttachmentController.cs b/server/AyaNova/Controllers/AttachmentController.cs index 79d2dff6..fa8d5bef 100644 --- a/server/AyaNova/Controllers/AttachmentController.cs +++ b/server/AyaNova/Controllers/AttachmentController.cs @@ -259,7 +259,7 @@ namespace AyaNova.Api.Controllers if (!badRequest) { //check if object exists - if (!await BizObjectExistsInDatabase.ExistsAsync(attachToObject, ct)) + if (!await BizObjectExistsInDatabase.ExistsAsync(attachToObject.ObjectType, attachToObject.ObjectId, ct)) { badRequest = true; errorMessage = "Invalid attach object"; diff --git a/server/AyaNova/biz/AttachmentBiz.cs b/server/AyaNova/biz/AttachmentBiz.cs index 05d1da28..b49e9539 100644 --- a/server/AyaNova/biz/AttachmentBiz.cs +++ b/server/AyaNova/biz/AttachmentBiz.cs @@ -78,7 +78,7 @@ namespace AyaNova.Biz int chunkSize = 100; do { - var chunk = await ct.FileAttachment.AsNoTracking().OrderBy(z => z.Id).Skip(skip).Take(chunkSize).Select(z => new { z.Id, z.StoredFileName, z.Exists }).ToListAsync(); + var chunk = await ct.FileAttachment.AsNoTracking().OrderBy(z => z.Id).Skip(skip).Take(chunkSize).ToListAsync(); if (chunk.Count < chunkSize) { //we've reached the end @@ -90,17 +90,26 @@ namespace AyaNova.Biz var FullPathName = FileUtil.GetPermanentAttachmentFilePath(i.StoredFileName); AllDBFileFullPath.Add(FullPathName); var FileExistsInReality = AllAttachmentFilesOnDisk.Contains(FullPathName); + var ParentBizObjectExistsInReality = await BizObjectExistsInDatabase.ExistsAsync(i.AttachToObjectType, i.AttachToObjectId, ct); //does the db record reflect the same status as reality? - if (FileExistsInReality != i.Exists) + if (FileExistsInReality != i.Exists || !ParentBizObjectExistsInReality) { - //Nope so update it to be the same var f = await ct.FileAttachment.FirstOrDefaultAsync(z => z.Id == i.Id); if (f != null) { f.Exists = FileExistsInReality; + if (!ParentBizObjectExistsInReality) + { + //switch it to notype + f.AttachToObjectType = AyaType.NoType; + f.AttachToObjectId = 0; + } await ct.SaveChangesAsync(); } } + + //DOES THE PARENT OBJECT EXIST? + } } while (moreRecords); @@ -125,7 +134,8 @@ namespace AyaNova.Biz // ORPHANED FILES CHECK var FilesOnDiskNotInDb = AllAttachmentFilesOnDisk.Except(AllDBFileFullPath); - await JobsBiz.LogJobAsync(job.GId, $"Found {FilesOnDiskNotInDb.Count()} physical files not known to be existing Attachments, creating attachment records tied to 'NoType' so they show in UI"); + if (FilesOnDiskNotInDb.Count() > 0) + await JobsBiz.LogJobAsync(job.GId, $"Found {FilesOnDiskNotInDb.Count()} physical files not known to be existing Attachments, creating attachment records tied to 'NoType' so they show in UI"); // FOREIGN FILES placed in folder directly outside of attachment system // user thinks they can just drop them in or accidentally copies them here diff --git a/server/AyaNova/biz/BizObjectExistsInDatabase.cs b/server/AyaNova/biz/BizObjectExistsInDatabase.cs index d9a2dde2..b481305b 100644 --- a/server/AyaNova/biz/BizObjectExistsInDatabase.cs +++ b/server/AyaNova/biz/BizObjectExistsInDatabase.cs @@ -14,91 +14,93 @@ namespace AyaNova.Biz //Returns existance status of object type and id specified in database - internal static async Task ExistsAsync(AyaTypeId tid, AyContext ct) + + internal static async Task ExistsAsync(AyaType objectType, long id, AyContext ct) { //new up a context?? - switch (tid.ObjectType) + switch (objectType) { //CoreBizObject add here - + case AyaType.NoType://no type always exists and this is used by orphaned attachments + return true; case AyaType.FileAttachment: - return await ct.FileAttachment.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.FileAttachment.AnyAsync(z => z.Id == id); case AyaType.DataListView: - return await ct.DataListView.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.DataListView.AnyAsync(z => z.Id == id); case AyaType.FormCustom: - return await ct.FormCustom.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.FormCustom.AnyAsync(z => z.Id == id); case AyaType.User: - return await ct.User.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.User.AnyAsync(z => z.Id == id); case AyaType.Widget: - return await ct.Widget.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Widget.AnyAsync(z => z.Id == id); case AyaType.Customer: - return await ct.Customer.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Customer.AnyAsync(z => z.Id == id); case AyaType.Contract: - return await ct.Contract.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Contract.AnyAsync(z => z.Id == id); case AyaType.HeadOffice: - return await ct.HeadOffice.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.HeadOffice.AnyAsync(z => z.Id == id); case AyaType.LoanUnit: - return await ct.LoanUnit.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.LoanUnit.AnyAsync(z => z.Id == id); case AyaType.Part: - return await ct.Part.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Part.AnyAsync(z => z.Id == id); case AyaType.PM: - return await ct.PM.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.PM.AnyAsync(z => z.Id == id); case AyaType.PMItem: - return await ct.PMItem.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.PMItem.AnyAsync(z => z.Id == id); case AyaType.PMTemplate: - return await ct.PMTemplate.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.PMTemplate.AnyAsync(z => z.Id == id); case AyaType.PMTemplateItem: - return await ct.PMTemplateItem.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.PMTemplateItem.AnyAsync(z => z.Id == id); case AyaType.Project: - return await ct.Project.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Project.AnyAsync(z => z.Id == id); case AyaType.PurchaseOrder: - return await ct.PurchaseOrder.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.PurchaseOrder.AnyAsync(z => z.Id == id); case AyaType.Quote: - return await ct.Quote.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Quote.AnyAsync(z => z.Id == id); case AyaType.QuoteItem: - return await ct.QuoteItem.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.QuoteItem.AnyAsync(z => z.Id == id); case AyaType.QuoteTemplate: - return await ct.QuoteTemplate.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.QuoteTemplate.AnyAsync(z => z.Id == id); case AyaType.QuoteTemplateItem: - return await ct.QuoteTemplateItem.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.QuoteTemplateItem.AnyAsync(z => z.Id == id); case AyaType.Unit: - return await ct.Unit.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Unit.AnyAsync(z => z.Id == id); case AyaType.UnitModel: - return await ct.UnitModel.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.UnitModel.AnyAsync(z => z.Id == id); case AyaType.Vendor: - return await ct.Vendor.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.Vendor.AnyAsync(z => z.Id == id); //--- WorkOrder case AyaType.WorkOrder: - return await ct.WorkOrder.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrder.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItem: - return await ct.WorkOrderItem.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItem.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemExpense: - return await ct.WorkOrderItemExpense.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemExpense.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemLabor: - return await ct.WorkOrderItemLabor.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemLabor.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemLoan: - return await ct.WorkOrderItemLoan.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemLoan.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemPart: - return await ct.WorkOrderItemPart.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemPart.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemPartRequest: - return await ct.WorkOrderItemPartRequest.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemPartRequest.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemScheduledUser: - return await ct.WorkOrderItemScheduledUser.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemScheduledUser.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemTask: - return await ct.WorkOrderItemTask.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemTask.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemTravel: - return await ct.WorkOrderItemTravel.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemTravel.AnyAsync(z => z.Id == id); case AyaType.WorkOrderItemUnit: - return await ct.WorkOrderItemUnit.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderItemUnit.AnyAsync(z => z.Id == id); //--- case AyaType.WorkOrderTemplate: - return await ct.WorkOrderTemplate.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderTemplate.AnyAsync(z => z.Id == id); case AyaType.WorkOrderTemplateItem: - return await ct.WorkOrderTemplateItem.AnyAsync(z => z.Id == tid.ObjectId); + return await ct.WorkOrderTemplateItem.AnyAsync(z => z.Id == id); default: - throw new System.NotSupportedException($"AyaNova.Biz.BizObjectExistsInDatabase::ExistsAsync type {tid.ObjectType.ToString()} is not supported"); + throw new System.NotSupportedException($"AyaNova.Biz.BizObjectExistsInDatabase::ExistsAsync type {objectType.ToString()} is not supported"); } }