@budibase/server 2.5.3 → 2.5.5-alpha.0
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.7f9a008b.css → index.841e62d8.css} +3 -3
- package/builder/assets/index.c50f7af4.js +1776 -0
- package/builder/index.html +2 -2
- package/dist/api/controllers/ops.js +40 -0
- package/dist/api/routes/index.js +2 -0
- package/dist/api/routes/ops.js +52 -0
- package/dist/app.js +2 -11
- package/dist/environment.js +0 -1
- package/dist/integrations/redis.js +7 -0
- package/dist/integrations/rest.js +4 -0
- package/dist/migrations/functions/usageQuotas/syncApps.js +1 -1
- package/dist/migrations/functions/usageQuotas/syncRows.js +1 -2
- package/dist/package.json +12 -12
- package/dist/startup.js +29 -27
- package/dist/threads/automation.js +14 -3
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/scripts/dev/manage.js +2 -0
- package/src/api/controllers/ops.ts +32 -0
- package/src/api/routes/index.ts +2 -0
- package/src/api/routes/ops.ts +30 -0
- package/src/api/routes/tests/automation.spec.js +5 -2
- package/src/api/routes/tests/user.spec.js +61 -13
- package/src/app.ts +2 -13
- package/src/environment.ts +0 -1
- package/src/integrations/redis.ts +8 -0
- package/src/integrations/rest.ts +3 -0
- package/src/migrations/functions/usageQuotas/syncApps.ts +1 -1
- package/src/migrations/functions/usageQuotas/syncRows.ts +2 -3
- package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +2 -2
- package/src/startup.ts +34 -33
- package/src/tests/jestEnv.ts +0 -1
- package/src/tests/jestSetup.ts +0 -1
- package/src/threads/automation.ts +16 -4
- package/builder/assets/index.b6dcba67.js +0 -1817
- package/dist/elasticApm.js +0 -14
- package/scripts/likeCypress.ts +0 -35
- package/src/elasticApm.ts +0 -10
- package/src/tests/logging.ts +0 -34
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.5.
|
|
4
|
+
"version": "2.5.5-alpha.0",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"dev:stack:down": "node scripts/dev/manage.js down",
|
|
27
27
|
"dev:stack:nuke": "node scripts/dev/manage.js nuke",
|
|
28
28
|
"dev:builder": "yarn run dev:stack:up && nodemon",
|
|
29
|
+
"dev:built": "yarn run dev:stack:up && yarn run run:docker",
|
|
29
30
|
"specs": "ts-node specs/generate.ts && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts",
|
|
30
31
|
"initialise": "node scripts/initialise.js",
|
|
31
32
|
"env:multi:enable": "node scripts/multiTenancy.js enable",
|
|
@@ -44,12 +45,12 @@
|
|
|
44
45
|
"license": "GPL-3.0",
|
|
45
46
|
"dependencies": {
|
|
46
47
|
"@apidevtools/swagger-parser": "10.0.3",
|
|
47
|
-
"@budibase/backend-core": "
|
|
48
|
-
"@budibase/client": "
|
|
49
|
-
"@budibase/pro": "2.5.
|
|
50
|
-
"@budibase/shared-core": "
|
|
51
|
-
"@budibase/string-templates": "
|
|
52
|
-
"@budibase/types": "
|
|
48
|
+
"@budibase/backend-core": "2.5.5-alpha.0",
|
|
49
|
+
"@budibase/client": "2.5.5-alpha.0",
|
|
50
|
+
"@budibase/pro": "2.5.4",
|
|
51
|
+
"@budibase/shared-core": "2.5.5-alpha.0",
|
|
52
|
+
"@budibase/string-templates": "2.5.5-alpha.0",
|
|
53
|
+
"@budibase/types": "2.5.5-alpha.0",
|
|
53
54
|
"@bull-board/api": "3.7.0",
|
|
54
55
|
"@bull-board/koa": "3.9.4",
|
|
55
56
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -85,7 +86,6 @@
|
|
|
85
86
|
"koa-body": "4.2.0",
|
|
86
87
|
"koa-compress": "4.0.1",
|
|
87
88
|
"koa-connect": "2.1.0",
|
|
88
|
-
"koa-pino-logger": "3.0.0",
|
|
89
89
|
"koa-send": "5.0.0",
|
|
90
90
|
"koa-session": "5.12.0",
|
|
91
91
|
"koa-static": "5.0.0",
|
|
@@ -99,7 +99,6 @@
|
|
|
99
99
|
"node-fetch": "2.6.7",
|
|
100
100
|
"open": "8.4.0",
|
|
101
101
|
"pg": "8.5.1",
|
|
102
|
-
"pino-pretty": "4.0.0",
|
|
103
102
|
"posthog-node": "1.3.0",
|
|
104
103
|
"pouchdb": "7.3.0",
|
|
105
104
|
"pouchdb-adapter-memory": "7.2.2",
|
|
@@ -116,9 +115,9 @@
|
|
|
116
115
|
"to-json-schema": "0.2.5",
|
|
117
116
|
"uuid": "3.3.2",
|
|
118
117
|
"validate.js": "0.13.1",
|
|
119
|
-
"vm2": "
|
|
118
|
+
"vm2": "3.9.16",
|
|
120
119
|
"worker-farm": "1.7.0",
|
|
121
|
-
"xml2js": "0.
|
|
120
|
+
"xml2js": "0.5.0",
|
|
122
121
|
"yargs": "13.2.4",
|
|
123
122
|
"zlib": "1.0.5"
|
|
124
123
|
},
|
|
@@ -149,7 +148,7 @@
|
|
|
149
148
|
"@types/tar": "6.1.3",
|
|
150
149
|
"@typescript-eslint/parser": "5.45.0",
|
|
151
150
|
"apidoc": "0.50.4",
|
|
152
|
-
"babel-jest": "
|
|
151
|
+
"babel-jest": "29.5.0",
|
|
153
152
|
"copyfiles": "2.4.1",
|
|
154
153
|
"docker-compose": "0.23.17",
|
|
155
154
|
"eslint": "6.8.0",
|
|
@@ -157,6 +156,7 @@
|
|
|
157
156
|
"is-wsl": "2.2.0",
|
|
158
157
|
"jest": "29.5.0",
|
|
159
158
|
"jest-openapi": "0.14.2",
|
|
159
|
+
"jest-runner": "29.5.0",
|
|
160
160
|
"jest-serial-runner": "^1.2.1",
|
|
161
161
|
"nodemon": "2.0.15",
|
|
162
162
|
"openapi-types": "9.3.1",
|
|
@@ -176,5 +176,5 @@
|
|
|
176
176
|
"optionalDependencies": {
|
|
177
177
|
"oracledb": "5.3.0"
|
|
178
178
|
},
|
|
179
|
-
"gitHead": "
|
|
179
|
+
"gitHead": "84e8cc00315e223433e388b72fae3bd048ff5760"
|
|
180
180
|
}
|
package/scripts/dev/manage.js
CHANGED
|
@@ -45,6 +45,8 @@ async function init() {
|
|
|
45
45
|
BB_ADMIN_USER_PASSWORD: "",
|
|
46
46
|
PLUGINS_DIR: "",
|
|
47
47
|
TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR",
|
|
48
|
+
HTTP_MIGRATIONS: "0",
|
|
49
|
+
HTTP_LOGGING: "0",
|
|
48
50
|
}
|
|
49
51
|
let envFile = ""
|
|
50
52
|
Object.keys(envFileJson).forEach(key => {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Ctx } from "@budibase/types"
|
|
2
|
+
import { logging } from "@budibase/backend-core"
|
|
3
|
+
|
|
4
|
+
interface LogRequest {
|
|
5
|
+
message: string
|
|
6
|
+
data?: any
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ErrorRequest {
|
|
10
|
+
message: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function log(ctx: Ctx<LogRequest>) {
|
|
14
|
+
const body = ctx.request.body
|
|
15
|
+
console.trace(body.message, body.data)
|
|
16
|
+
console.debug(body.message, body.data)
|
|
17
|
+
console.info(body.message, body.data)
|
|
18
|
+
console.warn(body.message, body.data)
|
|
19
|
+
console.error(body.message, body.data)
|
|
20
|
+
ctx.status = 204
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function alert(ctx: Ctx<ErrorRequest>) {
|
|
24
|
+
const body = ctx.request.body
|
|
25
|
+
logging.logAlert(body.message, new Error(body.message))
|
|
26
|
+
ctx.status = 204
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function error(ctx: Ctx<ErrorRequest>) {
|
|
30
|
+
const body = ctx.request.body
|
|
31
|
+
throw new Error(body.message)
|
|
32
|
+
}
|
package/src/api/routes/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ import devRoutes from "./dev"
|
|
|
25
25
|
import cloudRoutes from "./cloud"
|
|
26
26
|
import migrationRoutes from "./migrations"
|
|
27
27
|
import pluginRoutes from "./plugin"
|
|
28
|
+
import opsRoutes from "./ops"
|
|
28
29
|
import Router from "@koa/router"
|
|
29
30
|
import { api as pro } from "@budibase/pro"
|
|
30
31
|
|
|
@@ -63,6 +64,7 @@ export const mainRoutes: Router[] = [
|
|
|
63
64
|
rowRoutes,
|
|
64
65
|
migrationRoutes,
|
|
65
66
|
pluginRoutes,
|
|
67
|
+
opsRoutes,
|
|
66
68
|
scheduleRoutes,
|
|
67
69
|
environmentVariableRoutes,
|
|
68
70
|
// 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
|
|
@@ -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
|
|
@@ -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 () => {
|
|
@@ -165,33 +209,37 @@ describe("/users", () => {
|
|
|
165
209
|
describe("syncUser", () => {
|
|
166
210
|
it("should sync the user", async () => {
|
|
167
211
|
let user = await config.createUser()
|
|
168
|
-
await config.createApp(
|
|
212
|
+
await config.createApp("New App")
|
|
169
213
|
let res = await request
|
|
170
214
|
.post(`/api/users/metadata/sync/${user._id}`)
|
|
171
215
|
.set(config.defaultHeaders())
|
|
172
216
|
.expect(200)
|
|
173
217
|
.expect("Content-Type", /json/)
|
|
174
|
-
expect(res.body.message).toEqual(
|
|
218
|
+
expect(res.body.message).toEqual("User synced.")
|
|
175
219
|
})
|
|
176
220
|
|
|
177
|
-
|
|
178
221
|
it("should sync the user when a previous user is specified", async () => {
|
|
179
|
-
const app1 = await config.createApp(
|
|
180
|
-
const app2 = await config.createApp(
|
|
222
|
+
const app1 = await config.createApp("App 1")
|
|
223
|
+
const app2 = await config.createApp("App 2")
|
|
181
224
|
|
|
182
225
|
let user = await config.createUser({
|
|
183
226
|
builder: false,
|
|
184
227
|
admin: true,
|
|
185
|
-
|
|
186
|
-
|
|
228
|
+
roles: { [app1.appId]: "ADMIN" },
|
|
229
|
+
})
|
|
187
230
|
let res = await request
|
|
188
231
|
.post(`/api/users/metadata/sync/${user._id}`)
|
|
189
232
|
.set(config.defaultHeaders())
|
|
190
|
-
.send({
|
|
233
|
+
.send({
|
|
234
|
+
previousUser: {
|
|
235
|
+
...user,
|
|
236
|
+
roles: { ...user.roles, [app2.appId]: "BASIC" },
|
|
237
|
+
},
|
|
238
|
+
})
|
|
191
239
|
.expect(200)
|
|
192
240
|
.expect("Content-Type", /json/)
|
|
193
241
|
|
|
194
|
-
expect(res.body.message).toEqual(
|
|
242
|
+
expect(res.body.message).toEqual("User synced.")
|
|
195
243
|
})
|
|
196
244
|
})
|
|
197
245
|
})
|
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()
|
|
@@ -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()) {
|
package/src/environment.ts
CHANGED
|
@@ -62,7 +62,6 @@ const environment = {
|
|
|
62
62
|
// minor
|
|
63
63
|
SALT_ROUNDS: process.env.SALT_ROUNDS,
|
|
64
64
|
LOGGER: process.env.LOGGER,
|
|
65
|
-
LOG_LEVEL: process.env.LOG_LEVEL,
|
|
66
65
|
ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL,
|
|
67
66
|
AUTOMATION_MAX_ITERATIONS:
|
|
68
67
|
parseIntSafe(process.env.AUTOMATION_MAX_ITERATIONS) || 200,
|
|
@@ -6,6 +6,7 @@ interface RedisConfig {
|
|
|
6
6
|
port: number
|
|
7
7
|
username: string
|
|
8
8
|
password?: string
|
|
9
|
+
db?: number
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
const SCHEMA: Integration = {
|
|
@@ -32,6 +33,12 @@ const SCHEMA: Integration = {
|
|
|
32
33
|
type: "password",
|
|
33
34
|
required: false,
|
|
34
35
|
},
|
|
36
|
+
db: {
|
|
37
|
+
type: "number",
|
|
38
|
+
required: false,
|
|
39
|
+
display: "DB",
|
|
40
|
+
default: 0,
|
|
41
|
+
},
|
|
35
42
|
},
|
|
36
43
|
query: {
|
|
37
44
|
create: {
|
|
@@ -88,6 +95,7 @@ class RedisIntegration {
|
|
|
88
95
|
port: this.config.port,
|
|
89
96
|
username: this.config.username,
|
|
90
97
|
password: this.config.password,
|
|
98
|
+
db: this.config.db,
|
|
91
99
|
})
|
|
92
100
|
}
|
|
93
101
|
|
package/src/integrations/rest.ts
CHANGED
|
@@ -151,6 +151,9 @@ class RestIntegration implements IntegrationBase {
|
|
|
151
151
|
data = data[keys[0]]
|
|
152
152
|
}
|
|
153
153
|
raw = rawXml
|
|
154
|
+
} else if (contentType.includes("application/pdf")) {
|
|
155
|
+
data = await response.arrayBuffer() // Save PDF as ArrayBuffer
|
|
156
|
+
raw = Buffer.from(data)
|
|
154
157
|
} else {
|
|
155
158
|
data = await response.text()
|
|
156
159
|
raw = data
|
|
@@ -9,6 +9,6 @@ export const run = async () => {
|
|
|
9
9
|
|
|
10
10
|
// sync app count
|
|
11
11
|
const tenantId = tenancy.getTenantId()
|
|
12
|
-
console.log(`
|
|
12
|
+
console.log(`Syncing app count: ${appCount}`)
|
|
13
13
|
await quotas.setUsage(appCount, StaticQuotaName.APPS, QuotaUsageType.STATIC)
|
|
14
14
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { db as dbCore } from "@budibase/backend-core"
|
|
2
2
|
import { getUniqueRows } from "../../../utilities/usageQuota/rows"
|
|
3
3
|
import { quotas } from "@budibase/pro"
|
|
4
4
|
import { StaticQuotaName, QuotaUsageType, App } from "@budibase/types"
|
|
@@ -18,8 +18,7 @@ export const run = async () => {
|
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
// sync row count
|
|
21
|
-
|
|
22
|
-
console.log(`[Tenant: ${tenantId}] Syncing row count: ${rowCount}`)
|
|
21
|
+
console.log(`Syncing row count: ${rowCount}`)
|
|
23
22
|
await quotas.setUsagePerApp(
|
|
24
23
|
counts,
|
|
25
24
|
StaticQuotaName.ROWS,
|
|
@@ -24,7 +24,7 @@ describe("syncRows", () => {
|
|
|
24
24
|
|
|
25
25
|
// app 1
|
|
26
26
|
const app1 = config.app
|
|
27
|
-
await context.doInAppContext(app1
|
|
27
|
+
await context.doInAppContext(app1!.appId, async () => {
|
|
28
28
|
await config.createTable()
|
|
29
29
|
await config.createRow()
|
|
30
30
|
})
|
|
@@ -43,7 +43,7 @@ describe("syncRows", () => {
|
|
|
43
43
|
usageDoc = await quotas.getQuotaUsage()
|
|
44
44
|
expect(usageDoc.usageQuota.rows).toEqual(3)
|
|
45
45
|
expect(
|
|
46
|
-
usageDoc.apps?.[dbCore.getProdAppID(app1
|
|
46
|
+
usageDoc.apps?.[dbCore.getProdAppID(app1!.appId)].usageQuota.rows
|
|
47
47
|
).toEqual(1)
|
|
48
48
|
expect(
|
|
49
49
|
usageDoc.apps?.[dbCore.getProdAppID(app2.appId)].usageQuota.rows
|
package/src/startup.ts
CHANGED
|
@@ -16,13 +16,10 @@ import * as bullboard from "./automations/bullboard"
|
|
|
16
16
|
import * as pro from "@budibase/pro"
|
|
17
17
|
import * as api from "./api"
|
|
18
18
|
import sdk from "./sdk"
|
|
19
|
-
const pino = require("koa-pino-logger")
|
|
20
19
|
|
|
21
20
|
let STARTUP_RAN = false
|
|
22
21
|
|
|
23
22
|
async function initRoutes(app: any) {
|
|
24
|
-
app.use(pino(logging.pinoSettings()))
|
|
25
|
-
|
|
26
23
|
if (!env.isTest()) {
|
|
27
24
|
const plugin = await bullboard.init()
|
|
28
25
|
app.use(plugin)
|
|
@@ -48,8 +45,10 @@ async function initPro() {
|
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
function shutdown(server?: any) {
|
|
51
|
-
server
|
|
52
|
-
|
|
48
|
+
if (server) {
|
|
49
|
+
server.close()
|
|
50
|
+
server.destroy()
|
|
51
|
+
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
export async function startup(app?: any, server?: any) {
|
|
@@ -72,11 +71,39 @@ export async function startup(app?: any, server?: any) {
|
|
|
72
71
|
await migrations.migrate()
|
|
73
72
|
} catch (e) {
|
|
74
73
|
logging.logAlert("Error performing migrations. Exiting.", e)
|
|
75
|
-
shutdown()
|
|
74
|
+
shutdown(server)
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
// monitor plugin directory if required
|
|
79
|
+
if (
|
|
80
|
+
env.SELF_HOSTED &&
|
|
81
|
+
!env.MULTI_TENANCY &&
|
|
82
|
+
env.PLUGINS_DIR &&
|
|
83
|
+
fs.existsSync(env.PLUGINS_DIR)
|
|
84
|
+
) {
|
|
85
|
+
watch()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// check for version updates
|
|
89
|
+
await installation.checkInstallVersion()
|
|
90
|
+
|
|
91
|
+
// get the references to the queue promises, don't await as
|
|
92
|
+
// they will never end, unless the processing stops
|
|
93
|
+
let queuePromises = []
|
|
94
|
+
// configure events to use the pro audit log write
|
|
95
|
+
// can't integrate directly into backend-core due to cyclic issues
|
|
96
|
+
queuePromises.push(events.processors.init(pro.sdk.auditLogs.write))
|
|
97
|
+
queuePromises.push(automations.init())
|
|
98
|
+
queuePromises.push(initPro())
|
|
99
|
+
if (app) {
|
|
100
|
+
// bring routes online as final step once everything ready
|
|
101
|
+
await initRoutes(app)
|
|
102
|
+
}
|
|
103
|
+
|
|
79
104
|
// check and create admin user if required
|
|
105
|
+
// this must be run after the api has been initialised due to
|
|
106
|
+
// the app user sync
|
|
80
107
|
if (
|
|
81
108
|
env.SELF_HOSTED &&
|
|
82
109
|
!env.MULTI_TENANCY &&
|
|
@@ -103,34 +130,8 @@ export async function startup(app?: any, server?: any) {
|
|
|
103
130
|
)
|
|
104
131
|
} catch (e) {
|
|
105
132
|
logging.logAlert("Error creating initial admin user. Exiting.", e)
|
|
106
|
-
shutdown()
|
|
133
|
+
shutdown(server)
|
|
107
134
|
}
|
|
108
135
|
}
|
|
109
136
|
}
|
|
110
|
-
|
|
111
|
-
// monitor plugin directory if required
|
|
112
|
-
if (
|
|
113
|
-
env.SELF_HOSTED &&
|
|
114
|
-
!env.MULTI_TENANCY &&
|
|
115
|
-
env.PLUGINS_DIR &&
|
|
116
|
-
fs.existsSync(env.PLUGINS_DIR)
|
|
117
|
-
) {
|
|
118
|
-
watch()
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// check for version updates
|
|
122
|
-
await installation.checkInstallVersion()
|
|
123
|
-
|
|
124
|
-
// get the references to the queue promises, don't await as
|
|
125
|
-
// they will never end, unless the processing stops
|
|
126
|
-
let queuePromises = []
|
|
127
|
-
// configure events to use the pro audit log write
|
|
128
|
-
// can't integrate directly into backend-core due to cyclic issues
|
|
129
|
-
queuePromises.push(events.processors.init(pro.sdk.auditLogs.write))
|
|
130
|
-
queuePromises.push(automations.init())
|
|
131
|
-
queuePromises.push(initPro())
|
|
132
|
-
if (app) {
|
|
133
|
-
// bring routes online as final step once everything ready
|
|
134
|
-
await initRoutes(app)
|
|
135
|
-
}
|
|
136
137
|
}
|
package/src/tests/jestEnv.ts
CHANGED
|
@@ -6,7 +6,6 @@ process.env.MULTI_TENANCY = "1"
|
|
|
6
6
|
// @ts-ignore
|
|
7
7
|
process.env.BUDIBASE_DIR = tmpdir("budibase-unittests")
|
|
8
8
|
process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
|
|
9
|
-
process.env.ENABLE_4XX_HTTP_LOGGING = "0"
|
|
10
9
|
process.env.MOCK_REDIS = "1"
|
|
11
10
|
process.env.PLATFORM_URL = "http://localhost:10000"
|
|
12
11
|
process.env.REDIS_PASSWORD = "budibase"
|
package/src/tests/jestSetup.ts
CHANGED
|
@@ -34,8 +34,8 @@ const STOPPED_STATUS = { success: true, status: AutomationStatus.STOPPED }
|
|
|
34
34
|
|
|
35
35
|
function getLoopIterations(loopStep: LoopStep, input: LoopInput) {
|
|
36
36
|
const binding = automationUtils.typecastForLooping(loopStep, input)
|
|
37
|
-
if (!
|
|
38
|
-
return
|
|
37
|
+
if (!binding) {
|
|
38
|
+
return 0
|
|
39
39
|
}
|
|
40
40
|
if (Array.isArray(binding)) {
|
|
41
41
|
return binding.length
|
|
@@ -43,7 +43,7 @@ function getLoopIterations(loopStep: LoopStep, input: LoopInput) {
|
|
|
43
43
|
if (typeof binding === "string") {
|
|
44
44
|
return automationUtils.stringSplit(binding).length
|
|
45
45
|
}
|
|
46
|
-
return
|
|
46
|
+
return 0
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -423,13 +423,25 @@ class Orchestrator {
|
|
|
423
423
|
}
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
if (loopStep && iterations === 0) {
|
|
427
|
+
loopStep = undefined
|
|
428
|
+
this.executionOutput.steps.splice(loopStepNumber + 1, 0, {
|
|
429
|
+
id: step.id,
|
|
430
|
+
stepId: step.stepId,
|
|
431
|
+
outputs: { status: AutomationStatus.NO_ITERATIONS, success: true },
|
|
432
|
+
inputs: {},
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
this._context.steps.splice(loopStepNumber, 1)
|
|
436
|
+
iterations = 1
|
|
437
|
+
}
|
|
438
|
+
|
|
426
439
|
// Delete the step after the loop step as it's irrelevant, since information is included
|
|
427
440
|
// in the loop step
|
|
428
441
|
if (wasLoopStep && !loopStep) {
|
|
429
442
|
this._context.steps.splice(loopStepNumber + 1, 1)
|
|
430
443
|
wasLoopStep = false
|
|
431
444
|
}
|
|
432
|
-
|
|
433
445
|
if (loopSteps && loopSteps.length) {
|
|
434
446
|
let tempOutput = {
|
|
435
447
|
success: true,
|