Properly clean up row actions on table deletion.

This commit is contained in:
Sam Rose 2024-10-10 14:56:38 +01:00
parent f0d52f2ea0
commit a00a64bb6e
No known key found for this signature in database
4 changed files with 77 additions and 1 deletions

View File

@ -139,6 +139,7 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
export async function destroy(ctx: UserCtx) {
const appId = ctx.appId
const tableId = ctx.params.tableId
await sdk.rowActions.deleteAll(tableId)
const deletedTable = await pickApi({ tableId }).destroy(ctx)
await events.table.deleted(deletedTable)
ctx.eventEmitter &&

View File

@ -1041,4 +1041,44 @@ describe("/rowsActions", () => {
)
})
})
describe("scenarios", () => {
// https://linear.app/budibase/issue/BUDI-8717/
it("should not brick the app when deleting a table with row actions", async () => {
const view = await config.api.viewV2.create({
tableId,
name: generator.guid(),
schema: {
name: { visible: true },
},
})
const rowAction = await config.api.rowAction.save(tableId, {
name: generator.guid(),
})
await config.api.rowAction.setViewPermission(
tableId,
view.id,
rowAction.id
)
let actionsResp = await config.api.rowAction.find(tableId)
expect(actionsResp.actions[rowAction.id]).toEqual({
...rowAction,
allowedSources: [tableId, view.id],
})
const table = await config.api.table.get(tableId)
await config.api.table.destroy(table._id!, table._rev!)
// In the bug reported by Conor, when a delete got deleted its row action
// document was not being cleaned up. This meant there existed code paths
// that would find it and try to reference the tables within it, resulting
// in errors.
await config.api.automation.fetchEnriched({
status: 200,
})
})
})
})

View File

@ -1,5 +1,6 @@
import { context, docIds, HTTPError, utils } from "@budibase/backend-core"
import {
Automation,
AutomationTriggerStepId,
SEPARATOR,
TableRowActions,
@ -105,6 +106,20 @@ export async function getAll(tableId: string) {
return await db.get<TableRowActions>(rowActionsId)
}
export async function deleteAll(tableId: string) {
const db = context.getAppDB()
const doc = await getAll(tableId)
const automationIds = Object.values(doc.actions).map(a => a.automationId)
const automations = await db.getMultiple<Automation>(automationIds)
for (const automation of automations) {
await sdk.automations.remove(automation._id!, automation._rev!)
}
await db.remove(doc)
}
export async function docExists(tableId: string) {
const db = context.getAppDB()
const rowActionsId = generateRowActionsID(tableId)

View File

@ -1,4 +1,4 @@
import { Automation } from "@budibase/types"
import { Automation, FetchAutomationResponse } from "@budibase/types"
import { Expectations, TestAPI } from "./base"
export class AutomationAPI extends TestAPI {
@ -14,6 +14,26 @@ export class AutomationAPI extends TestAPI {
)
return result
}
fetch = async (
expectations?: Expectations
): Promise<FetchAutomationResponse> => {
return await this._get<FetchAutomationResponse>(`/api/automations`, {
expectations,
})
}
fetchEnriched = async (
expectations?: Expectations
): Promise<FetchAutomationResponse> => {
return await this._get<FetchAutomationResponse>(
`/api/automations?enrich=true`,
{
expectations,
}
)
}
post = async (
body: Automation,
expectations?: Expectations