@budibase/server 2.5.9 → 2.5.10-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/builder/assets/index.24635afb.js +1794 -0
- package/builder/assets/index.4eae16b2.css +6 -0
- package/builder/index.html +2 -2
- package/dist/api/controllers/application.js +3 -4
- package/dist/api/controllers/automation.js +13 -7
- package/dist/api/controllers/datasource.js +1 -1
- package/dist/api/controllers/dev.js +1 -1
- package/dist/api/controllers/ops.js +40 -0
- package/dist/api/controllers/plugin/index.js +6 -37
- package/dist/api/controllers/query/index.js +2 -2
- package/dist/api/controllers/row/ExternalRequest.js +21 -14
- package/dist/api/controllers/row/internal.js +5 -2
- package/dist/api/controllers/row/utils.js +2 -2
- package/dist/api/controllers/table/index.js +2 -2
- package/dist/api/controllers/table/utils.js +9 -3
- package/dist/api/controllers/user.js +1 -83
- package/dist/api/controllers/view/exporters.js +3 -1
- package/dist/api/index.js +1 -2
- package/dist/api/routes/index.js +2 -2
- package/dist/api/routes/{cloud.js → ops.js} +19 -6
- package/dist/api/routes/user.js +0 -1
- package/dist/app.js +4 -13
- package/dist/automations/actions.js +32 -6
- package/dist/automations/index.js +3 -2
- package/dist/automations/steps/bash.js +6 -6
- package/dist/automations/steps/createRow.js +11 -11
- package/dist/automations/steps/delay.js +3 -3
- package/dist/automations/steps/deleteRow.js +8 -8
- package/dist/automations/steps/discord.js +8 -8
- package/dist/automations/steps/executeQuery.js +9 -9
- package/dist/automations/steps/executeScript.js +6 -6
- package/dist/automations/steps/filter.js +6 -6
- package/dist/automations/steps/integromat.js +10 -10
- package/dist/automations/steps/loop.js +9 -9
- package/dist/automations/steps/outgoingWebhook.js +10 -10
- package/dist/automations/steps/queryRows.js +14 -14
- package/dist/automations/steps/sendSmtpEmail.js +9 -9
- package/dist/automations/steps/serverLog.js +4 -4
- package/dist/automations/steps/slack.js +6 -6
- package/dist/automations/steps/updateRow.js +11 -11
- package/dist/automations/steps/zapier.js +9 -9
- package/dist/automations/triggerInfo/app.js +5 -5
- package/dist/automations/triggerInfo/cron.js +4 -4
- package/dist/automations/triggerInfo/rowDeleted.js +5 -5
- package/dist/automations/triggerInfo/rowSaved.js +7 -7
- package/dist/automations/triggerInfo/rowUpdated.js +7 -7
- package/dist/automations/triggerInfo/webhook.js +6 -6
- package/dist/db/utils.js +3 -2
- package/dist/environment.js +0 -1
- package/dist/events/docUpdates/index.js +17 -0
- package/dist/events/docUpdates/processors.js +18 -0
- package/dist/events/docUpdates/syncUsers.js +49 -0
- package/dist/events/index.js +3 -0
- package/dist/integrations/base/sqlTable.js +9 -2
- package/dist/integrations/index.js +3 -3
- package/dist/integrations/microsoftSqlServer.js +5 -2
- package/dist/integrations/mysql.js +5 -3
- package/dist/integrations/postgres.js +7 -5
- package/dist/integrations/redis.js +7 -0
- package/dist/integrations/rest.js +4 -0
- package/dist/migrations/functions/syncQuotas.js +2 -0
- package/dist/migrations/functions/usageQuotas/syncApps.js +1 -2
- package/dist/migrations/functions/usageQuotas/syncRows.js +1 -2
- package/dist/migrations/functions/usageQuotas/syncUsers.js +21 -0
- package/dist/sdk/app/applications/sync.js +117 -23
- package/dist/sdk/app/backups/exports.js +14 -38
- package/dist/sdk/index.js +2 -0
- package/dist/sdk/plugins/index.js +27 -0
- package/dist/sdk/plugins/plugins.js +53 -0
- package/dist/sdk/users/utils.js +21 -4
- package/dist/startup.js +31 -28
- package/dist/threads/automation.js +16 -5
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/csv.js +33 -0
- package/dist/utilities/fileSystem/plugin.js +33 -23
- package/dist/utilities/global.js +17 -12
- package/dist/utilities/rowProcessor/utils.js +4 -5
- package/dist/utilities/schema.js +5 -1
- package/dist/watch.js +2 -2
- package/dist/websockets/client.js +14 -0
- package/dist/websockets/grid.js +60 -0
- package/dist/websockets/index.js +17 -0
- package/dist/websockets/websocket.js +78 -0
- package/package.json +16 -16
- package/scripts/dev/manage.js +2 -0
- package/scripts/integrations/mssql/data/entrypoint.sh +1 -0
- package/scripts/integrations/mssql/data/setup.sql +17 -17
- package/scripts/integrations/mysql/init.sql +1 -1
- package/scripts/integrations/postgres/init.sql +1 -0
- package/src/api/controllers/application.ts +4 -4
- package/src/api/controllers/automation.ts +12 -6
- package/src/api/controllers/datasource.ts +15 -5
- package/src/api/controllers/dev.ts +2 -2
- package/src/api/controllers/ops.ts +32 -0
- package/src/api/controllers/plugin/index.ts +8 -45
- package/src/api/controllers/query/index.ts +2 -2
- package/src/api/controllers/row/ExternalRequest.ts +21 -12
- package/src/api/controllers/row/internal.ts +13 -11
- package/src/api/controllers/row/utils.ts +4 -4
- package/src/api/controllers/table/index.ts +2 -2
- package/src/api/controllers/table/utils.ts +10 -3
- package/src/api/controllers/user.ts +10 -96
- package/src/api/controllers/view/exporters.ts +3 -1
- package/src/api/index.ts +2 -4
- package/src/api/routes/index.ts +2 -2
- package/src/api/routes/ops.ts +30 -0
- package/src/api/routes/tests/automation.spec.js +7 -4
- package/src/api/routes/tests/user.spec.js +48 -37
- package/src/api/routes/user.ts +0 -5
- package/src/app.ts +4 -15
- package/src/automations/actions.ts +56 -24
- package/src/automations/index.ts +1 -1
- package/src/automations/steps/bash.ts +10 -7
- package/src/automations/steps/createRow.ts +15 -12
- package/src/automations/steps/delay.ts +6 -4
- package/src/automations/steps/deleteRow.ts +12 -9
- package/src/automations/steps/discord.ts +10 -8
- package/src/automations/steps/executeQuery.ts +13 -10
- package/src/automations/steps/executeScript.ts +10 -7
- package/src/automations/steps/filter.ts +8 -6
- package/src/automations/steps/integromat.ts +12 -10
- package/src/automations/steps/loop.ts +16 -10
- package/src/automations/steps/outgoingWebhook.ts +14 -11
- package/src/automations/steps/queryRows.ts +18 -15
- package/src/automations/steps/sendSmtpEmail.ts +11 -9
- package/src/automations/steps/serverLog.ts +6 -4
- package/src/automations/steps/slack.ts +8 -6
- package/src/automations/steps/updateRow.ts +15 -12
- package/src/automations/steps/zapier.ts +11 -9
- package/src/automations/tests/utilities/index.ts +2 -2
- package/src/automations/triggerInfo/app.ts +8 -5
- package/src/automations/triggerInfo/cron.ts +7 -4
- package/src/automations/triggerInfo/rowDeleted.ts +8 -5
- package/src/automations/triggerInfo/rowSaved.ts +10 -7
- package/src/automations/triggerInfo/rowUpdated.ts +10 -7
- package/src/automations/triggerInfo/webhook.ts +9 -6
- package/src/db/utils.ts +1 -0
- package/src/environment.ts +0 -1
- package/src/events/docUpdates/index.ts +1 -0
- package/src/events/docUpdates/processors.ts +14 -0
- package/src/events/docUpdates/syncUsers.ts +35 -0
- package/src/events/index.ts +1 -0
- package/src/integration-test/postgres.spec.ts +3 -1
- package/src/integrations/base/sqlTable.ts +9 -2
- package/src/integrations/index.ts +3 -3
- package/src/integrations/microsoftSqlServer.ts +5 -2
- package/src/integrations/mysql.ts +5 -3
- package/src/integrations/postgres.ts +7 -5
- package/src/integrations/redis.ts +8 -0
- package/src/integrations/rest.ts +3 -0
- package/src/migrations/functions/syncQuotas.ts +2 -0
- package/src/migrations/functions/usageQuotas/syncApps.ts +2 -3
- package/src/migrations/functions/usageQuotas/syncRows.ts +2 -3
- package/src/migrations/functions/usageQuotas/syncUsers.ts +9 -0
- package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +2 -2
- package/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts +26 -0
- package/src/migrations/index.ts +1 -0
- package/src/sdk/app/applications/sync.ts +129 -22
- package/src/sdk/app/applications/tests/sync.spec.ts +137 -0
- package/src/sdk/app/backups/exports.ts +17 -41
- package/src/sdk/index.ts +2 -0
- package/src/sdk/plugins/index.ts +5 -0
- package/src/sdk/plugins/plugins.ts +41 -0
- package/src/sdk/users/tests/utils.spec.ts +1 -32
- package/src/sdk/users/utils.ts +23 -5
- package/src/startup.ts +36 -34
- package/src/tests/jestEnv.ts +0 -1
- package/src/tests/jestSetup.ts +0 -1
- package/src/tests/utilities/TestConfiguration.ts +28 -0
- package/src/tests/utilities/structures.ts +25 -17
- package/src/threads/automation.ts +18 -6
- package/src/utilities/csv.ts +22 -0
- package/src/utilities/fileSystem/plugin.ts +13 -4
- package/src/utilities/global.ts +21 -16
- package/src/utilities/rowProcessor/utils.ts +9 -10
- package/src/utilities/schema.ts +8 -0
- package/src/utilities/tests/csv.spec.ts +33 -0
- package/src/watch.ts +2 -2
- package/src/websockets/client.ts +11 -0
- package/src/websockets/grid.ts +55 -0
- package/src/websockets/index.ts +14 -0
- package/src/websockets/websocket.ts +83 -0
- package/tsconfig.build.json +3 -5
- package/tsconfig.json +2 -1
- package/builder/assets/index.0b358332.js +0 -1817
- package/builder/assets/index.7f9a008b.css +0 -6
- package/dist/api/controllers/cloud.js +0 -130
- package/dist/elasticApm.js +0 -14
- package/dist/package.json +0 -180
- package/dist/websocket.js +0 -22
- package/scripts/likeCypress.ts +0 -35
- package/src/api/controllers/cloud.ts +0 -119
- package/src/api/routes/cloud.ts +0 -18
- package/src/api/routes/tests/cloud.spec.ts +0 -54
- package/src/elasticApm.ts +0 -10
- package/src/migrations/functions/tests/syncQuotas.spec.js +0 -26
- package/src/tests/logging.ts +0 -34
- package/src/websocket.ts +0 -26
|
@@ -1,98 +1,12 @@
|
|
|
1
1
|
import { generateUserMetadataID, generateUserFlagID } from "../../db/utils"
|
|
2
2
|
import { InternalTables } from "../../db/utils"
|
|
3
|
-
import { getGlobalUsers
|
|
3
|
+
import { getGlobalUsers } from "../../utilities/global"
|
|
4
4
|
import { getFullUser } from "../../utilities/users"
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
roles as rolesCore,
|
|
8
|
-
db as dbCore,
|
|
9
|
-
} from "@budibase/backend-core"
|
|
10
|
-
import { BBContext, Ctx, SyncUserRequest, User } from "@budibase/types"
|
|
5
|
+
import { context } from "@budibase/backend-core"
|
|
6
|
+
import { UserCtx } from "@budibase/types"
|
|
11
7
|
import sdk from "../../sdk"
|
|
12
8
|
|
|
13
|
-
export async function
|
|
14
|
-
let deleting = false,
|
|
15
|
-
user: User | any
|
|
16
|
-
const userId = ctx.params.id
|
|
17
|
-
|
|
18
|
-
const previousUser = ctx.request.body?.previousUser
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
user = (await getRawGlobalUser(userId)) as User
|
|
22
|
-
} catch (err: any) {
|
|
23
|
-
if (err && err.status === 404) {
|
|
24
|
-
user = {}
|
|
25
|
-
deleting = true
|
|
26
|
-
} else {
|
|
27
|
-
throw err
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let previousApps = previousUser
|
|
32
|
-
? Object.keys(previousUser.roles).map(appId => appId)
|
|
33
|
-
: []
|
|
34
|
-
|
|
35
|
-
const roles = deleting ? {} : user.roles
|
|
36
|
-
// remove props which aren't useful to metadata
|
|
37
|
-
delete user.password
|
|
38
|
-
delete user.forceResetPassword
|
|
39
|
-
delete user.roles
|
|
40
|
-
// run through all production appIDs in the users roles
|
|
41
|
-
let prodAppIds
|
|
42
|
-
// if they are a builder then get all production app IDs
|
|
43
|
-
if ((user.builder && user.builder.global) || deleting) {
|
|
44
|
-
prodAppIds = await dbCore.getProdAppIDs()
|
|
45
|
-
} else {
|
|
46
|
-
prodAppIds = Object.entries(roles)
|
|
47
|
-
.filter(entry => entry[1] !== rolesCore.BUILTIN_ROLE_IDS.PUBLIC)
|
|
48
|
-
.map(([appId]) => appId)
|
|
49
|
-
}
|
|
50
|
-
for (let prodAppId of new Set([...prodAppIds, ...previousApps])) {
|
|
51
|
-
const roleId = roles[prodAppId]
|
|
52
|
-
const deleteFromApp = !roleId
|
|
53
|
-
const devAppId = dbCore.getDevelopmentAppID(prodAppId)
|
|
54
|
-
for (let appId of [prodAppId, devAppId]) {
|
|
55
|
-
if (!(await dbCore.dbExists(appId))) {
|
|
56
|
-
continue
|
|
57
|
-
}
|
|
58
|
-
await context.doInAppContext(appId, async () => {
|
|
59
|
-
const db = context.getAppDB()
|
|
60
|
-
const metadataId = generateUserMetadataID(userId)
|
|
61
|
-
let metadata
|
|
62
|
-
try {
|
|
63
|
-
metadata = await db.get(metadataId)
|
|
64
|
-
} catch (err) {
|
|
65
|
-
if (deleteFromApp) {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
metadata = {
|
|
69
|
-
tableId: InternalTables.USER_METADATA,
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (deleteFromApp) {
|
|
74
|
-
await db.remove(metadata)
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// assign the roleId for the metadata doc
|
|
79
|
-
if (roleId) {
|
|
80
|
-
metadata.roleId = roleId
|
|
81
|
-
}
|
|
82
|
-
let combined = sdk.users.combineMetadataAndUser(user, metadata)
|
|
83
|
-
// if its null then there was no updates required
|
|
84
|
-
if (combined) {
|
|
85
|
-
await db.put(combined)
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
ctx.body = {
|
|
91
|
-
message: "User synced.",
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export async function fetchMetadata(ctx: BBContext) {
|
|
9
|
+
export async function fetchMetadata(ctx: UserCtx) {
|
|
96
10
|
const global = await getGlobalUsers()
|
|
97
11
|
const metadata = await sdk.users.rawUserMetadata()
|
|
98
12
|
const users = []
|
|
@@ -111,7 +25,7 @@ export async function fetchMetadata(ctx: BBContext) {
|
|
|
111
25
|
ctx.body = users
|
|
112
26
|
}
|
|
113
27
|
|
|
114
|
-
export async function updateSelfMetadata(ctx:
|
|
28
|
+
export async function updateSelfMetadata(ctx: UserCtx) {
|
|
115
29
|
// overwrite the ID with current users
|
|
116
30
|
ctx.request.body._id = ctx.user?._id
|
|
117
31
|
// make sure no stale rev
|
|
@@ -121,7 +35,7 @@ export async function updateSelfMetadata(ctx: BBContext) {
|
|
|
121
35
|
await updateMetadata(ctx)
|
|
122
36
|
}
|
|
123
37
|
|
|
124
|
-
export async function updateMetadata(ctx:
|
|
38
|
+
export async function updateMetadata(ctx: UserCtx) {
|
|
125
39
|
const db = context.getAppDB()
|
|
126
40
|
const user = ctx.request.body
|
|
127
41
|
// this isn't applicable to the user
|
|
@@ -133,7 +47,7 @@ export async function updateMetadata(ctx: BBContext) {
|
|
|
133
47
|
ctx.body = await db.put(metadata)
|
|
134
48
|
}
|
|
135
49
|
|
|
136
|
-
export async function destroyMetadata(ctx:
|
|
50
|
+
export async function destroyMetadata(ctx: UserCtx) {
|
|
137
51
|
const db = context.getAppDB()
|
|
138
52
|
try {
|
|
139
53
|
const dbUser = await db.get(ctx.params.id)
|
|
@@ -146,11 +60,11 @@ export async function destroyMetadata(ctx: BBContext) {
|
|
|
146
60
|
}
|
|
147
61
|
}
|
|
148
62
|
|
|
149
|
-
export async function findMetadata(ctx:
|
|
63
|
+
export async function findMetadata(ctx: UserCtx) {
|
|
150
64
|
ctx.body = await getFullUser(ctx, ctx.params.id)
|
|
151
65
|
}
|
|
152
66
|
|
|
153
|
-
export async function setFlag(ctx:
|
|
67
|
+
export async function setFlag(ctx: UserCtx) {
|
|
154
68
|
const userId = ctx.user?._id
|
|
155
69
|
const { flag, value } = ctx.request.body
|
|
156
70
|
if (!flag) {
|
|
@@ -169,7 +83,7 @@ export async function setFlag(ctx: BBContext) {
|
|
|
169
83
|
ctx.body = { message: "Flag set successfully" }
|
|
170
84
|
}
|
|
171
85
|
|
|
172
|
-
export async function getFlags(ctx:
|
|
86
|
+
export async function getFlags(ctx: UserCtx) {
|
|
173
87
|
const userId = ctx.user?._id
|
|
174
88
|
const docId = generateUserFlagID(userId!)
|
|
175
89
|
const db = context.getAppDB()
|
|
@@ -10,7 +10,9 @@ export function csv(headers: string[], rows: Row[]) {
|
|
|
10
10
|
val =
|
|
11
11
|
typeof val === "object" && !(val instanceof Date)
|
|
12
12
|
? `"${JSON.stringify(val).replace(/"/g, "'")}"`
|
|
13
|
-
:
|
|
13
|
+
: val !== undefined
|
|
14
|
+
? `"${val}"`
|
|
15
|
+
: ""
|
|
14
16
|
return val.trim()
|
|
15
17
|
})
|
|
16
18
|
.join(",")}`
|
package/src/api/index.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import Router from "@koa/router"
|
|
2
|
-
import { auth, middleware } from "@budibase/backend-core"
|
|
2
|
+
import { auth, middleware, env as envCore } from "@budibase/backend-core"
|
|
3
3
|
import currentApp from "../middleware/currentapp"
|
|
4
4
|
import zlib from "zlib"
|
|
5
5
|
import { mainRoutes, staticRoutes, publicRoutes } from "./routes"
|
|
6
|
-
import pkg from "../../package.json"
|
|
7
|
-
import env from "../environment"
|
|
8
6
|
import { middleware as pro } from "@budibase/pro"
|
|
9
7
|
export { shutdown } from "./routes/public"
|
|
10
8
|
const compress = require("koa-compress")
|
|
@@ -12,7 +10,7 @@ const compress = require("koa-compress")
|
|
|
12
10
|
export const router: Router = new Router()
|
|
13
11
|
|
|
14
12
|
router.get("/health", ctx => (ctx.status = 200))
|
|
15
|
-
router.get("/version", ctx => (ctx.body =
|
|
13
|
+
router.get("/version", ctx => (ctx.body = envCore.VERSION))
|
|
16
14
|
|
|
17
15
|
router.use(middleware.errorHandling)
|
|
18
16
|
|
package/src/api/routes/index.ts
CHANGED
|
@@ -22,9 +22,9 @@ import queryRoutes from "./query"
|
|
|
22
22
|
import backupRoutes from "./backup"
|
|
23
23
|
import metadataRoutes from "./metadata"
|
|
24
24
|
import devRoutes from "./dev"
|
|
25
|
-
import cloudRoutes from "./cloud"
|
|
26
25
|
import migrationRoutes from "./migrations"
|
|
27
26
|
import pluginRoutes from "./plugin"
|
|
27
|
+
import opsRoutes from "./ops"
|
|
28
28
|
import Router from "@koa/router"
|
|
29
29
|
import { api as pro } from "@budibase/pro"
|
|
30
30
|
|
|
@@ -59,10 +59,10 @@ export const mainRoutes: Router[] = [
|
|
|
59
59
|
queryRoutes,
|
|
60
60
|
metadataRoutes,
|
|
61
61
|
devRoutes,
|
|
62
|
-
cloudRoutes,
|
|
63
62
|
rowRoutes,
|
|
64
63
|
migrationRoutes,
|
|
65
64
|
pluginRoutes,
|
|
65
|
+
opsRoutes,
|
|
66
66
|
scheduleRoutes,
|
|
67
67
|
environmentVariableRoutes,
|
|
68
68
|
// these need to be handled last as they still use /api/:tableId
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Router from "@koa/router"
|
|
2
|
+
import * as controller from "../controllers/ops"
|
|
3
|
+
import { middleware } from "@budibase/backend-core"
|
|
4
|
+
import Joi from "joi"
|
|
5
|
+
|
|
6
|
+
export function logsValidator() {
|
|
7
|
+
return middleware.joiValidator.body(
|
|
8
|
+
Joi.object({
|
|
9
|
+
message: Joi.string().required(),
|
|
10
|
+
data: Joi.object(),
|
|
11
|
+
})
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function errorValidator() {
|
|
16
|
+
return middleware.joiValidator.body(
|
|
17
|
+
Joi.object({
|
|
18
|
+
message: Joi.string().required(),
|
|
19
|
+
})
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const router: Router = new Router()
|
|
24
|
+
|
|
25
|
+
router
|
|
26
|
+
.post("/api/ops/log", logsValidator(), controller.log)
|
|
27
|
+
.post("/api/ops/error", errorValidator(), controller.error)
|
|
28
|
+
.post("/api/ops/alert", errorValidator(), controller.alert)
|
|
29
|
+
|
|
30
|
+
export default router
|
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
const setup = require("./utilities")
|
|
8
8
|
const { basicAutomation, newAutomation, automationTrigger, automationStep } = setup.structures
|
|
9
9
|
const MAX_RETRIES = 4
|
|
10
|
-
const { TRIGGER_DEFINITIONS,
|
|
10
|
+
const { TRIGGER_DEFINITIONS, BUILTIN_ACTION_DEFINITIONS } = require("../../../automations")
|
|
11
11
|
const { events } = require("@budibase/backend-core")
|
|
12
12
|
|
|
13
13
|
|
|
@@ -19,11 +19,14 @@ describe("/automations", () => {
|
|
|
19
19
|
|
|
20
20
|
afterAll(setup.afterAll)
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
22
|
+
beforeAll(async () => {
|
|
24
23
|
await config.init()
|
|
25
24
|
})
|
|
26
25
|
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
events.automation.deleted.mockClear()
|
|
28
|
+
})
|
|
29
|
+
|
|
27
30
|
describe("get definitions", () => {
|
|
28
31
|
it("returns a list of definitions for actions", async () => {
|
|
29
32
|
const res = await request
|
|
@@ -52,7 +55,7 @@ describe("/automations", () => {
|
|
|
52
55
|
.expect('Content-Type', /json/)
|
|
53
56
|
.expect(200)
|
|
54
57
|
|
|
55
|
-
let definitionsLength = Object.keys(
|
|
58
|
+
let definitionsLength = Object.keys(BUILTIN_ACTION_DEFINITIONS).length
|
|
56
59
|
definitionsLength-- // OUTGOING_WEBHOOK is deprecated
|
|
57
60
|
|
|
58
61
|
expect(Object.keys(res.body.action).length).toBeGreaterThanOrEqual(definitionsLength)
|
|
@@ -57,6 +57,7 @@ describe("/users", () => {
|
|
|
57
57
|
it("should be able to update the user", async () => {
|
|
58
58
|
const user = await config.createUser({ id: `us_update${utils.newid()}` })
|
|
59
59
|
user.roleId = BUILTIN_ROLE_IDS.BASIC
|
|
60
|
+
delete user._rev
|
|
60
61
|
const res = await request
|
|
61
62
|
.put(`/api/users/metadata`)
|
|
62
63
|
.set(config.defaultHeaders())
|
|
@@ -65,6 +66,46 @@ describe("/users", () => {
|
|
|
65
66
|
.expect("Content-Type", /json/)
|
|
66
67
|
expect(res.body.ok).toEqual(true)
|
|
67
68
|
})
|
|
69
|
+
|
|
70
|
+
it("should be able to update the user multiple times", async () => {
|
|
71
|
+
const user = await config.createUser()
|
|
72
|
+
delete user._rev
|
|
73
|
+
|
|
74
|
+
const res1 = await request
|
|
75
|
+
.put(`/api/users/metadata`)
|
|
76
|
+
.set(config.defaultHeaders())
|
|
77
|
+
.send({ ...user, roleId: BUILTIN_ROLE_IDS.BASIC })
|
|
78
|
+
.expect(200)
|
|
79
|
+
.expect("Content-Type", /json/)
|
|
80
|
+
|
|
81
|
+
const res = await request
|
|
82
|
+
.put(`/api/users/metadata`)
|
|
83
|
+
.set(config.defaultHeaders())
|
|
84
|
+
.send({ ...user, _rev: res1.body.rev, roleId: BUILTIN_ROLE_IDS.POWER })
|
|
85
|
+
.expect(200)
|
|
86
|
+
.expect("Content-Type", /json/)
|
|
87
|
+
|
|
88
|
+
expect(res.body.ok).toEqual(true)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it("should require the _rev field for multiple updates", async () => {
|
|
92
|
+
const user = await config.createUser()
|
|
93
|
+
delete user._rev
|
|
94
|
+
|
|
95
|
+
await request
|
|
96
|
+
.put(`/api/users/metadata`)
|
|
97
|
+
.set(config.defaultHeaders())
|
|
98
|
+
.send({ ...user, roleId: BUILTIN_ROLE_IDS.BASIC })
|
|
99
|
+
.expect(200)
|
|
100
|
+
.expect("Content-Type", /json/)
|
|
101
|
+
|
|
102
|
+
await request
|
|
103
|
+
.put(`/api/users/metadata`)
|
|
104
|
+
.set(config.defaultHeaders())
|
|
105
|
+
.send({ ...user, roleId: BUILTIN_ROLE_IDS.POWER })
|
|
106
|
+
.expect(409)
|
|
107
|
+
.expect("Content-Type", /json/)
|
|
108
|
+
})
|
|
68
109
|
})
|
|
69
110
|
|
|
70
111
|
describe("destroy", () => {
|
|
@@ -92,6 +133,7 @@ describe("/users", () => {
|
|
|
92
133
|
expect(res.body.tableId).toBeDefined()
|
|
93
134
|
})
|
|
94
135
|
})
|
|
136
|
+
|
|
95
137
|
describe("setFlag", () => {
|
|
96
138
|
it("should throw an error if a flag is not provided", async () => {
|
|
97
139
|
await config.createUser()
|
|
@@ -101,8 +143,9 @@ describe("/users", () => {
|
|
|
101
143
|
.send({ value: "test" })
|
|
102
144
|
.expect(400)
|
|
103
145
|
.expect("Content-Type", /json/)
|
|
104
|
-
expect(res.body.message).toEqual(
|
|
105
|
-
|
|
146
|
+
expect(res.body.message).toEqual(
|
|
147
|
+
"Must supply a 'flag' field in request body."
|
|
148
|
+
)
|
|
106
149
|
})
|
|
107
150
|
|
|
108
151
|
it("should be able to set a flag on the user", async () => {
|
|
@@ -146,8 +189,9 @@ describe("/users", () => {
|
|
|
146
189
|
.send({ value: "test" })
|
|
147
190
|
.expect(400)
|
|
148
191
|
.expect("Content-Type", /json/)
|
|
149
|
-
expect(res.body.message).toEqual(
|
|
150
|
-
|
|
192
|
+
expect(res.body.message).toEqual(
|
|
193
|
+
"Must supply a 'flag' field in request body."
|
|
194
|
+
)
|
|
151
195
|
})
|
|
152
196
|
|
|
153
197
|
it("should be able to set a flag on the user", async () => {
|
|
@@ -161,37 +205,4 @@ describe("/users", () => {
|
|
|
161
205
|
expect(res.body.message).toEqual("Flag set successfully")
|
|
162
206
|
})
|
|
163
207
|
})
|
|
164
|
-
|
|
165
|
-
describe("syncUser", () => {
|
|
166
|
-
it("should sync the user", async () => {
|
|
167
|
-
let user = await config.createUser()
|
|
168
|
-
await config.createApp('New App')
|
|
169
|
-
let res = await request
|
|
170
|
-
.post(`/api/users/metadata/sync/${user._id}`)
|
|
171
|
-
.set(config.defaultHeaders())
|
|
172
|
-
.expect(200)
|
|
173
|
-
.expect("Content-Type", /json/)
|
|
174
|
-
expect(res.body.message).toEqual('User synced.')
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
it("should sync the user when a previous user is specified", async () => {
|
|
179
|
-
const app1 = await config.createApp('App 1')
|
|
180
|
-
const app2 = await config.createApp('App 2')
|
|
181
|
-
|
|
182
|
-
let user = await config.createUser({
|
|
183
|
-
builder: false,
|
|
184
|
-
admin: true,
|
|
185
|
-
roles: { [app1.appId]: 'ADMIN' }
|
|
186
|
-
})
|
|
187
|
-
let res = await request
|
|
188
|
-
.post(`/api/users/metadata/sync/${user._id}`)
|
|
189
|
-
.set(config.defaultHeaders())
|
|
190
|
-
.send({ previousUser: { ...user, roles: { ...user.roles, [app2.appId]: 'BASIC' } } })
|
|
191
|
-
.expect(200)
|
|
192
|
-
.expect("Content-Type", /json/)
|
|
193
|
-
|
|
194
|
-
expect(res.body.message).toEqual('User synced.')
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
208
|
})
|
package/src/api/routes/user.ts
CHANGED
|
@@ -32,11 +32,6 @@ router
|
|
|
32
32
|
authorized(PermissionType.USER, PermissionLevel.WRITE),
|
|
33
33
|
controller.destroyMetadata
|
|
34
34
|
)
|
|
35
|
-
.post(
|
|
36
|
-
"/api/users/metadata/sync/:id",
|
|
37
|
-
authorized(PermissionType.USER, PermissionLevel.WRITE),
|
|
38
|
-
controller.syncUser
|
|
39
|
-
)
|
|
40
35
|
.post(
|
|
41
36
|
"/api/users/flags",
|
|
42
37
|
authorized(PermissionType.USER, PermissionLevel.WRITE),
|
package/src/app.ts
CHANGED
|
@@ -2,21 +2,9 @@ if (process.env.DD_APM_ENABLED) {
|
|
|
2
2
|
require("./ddApm")
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
if (process.env.ELASTIC_APM_ENABLED) {
|
|
6
|
-
require("./elasticApm")
|
|
7
|
-
}
|
|
8
|
-
|
|
9
5
|
// need to load environment first
|
|
10
6
|
import env from "./environment"
|
|
11
7
|
|
|
12
|
-
// enable APM if configured
|
|
13
|
-
if (process.env.ELASTIC_APM_ENABLED) {
|
|
14
|
-
const apm = require("elastic-apm-node").start({
|
|
15
|
-
serviceName: process.env.SERVICE,
|
|
16
|
-
environment: process.env.BUDIBASE_ENVIRONMENT,
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
|
|
20
8
|
import { ExtendableContext } from "koa"
|
|
21
9
|
import * as db from "./db"
|
|
22
10
|
db.init()
|
|
@@ -27,8 +15,8 @@ import * as api from "./api"
|
|
|
27
15
|
import * as automations from "./automations"
|
|
28
16
|
import { Thread } from "./threads"
|
|
29
17
|
import * as redis from "./utilities/redis"
|
|
18
|
+
import { initialise as initialiseWebsockets } from "./websockets"
|
|
30
19
|
import { events, logging, middleware, timers } from "@budibase/backend-core"
|
|
31
|
-
import { initialise as initialiseWebsockets } from "./websocket"
|
|
32
20
|
import { startup } from "./startup"
|
|
33
21
|
const Sentry = require("@sentry/node")
|
|
34
22
|
const destroyable = require("server-destroy")
|
|
@@ -53,7 +41,8 @@ app.use(
|
|
|
53
41
|
})
|
|
54
42
|
)
|
|
55
43
|
|
|
56
|
-
app.use(middleware.
|
|
44
|
+
app.use(middleware.correlation)
|
|
45
|
+
app.use(middleware.pino)
|
|
57
46
|
app.use(userAgent)
|
|
58
47
|
|
|
59
48
|
if (env.isProd()) {
|
|
@@ -72,7 +61,7 @@ if (env.isProd()) {
|
|
|
72
61
|
|
|
73
62
|
const server = http.createServer(app.callback())
|
|
74
63
|
destroyable(server)
|
|
75
|
-
initialiseWebsockets(server)
|
|
64
|
+
initialiseWebsockets(app, server)
|
|
76
65
|
|
|
77
66
|
let shuttingDown = false,
|
|
78
67
|
errCode = 0
|
|
@@ -15,7 +15,14 @@ import * as delay from "./steps/delay"
|
|
|
15
15
|
import * as queryRow from "./steps/queryRows"
|
|
16
16
|
import * as loop from "./steps/loop"
|
|
17
17
|
import env from "../environment"
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
AutomationStepSchema,
|
|
20
|
+
AutomationStepInput,
|
|
21
|
+
PluginType,
|
|
22
|
+
AutomationStep,
|
|
23
|
+
} from "@budibase/types"
|
|
24
|
+
import sdk from "../sdk"
|
|
25
|
+
import { getAutomationPlugin } from "../utilities/fileSystem"
|
|
19
26
|
|
|
20
27
|
const ACTION_IMPLS: Record<
|
|
21
28
|
string,
|
|
@@ -38,25 +45,26 @@ const ACTION_IMPLS: Record<
|
|
|
38
45
|
zapier: zapier.run,
|
|
39
46
|
integromat: integromat.run,
|
|
40
47
|
}
|
|
41
|
-
export const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
export const BUILTIN_ACTION_DEFINITIONS: Record<string, AutomationStepSchema> =
|
|
49
|
+
{
|
|
50
|
+
SEND_EMAIL_SMTP: sendSmtpEmail.definition,
|
|
51
|
+
CREATE_ROW: createRow.definition,
|
|
52
|
+
UPDATE_ROW: updateRow.definition,
|
|
53
|
+
DELETE_ROW: deleteRow.definition,
|
|
54
|
+
OUTGOING_WEBHOOK: outgoingWebhook.definition,
|
|
55
|
+
EXECUTE_SCRIPT: executeScript.definition,
|
|
56
|
+
EXECUTE_QUERY: executeQuery.definition,
|
|
57
|
+
SERVER_LOG: serverLog.definition,
|
|
58
|
+
DELAY: delay.definition,
|
|
59
|
+
FILTER: filter.definition,
|
|
60
|
+
QUERY_ROWS: queryRow.definition,
|
|
61
|
+
LOOP: loop.definition,
|
|
62
|
+
// these used to be lowercase step IDs, maintain for backwards compat
|
|
63
|
+
discord: discord.definition,
|
|
64
|
+
slack: slack.definition,
|
|
65
|
+
zapier: zapier.definition,
|
|
66
|
+
integromat: integromat.definition,
|
|
67
|
+
}
|
|
60
68
|
|
|
61
69
|
// don't add the bash script/definitions unless in self host
|
|
62
70
|
// the fact this isn't included in any definitions means it cannot be
|
|
@@ -66,12 +74,36 @@ if (env.SELF_HOSTED) {
|
|
|
66
74
|
// @ts-ignore
|
|
67
75
|
ACTION_IMPLS["EXECUTE_BASH"] = bash.run
|
|
68
76
|
// @ts-ignore
|
|
69
|
-
|
|
77
|
+
BUILTIN_ACTION_DEFINITIONS["EXECUTE_BASH"] = bash.definition
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function getActionDefinitions() {
|
|
81
|
+
const actionDefinitions = BUILTIN_ACTION_DEFINITIONS
|
|
82
|
+
if (env.SELF_HOSTED) {
|
|
83
|
+
const plugins = await sdk.plugins.fetch(PluginType.AUTOMATION)
|
|
84
|
+
for (let plugin of plugins) {
|
|
85
|
+
const schema = plugin.schema.schema as AutomationStep
|
|
86
|
+
actionDefinitions[schema.stepId] = {
|
|
87
|
+
...schema,
|
|
88
|
+
custom: true,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return actionDefinitions
|
|
70
93
|
}
|
|
71
94
|
|
|
72
95
|
/* istanbul ignore next */
|
|
73
|
-
export async function getAction(
|
|
74
|
-
if (ACTION_IMPLS[
|
|
75
|
-
return ACTION_IMPLS[
|
|
96
|
+
export async function getAction(stepId: string) {
|
|
97
|
+
if (ACTION_IMPLS[stepId] != null) {
|
|
98
|
+
return ACTION_IMPLS[stepId]
|
|
99
|
+
}
|
|
100
|
+
// must be a plugin
|
|
101
|
+
if (env.SELF_HOSTED) {
|
|
102
|
+
const plugins = await sdk.plugins.fetch(PluginType.AUTOMATION)
|
|
103
|
+
const found = plugins.find(plugin => plugin.schema.schema.stepId === stepId)
|
|
104
|
+
if (!found) {
|
|
105
|
+
throw new Error(`Unable to find action implementation for "${stepId}"`)
|
|
106
|
+
}
|
|
107
|
+
return (await getAutomationPlugin(found)).action
|
|
76
108
|
}
|
|
77
109
|
}
|
package/src/automations/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import BullQueue from "bull"
|
|
|
6
6
|
export { automationQueue } from "./bullboard"
|
|
7
7
|
export { shutdown } from "./bullboard"
|
|
8
8
|
export { TRIGGER_DEFINITIONS } from "./triggers"
|
|
9
|
-
export {
|
|
9
|
+
export { BUILTIN_ACTION_DEFINITIONS, getActionDefinitions } from "./actions"
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* This module is built purely to kick off the worker farm and manage the inputs/outputs
|
|
@@ -4,8 +4,11 @@ import * as automationUtils from "../automationUtils"
|
|
|
4
4
|
import environment from "../../environment"
|
|
5
5
|
import {
|
|
6
6
|
AutomationActionStepId,
|
|
7
|
-
|
|
7
|
+
AutomationCustomIOType,
|
|
8
|
+
AutomationIOType,
|
|
8
9
|
AutomationStepInput,
|
|
10
|
+
AutomationStepSchema,
|
|
11
|
+
AutomationStepType,
|
|
9
12
|
} from "@budibase/types"
|
|
10
13
|
|
|
11
14
|
export const definition: AutomationStepSchema = {
|
|
@@ -13,7 +16,7 @@ export const definition: AutomationStepSchema = {
|
|
|
13
16
|
tagline: "Execute a bash command",
|
|
14
17
|
icon: "JourneyEvent",
|
|
15
18
|
description: "Run a bash script",
|
|
16
|
-
type:
|
|
19
|
+
type: AutomationStepType.ACTION,
|
|
17
20
|
internal: true,
|
|
18
21
|
stepId: AutomationActionStepId.EXECUTE_BASH,
|
|
19
22
|
inputs: {},
|
|
@@ -21,8 +24,8 @@ export const definition: AutomationStepSchema = {
|
|
|
21
24
|
inputs: {
|
|
22
25
|
properties: {
|
|
23
26
|
code: {
|
|
24
|
-
type:
|
|
25
|
-
customType:
|
|
27
|
+
type: AutomationIOType.STRING,
|
|
28
|
+
customType: AutomationCustomIOType.CODE,
|
|
26
29
|
title: "Code",
|
|
27
30
|
},
|
|
28
31
|
},
|
|
@@ -31,16 +34,16 @@ export const definition: AutomationStepSchema = {
|
|
|
31
34
|
outputs: {
|
|
32
35
|
properties: {
|
|
33
36
|
stdout: {
|
|
34
|
-
type:
|
|
37
|
+
type: AutomationIOType.STRING,
|
|
35
38
|
description: "Standard output of your bash command or script",
|
|
36
39
|
},
|
|
37
40
|
success: {
|
|
38
|
-
type:
|
|
41
|
+
type: AutomationIOType.BOOLEAN,
|
|
39
42
|
description: "Whether the command was successful",
|
|
40
43
|
},
|
|
41
44
|
},
|
|
45
|
+
required: ["stdout"],
|
|
42
46
|
},
|
|
43
|
-
required: ["stdout"],
|
|
44
47
|
},
|
|
45
48
|
}
|
|
46
49
|
|