User ValidateCanDelete switched to checking all references from only event log

This commit is contained in:
2021-11-10 23:50:36 +00:00
parent 6adfc2fb7f
commit 8d9e430f91
2 changed files with 78 additions and 19 deletions

View File

@@ -842,24 +842,83 @@ namespace AyaNova.Biz
//Can delete?
private async Task ValidateCanDelete(User inObj)
{
// //To make this simple and avoid a whole host of issues and work
// //I've decided that a user can't be deleted if they have *any* activity in the event log
// //this way a newly created user can be deleted before they do any real work still to cover a scenario where a user
// //makes a user but then doesn't need it or did it wrong
// //This avoids the whole issues related to having to check every table everywhere for their work and
// //the associated fuckery with trying to back them out of those tables without knock-on effects
// //They can always make any user inactive to get rid of them and it will mean referential integrity issues are not there
// //There's only one rule - have they done anything eventlog worthy yet?
// //if (await ct.Event.Select(z => z).Where(z => z.UserId == inObj.Id).Count() > 0)
// if (await ct.Event.AnyAsync(z => z.UserId == inObj.Id))
// {
// //Theres no more specific error to show for this
// AddError(ApiErrorCode.INVALID_OPERATION, "generalerror", await Translate("ErrorDBForeignKeyViolation"));
// return;
// }
//To make this simple and avoid a whole host of issues and work
//I've decided that a user can't be deleted if they have *any* activity in the event log
//this way a newly created user can be deleted before they do any real work still to cover a scenario where a user
//makes a user but then doesn't need it or did it wrong
//This avoids the whole issues related to having to check every table everywhere for their work and
//the associated fuckery with trying to back them out of those tables without knock-on effects
//They can always make any user inactive to get rid of them and it will mean referential integrity issues are not there
//NOPE, the above is not going to fly for many reasons, going to have to do it the hard way
//Users need to know *what* is holding up deleting a user if they should choose to do so and
//the event log will eventually have a purge feature so it's not a reliable source
//the db would prevent it anyway, but it's best to do it right
//There's only one rule - have they done anything eventlog worthy yet?
//if (await ct.Event.Select(z => z).Where(z => z.UserId == inObj.Id).Count() > 0)
if (await ct.Event.AnyAsync(z => z.UserId == inObj.Id))
{
//Theres no more specific error to show for this
AddError(ApiErrorCode.INVALID_OPERATION, "generalerror", await Translate("ErrorDBForeignKeyViolation"));
return;
}
//FOREIGN KEY CHECKS
if (await ct.Memo.AnyAsync(m => m.ToId == inObj.Id || m.FromId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("Memo"));
// if (await ct.Reminder.AnyAsync(m => m.UserId == inObj.Id))
// AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("Reminder"));//CASCADE DELETES
if (await ct.Review.AnyAsync(m => m.AssignedByUserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("Review"));
if (await ct.CustomerNote.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("CustomerNote"));
if (await ct.Project.AnyAsync(m => m.ProjectOverseerId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("Project"));
if (await ct.PurchaseOrderItem.AnyAsync(m => m.PartRequestedById == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("PurchaseOrderItem"));
if (await ct.WorkOrderState.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderState"));
if (await ct.WorkOrderItemExpense.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderItemExpense"));
if (await ct.WorkOrderItemLabor.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderItemLabor"));
if (await ct.WorkOrderItemPartRequest.AnyAsync(m => m.RequestedByUserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderItemPartRequest"));
if (await ct.WorkOrderItemScheduledUser.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderItemScheduledUser"));
if (await ct.WorkOrderItemTask.AnyAsync(m => m.CompletedByUserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderItemTask"));
if (await ct.WorkOrderItemTravel.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("WorkOrderItemTravel"));
if (await ct.Quote.AnyAsync(m => m.PreparedById == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("Quote"));
var quotetext = await Translate("Quote");
var pmtext = await Translate("PM");
if (await ct.QuoteState.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("QuoteState"));
if (await ct.QuoteItemExpense.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", quotetext + " - " + await Translate("WorkOrderItemExpense"));
if (await ct.QuoteItemLabor.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", quotetext + " - " + await Translate("WorkOrderItemLabor"));
if (await ct.QuoteItemScheduledUser.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", quotetext + " - " + await Translate("WorkOrderItemScheduledUser"));
if (await ct.QuoteItemTask.AnyAsync(m => m.CompletedByUserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", quotetext + " - " + await Translate("WorkOrderItemTask"));
if (await ct.QuoteItemTravel.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", quotetext + " - " + await Translate("WorkOrderItemTravel"));
if (await ct.PMItemExpense.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", pmtext + " - " + await Translate("WorkOrderItemExpense"));
if (await ct.PMItemLabor.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", pmtext + " - " + await Translate("WorkOrderItemLabor"));
if (await ct.PMItemScheduledUser.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", pmtext + " - " + await Translate("WorkOrderItemScheduledUser"));
if (await ct.PMItemTask.AnyAsync(m => m.CompletedByUserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", pmtext + " - " + await Translate("WorkOrderItemTask"));
if (await ct.PMItemTravel.AnyAsync(m => m.UserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", pmtext + " - " + await Translate("WorkOrderItemTravel"));
if (await ct.CustomerServiceRequest.AnyAsync(m => m.RequestedByUserId == inObj.Id))
AddError(ApiErrorCode.VALIDATION_REFERENTIAL_INTEGRITY, "generalerror", await Translate("CustomerServiceRequest"));
}

View File

@@ -611,7 +611,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
//Add user options table
await ExecQueryAsync("CREATE TABLE auseroptions (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
+ "userid BIGINT NOT NULL UNIQUE REFERENCES auser (id), translationid BIGINT NOT NULL REFERENCES atranslation (id), languageoverride TEXT, timezoneoverride TEXT, "
+ "userid BIGINT NOT NULL UNIQUE REFERENCES auser (id) ON DELETE CASCADE, translationid BIGINT NOT NULL REFERENCES atranslation (id), languageoverride TEXT, timezoneoverride TEXT, "
+ "currencyname TEXT, hour12 BOOL NOT NULL, emailaddress TEXT, phone1 TEXT, phone2 TEXT, phone3 TEXT, mapurltemplate TEXT)");
@@ -1302,16 +1302,16 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
//NOTIFICATION
await ExecQueryAsync("CREATE TABLE anotifysubscription (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
+ "userid BIGINT NOT NULL REFERENCES auser (id), ayatype INTEGER NOT NULL, eventtype INTEGER NOT NULL, advancenotice INTERVAL NOT NULL, "
+ "userid BIGINT NOT NULL REFERENCES auser (id) ON DELETE CASCADE, ayatype INTEGER NOT NULL, eventtype INTEGER NOT NULL, advancenotice INTERVAL NOT NULL, "
+ "idvalue BIGINT NOT NULL, decvalue DECIMAL(38,18) NOT NULL, agevalue INTERVAL NOT NULL, deliverymethod INTEGER NOT NULL, "
+ "deliveryaddress TEXT, linkreportid BIGINT NOT NULL, tags VARCHAR(255) ARRAY)");
await ExecQueryAsync("CREATE TABLE anotifyevent (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, created TIMESTAMPTZ NOT NULL, "
+ "ayatype INTEGER NOT NULL, objectid BIGINT NOT NULL, name TEXT NOT NULL, eventtype INTEGER NOT NULL, notifysubscriptionid BIGINT NOT NULL REFERENCES anotifysubscription(id) ON DELETE CASCADE, "
+ "userid BIGINT NOT NULL REFERENCES auser (id), eventdate TIMESTAMPTZ NOT NULL, decvalue DECIMAL(38,18) NULL, message TEXT)");
+ "userid BIGINT NOT NULL REFERENCES auser (id) ON DELETE CASCADE, eventdate TIMESTAMPTZ NOT NULL, decvalue DECIMAL(38,18) NULL, message TEXT)");
await ExecQueryAsync("CREATE TABLE ainappnotification (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, userid BIGINT NOT NULL REFERENCES auser (id), "
await ExecQueryAsync("CREATE TABLE ainappnotification (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, userid BIGINT NOT NULL REFERENCES auser (id) ON DELETE CASCADE, "
+ "created TIMESTAMPTZ NOT NULL, ayatype INTEGER NOT NULL, objectid BIGINT NOT NULL, name TEXT NOT NULL, agevalue INTERVAL, eventtype INTEGER NOT NULL, "
+ "decvalue DECIMAL(38,18) NULL, notifysubscriptionid BIGINT NOT NULL REFERENCES anotifysubscription(id) ON DELETE CASCADE, message TEXT, fetched BOOL NOT NULL)");