diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 4d40476b7c..fe29d46700 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -11,6 +11,7 @@ import { DeleteRow, DeleteRowRequest, DeleteRows, + EventType, ExportRowsRequest, ExportRowsResponse, FieldType, @@ -64,15 +65,15 @@ export async function patch( ctx.throw(404, "Row not found") } ctx.status = 200 - ctx.eventEmitter && - ctx.eventEmitter.emitRow({ - eventName: `row:update`, - appId, - row, - table, - oldRow, - user: sdk.users.getUserContextBindings(ctx.user), - }) + + ctx.eventEmitter?.emitRow({ + eventName: EventType.ROW_UPDATE, + appId, + row, + table, + oldRow, + user: sdk.users.getUserContextBindings(ctx.user), + }) ctx.message = `${table.name} updated successfully.` ctx.body = row gridSocket?.emitRowUpdate(ctx, row) @@ -103,14 +104,14 @@ export const save = async (ctx: UserCtx) => { sdk.rows.save(sourceId, ctx.request.body, ctx.user?._id) ) ctx.status = 200 - ctx.eventEmitter && - ctx.eventEmitter.emitRow({ - eventName: `row:save`, - appId, - row, - table, - user: sdk.users.getUserContextBindings(ctx.user), - }) + + ctx.eventEmitter?.emitRow({ + eventName: EventType.ROW_SAVE, + appId, + row, + table, + user: sdk.users.getUserContextBindings(ctx.user), + }) ctx.message = `${table.name} saved successfully` // prefer squashed for response ctx.body = row || squashed @@ -182,13 +183,12 @@ async function deleteRows(ctx: UserCtx) { } for (let row of rows) { - ctx.eventEmitter && - ctx.eventEmitter.emitRow({ - eventName: `row:delete`, - appId, - row, - user: sdk.users.getUserContextBindings(ctx.user), - }) + ctx.eventEmitter?.emitRow({ + eventName: EventType.ROW_DELETE, + appId, + row, + user: sdk.users.getUserContextBindings(ctx.user), + }) gridSocket?.emitRowDeletion(ctx, row) } return rows @@ -203,13 +203,12 @@ async function deleteRow(ctx: UserCtx) { await quotas.removeRow() } - ctx.eventEmitter && - ctx.eventEmitter.emitRow({ - eventName: `row:delete`, - appId, - row: resp.row, - user: sdk.users.getUserContextBindings(ctx.user), - }) + ctx.eventEmitter?.emitRow({ + eventName: EventType.ROW_DELETE, + appId, + row: resp.row, + user: sdk.users.getUserContextBindings(ctx.user), + }) gridSocket?.emitRowDeletion(ctx, resp.row) return resp diff --git a/packages/server/src/api/controllers/table/index.ts b/packages/server/src/api/controllers/table/index.ts index 2f2f93bffe..77c1f3923a 100644 --- a/packages/server/src/api/controllers/table/index.ts +++ b/packages/server/src/api/controllers/table/index.ts @@ -16,6 +16,7 @@ import { BulkImportResponse, CsvToJsonRequest, CsvToJsonResponse, + EventType, FetchTablesResponse, FieldType, MigrateRequest, @@ -129,8 +130,7 @@ export async function save(ctx: UserCtx) { } ctx.status = 200 ctx.message = `Table ${table.name} saved successfully.` - ctx.eventEmitter && - ctx.eventEmitter.emitTable(`table:save`, appId, { ...savedTable }) + ctx.eventEmitter?.emitTable(EventType.TABLE_SAVE, appId, { ...savedTable }) ctx.body = savedTable savedTable = await processTable(savedTable) @@ -143,8 +143,8 @@ export async function destroy(ctx: UserCtx) { await sdk.rowActions.deleteAll(tableId) const deletedTable = await pickApi({ tableId }).destroy(ctx) await events.table.deleted(deletedTable) - ctx.eventEmitter && - ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable) + + ctx.eventEmitter?.emitTable(EventType.TABLE_DELETE, appId, deletedTable) ctx.status = 200 ctx.table = deletedTable ctx.body = { message: `Table ${tableId} deleted.` } diff --git a/packages/server/src/db/linkedRows/index.ts b/packages/server/src/db/linkedRows/index.ts index fbb83b49a5..73ac695878 100644 --- a/packages/server/src/db/linkedRows/index.ts +++ b/packages/server/src/db/linkedRows/index.ts @@ -17,6 +17,7 @@ import { import { context, features } from "@budibase/backend-core" import { ContextUser, + EventType, FeatureFlag, FieldType, LinkDocumentValue, @@ -44,15 +45,7 @@ const INVALID_DISPLAY_COLUMN_TYPE = [ * This functionality makes sure that when rows with links are created, updated or deleted they are processed * correctly - making sure that no stale links are left around and that all links have been made successfully. */ - -export const EventType = { - ROW_SAVE: "row:save", - ROW_UPDATE: "row:update", - ROW_DELETE: "row:delete", - TABLE_SAVE: "table:save", - TABLE_UPDATED: "table:updated", - TABLE_DELETE: "table:delete", -} +export { EventType } from "@budibase/types" function clearRelationshipFields(schema: TableSchema, rows: Row[]) { for (let [key, field] of Object.entries(schema)) { diff --git a/packages/server/src/events/AutomationEmitter.ts b/packages/server/src/events/AutomationEmitter.ts index a63273bdc0..a95acd0877 100644 --- a/packages/server/src/events/AutomationEmitter.ts +++ b/packages/server/src/events/AutomationEmitter.ts @@ -1,12 +1,20 @@ import { rowEmission, tableEmission } from "./utils" import mainEmitter from "./index" import env from "../environment" -import { Table, Row, DocumentType, App } from "@budibase/types" +import { + Table, + Row, + DocumentType, + App, + ContextEmitter, + EventType, + UserBindings, +} from "@budibase/types" import { context } from "@budibase/backend-core" const MAX_AUTOMATIONS_ALLOWED = 5 -class AutomationEmitter { +class AutomationEmitter implements ContextEmitter { chainCount: number metadata: { automationChainCount: number } @@ -36,11 +44,15 @@ class AutomationEmitter { appId, row, table, + oldRow, + user, }: { - eventName: string + eventName: EventType.ROW_SAVE | EventType.ROW_DELETE | EventType.ROW_UPDATE appId: string row: Row table?: Table + oldRow?: Row + user: UserBindings }) { let MAX_AUTOMATION_CHAIN = await this.getMaxAutomationChain() @@ -54,7 +66,9 @@ class AutomationEmitter { appId, row, table, + oldRow, metadata: this.metadata, + user, }) } diff --git a/packages/server/src/events/BudibaseEmitter.ts b/packages/server/src/events/BudibaseEmitter.ts index c8983096d0..9fc5c2f906 100644 --- a/packages/server/src/events/BudibaseEmitter.ts +++ b/packages/server/src/events/BudibaseEmitter.ts @@ -1,6 +1,12 @@ import { EventEmitter } from "events" import { rowEmission, tableEmission } from "./utils" -import { Table, Row, User } from "@budibase/types" +import { + Table, + Row, + UserBindings, + EventType, + ContextEmitter, +} from "@budibase/types" /** * keeping event emitter in one central location as it might be used for things other than @@ -12,7 +18,7 @@ import { Table, Row, User } from "@budibase/types" * Extending the standard emitter to some syntactic sugar and standardisation to the emitted event. * This is specifically quite important for template strings used in automations. */ -class BudibaseEmitter extends EventEmitter { +class BudibaseEmitter extends EventEmitter implements ContextEmitter { emitRow({ eventName, appId, @@ -21,17 +27,17 @@ class BudibaseEmitter extends EventEmitter { oldRow, user, }: { - eventName: string + eventName: EventType.ROW_SAVE | EventType.ROW_DELETE | EventType.ROW_UPDATE appId: string row: Row table?: Table oldRow?: Row - user: User + user: UserBindings }) { rowEmission({ emitter: this, eventName, appId, row, table, oldRow, user }) } - emitTable(eventName: string, appId: string, table?: Table) { + emitTable(eventName: EventType, appId: string, table?: Table) { tableEmission({ emitter: this, eventName, appId, table }) } diff --git a/packages/server/src/events/utils.ts b/packages/server/src/events/utils.ts index 5e4a1bebbf..9cb5eef187 100644 --- a/packages/server/src/events/utils.ts +++ b/packages/server/src/events/utils.ts @@ -1,4 +1,4 @@ -import { Table, Row, User } from "@budibase/types" +import { Table, Row, UserBindings } from "@budibase/types" import BudibaseEmitter from "./BudibaseEmitter" type BBEventOpts = { @@ -9,7 +9,7 @@ type BBEventOpts = { row?: Row oldRow?: Row metadata?: any - user?: User + user?: UserBindings } interface BBEventTable extends Table { @@ -25,7 +25,7 @@ type BBEvent = { id?: string revision?: string metadata?: any - user?: User + user?: UserBindings } export function rowEmission({ diff --git a/packages/types/src/core/events.ts b/packages/types/src/core/events.ts new file mode 100644 index 0000000000..3ce948b3b5 --- /dev/null +++ b/packages/types/src/core/events.ts @@ -0,0 +1,8 @@ +export const enum EventType { + ROW_SAVE = "row:save", + ROW_UPDATE = "row:update", + ROW_DELETE = "row:delete", + TABLE_SAVE = "table:save", + TABLE_UPDATED = "table:updated", + TABLE_DELETE = "table:delete", +} diff --git a/packages/types/src/core/index.ts b/packages/types/src/core/index.ts index b5cbd7affa..73cc7d35e0 100644 --- a/packages/types/src/core/index.ts +++ b/packages/types/src/core/index.ts @@ -1 +1,2 @@ export * from "./installation" +export * from "./events" diff --git a/packages/types/src/sdk/koa.ts b/packages/types/src/sdk/koa.ts index a7df701171..95ea2b652f 100644 --- a/packages/types/src/sdk/koa.ts +++ b/packages/types/src/sdk/koa.ts @@ -1,7 +1,17 @@ import { Context, Request } from "koa" -import { User, Role, UserRoles, Account, ConfigType } from "../documents" +import { + User, + Role, + UserRoles, + Account, + ConfigType, + Row, + Table, + UserBindings, +} from "../documents" import { FeatureFlag, License } from "../sdk" import { Files } from "formidable" +import { EventType } from "../core" export interface ContextUser extends Omit { globalId?: string @@ -40,6 +50,7 @@ export interface UserCtx extends Ctx { user: ContextUser roleId?: string + eventEmitter?: ContextEmitter } /** @@ -49,3 +60,32 @@ export interface UserCtx export interface BBContext extends Ctx { user?: ContextUser } + +export interface ContextEmitter { + emitRow(values: { + eventName: EventType.ROW_SAVE + appId: string + row: Row + table: Table + user: UserBindings + }): void + emitRow(values: { + eventName: EventType.ROW_UPDATE + appId: string + row: Row + table: Table + oldRow: Row + user: UserBindings + }): void + emitRow(values: { + eventName: EventType.ROW_DELETE + appId: string + row: Row + user: UserBindings + }): void + emitTable( + eventName: EventType.TABLE_SAVE | EventType.TABLE_DELETE, + appId: string, + table?: Table + ): void +}