@budibase/server 2.3.18-alpha.11 → 2.3.18-alpha.13
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.7503d634.js → index.5db9630c.js} +365 -364
- package/builder/assets/{index.22724f34.css → index.d4b6aa43.css} +1 -1
- package/builder/index.html +2 -2
- package/dist/api/controllers/cloud.js +2 -2
- package/dist/integrations/googlesheets.js +2 -12
- package/dist/migrations/functions/backfill/global/configs.js +10 -4
- package/dist/migrations/tests/helpers.js +1 -1
- package/dist/migrations/tests/structures.js +1 -1
- package/dist/package.json +6 -6
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/api/controllers/cloud.ts +2 -2
- package/src/api/routes/tests/{cloud.seq.spec.ts → cloud.spec.ts} +13 -20
- package/src/api/routes/tests/utilities/TestFunctions.ts +1 -2
- package/src/integrations/googlesheets.ts +3 -11
- package/src/migrations/functions/backfill/global/configs.ts +15 -9
- package/src/migrations/functions/tests/userEmailViewCasing.spec.js +3 -4
- package/src/migrations/tests/helpers.ts +2 -2
- package/src/migrations/tests/structures.ts +1 -0
- package/src/tests/jestEnv.ts +1 -0
- package/src/tests/utilities/TestConfiguration.ts +42 -30
- package/src/tests/utilities/structures.ts +0 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.3.18-alpha.
|
|
4
|
+
"version": "2.3.18-alpha.13",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"license": "GPL-3.0",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@apidevtools/swagger-parser": "10.0.3",
|
|
46
|
-
"@budibase/backend-core": "2.3.18-alpha.
|
|
47
|
-
"@budibase/client": "2.3.18-alpha.
|
|
48
|
-
"@budibase/pro": "2.3.18-alpha.
|
|
49
|
-
"@budibase/string-templates": "2.3.18-alpha.
|
|
50
|
-
"@budibase/types": "2.3.18-alpha.
|
|
46
|
+
"@budibase/backend-core": "2.3.18-alpha.13",
|
|
47
|
+
"@budibase/client": "2.3.18-alpha.13",
|
|
48
|
+
"@budibase/pro": "2.3.18-alpha.12",
|
|
49
|
+
"@budibase/string-templates": "2.3.18-alpha.13",
|
|
50
|
+
"@budibase/types": "2.3.18-alpha.13",
|
|
51
51
|
"@bull-board/api": "3.7.0",
|
|
52
52
|
"@bull-board/koa": "3.9.4",
|
|
53
53
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -173,5 +173,5 @@
|
|
|
173
173
|
"optionalDependencies": {
|
|
174
174
|
"oracledb": "5.3.0"
|
|
175
175
|
},
|
|
176
|
-
"gitHead": "
|
|
176
|
+
"gitHead": "95ce3bb56c8db6b69b3b9081c0eeb0fff5180518"
|
|
177
177
|
}
|
|
@@ -58,7 +58,7 @@ export async function exportApps(ctx: Ctx) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
async function checkHasBeenImported() {
|
|
61
|
-
if (!env.SELF_HOSTED
|
|
61
|
+
if (!env.SELF_HOSTED) {
|
|
62
62
|
return true
|
|
63
63
|
}
|
|
64
64
|
const apps = await dbCore.getAllApps({ all: true })
|
|
@@ -72,7 +72,7 @@ export async function hasBeenImported(ctx: Ctx) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export async function importApps(ctx: Ctx) {
|
|
75
|
-
if (!env.SELF_HOSTED
|
|
75
|
+
if (!env.SELF_HOSTED) {
|
|
76
76
|
ctx.throw(400, "Importing only allowed in self hosted environments.")
|
|
77
77
|
}
|
|
78
78
|
const beenImported = await checkHasBeenImported()
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { App } from "@budibase/types"
|
|
2
|
+
|
|
1
3
|
jest.setTimeout(30000)
|
|
2
4
|
|
|
3
5
|
import { AppStatus } from "../../../db/utils"
|
|
@@ -5,6 +7,7 @@ import { AppStatus } from "../../../db/utils"
|
|
|
5
7
|
import * as setup from "./utilities"
|
|
6
8
|
|
|
7
9
|
import { wipeDb } from "./utilities/TestFunctions"
|
|
10
|
+
import { tenancy } from "@budibase/backend-core"
|
|
8
11
|
|
|
9
12
|
describe("/cloud", () => {
|
|
10
13
|
let request = setup.getRequest()!
|
|
@@ -12,18 +15,10 @@ describe("/cloud", () => {
|
|
|
12
15
|
|
|
13
16
|
afterAll(setup.afterAll)
|
|
14
17
|
|
|
15
|
-
beforeAll(() => {
|
|
18
|
+
beforeAll(async () => {
|
|
16
19
|
// Importing is only allowed in self hosted environments
|
|
17
|
-
config.modeSelf()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
beforeEach(async () => {
|
|
21
20
|
await config.init()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
afterEach(async () => {
|
|
25
|
-
// clear all mocks
|
|
26
|
-
jest.clearAllMocks()
|
|
21
|
+
config.modeSelf()
|
|
27
22
|
})
|
|
28
23
|
|
|
29
24
|
describe("import", () => {
|
|
@@ -32,30 +27,28 @@ describe("/cloud", () => {
|
|
|
32
27
|
// import will not run
|
|
33
28
|
await wipeDb()
|
|
34
29
|
|
|
35
|
-
// get a count of apps before the import
|
|
36
|
-
const preImportApps = await request
|
|
37
|
-
.get(`/api/applications?status=${AppStatus.ALL}`)
|
|
38
|
-
.set(config.defaultHeaders())
|
|
39
|
-
.expect("Content-Type", /json/)
|
|
40
|
-
.expect(200)
|
|
41
|
-
|
|
42
30
|
// Perform the import
|
|
43
31
|
const res = await request
|
|
44
32
|
.post(`/api/cloud/import`)
|
|
33
|
+
.set(config.publicHeaders())
|
|
45
34
|
.attach("importFile", "src/api/routes/tests/data/export-test.tar.gz")
|
|
46
|
-
.set(config.defaultHeaders())
|
|
47
35
|
.expect(200)
|
|
48
36
|
expect(res.body.message).toEqual("Apps successfully imported.")
|
|
49
37
|
|
|
50
38
|
// get a count of apps after the import
|
|
51
39
|
const postImportApps = await request
|
|
52
40
|
.get(`/api/applications?status=${AppStatus.ALL}`)
|
|
53
|
-
.set(config.
|
|
41
|
+
.set(config.publicHeaders())
|
|
54
42
|
.expect("Content-Type", /json/)
|
|
55
43
|
.expect(200)
|
|
56
44
|
|
|
45
|
+
const apps = postImportApps.body as App[]
|
|
57
46
|
// There are two apps in the file that was imported so check for this
|
|
58
|
-
expect(
|
|
47
|
+
expect(apps.length).toEqual(2)
|
|
48
|
+
// The new tenant id was assigned to the imported apps
|
|
49
|
+
expect(tenancy.getTenantIDFromAppID(apps[0].appId)).toBe(
|
|
50
|
+
config.getTenantId()
|
|
51
|
+
)
|
|
59
52
|
})
|
|
60
53
|
})
|
|
61
54
|
})
|
|
@@ -2,7 +2,6 @@ import * as rowController from "../../../controllers/row"
|
|
|
2
2
|
import * as appController from "../../../controllers/application"
|
|
3
3
|
import { AppStatus } from "../../../../db/utils"
|
|
4
4
|
import { roles, tenancy, context } from "@budibase/backend-core"
|
|
5
|
-
import { TENANT_ID } from "../../../../tests/utilities/structures"
|
|
6
5
|
import env from "../../../../environment"
|
|
7
6
|
import { db } from "@budibase/backend-core"
|
|
8
7
|
import Nano from "@budibase/nano"
|
|
@@ -33,7 +32,7 @@ export const getAllTableRows = async (config: any) => {
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
export const clearAllApps = async (
|
|
36
|
-
tenantId
|
|
35
|
+
tenantId: string,
|
|
37
36
|
exceptions: Array<string> = []
|
|
38
37
|
) => {
|
|
39
38
|
await tenancy.doInTenant(tenantId, async () => {
|
|
@@ -11,8 +11,7 @@ import { OAuth2Client } from "google-auth-library"
|
|
|
11
11
|
import { buildExternalTableId } from "./utils"
|
|
12
12
|
import { DataSourceOperation, FieldTypes } from "../constants"
|
|
13
13
|
import { GoogleSpreadsheet } from "google-spreadsheet"
|
|
14
|
-
import
|
|
15
|
-
import { tenancy, db as dbCore, constants } from "@budibase/backend-core"
|
|
14
|
+
import { configs, HTTPError } from "@budibase/backend-core"
|
|
16
15
|
const fetch = require("node-fetch")
|
|
17
16
|
|
|
18
17
|
interface GoogleSheetsConfig {
|
|
@@ -173,16 +172,9 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|
|
173
172
|
async connect() {
|
|
174
173
|
try {
|
|
175
174
|
// Initialise oAuth client
|
|
176
|
-
|
|
177
|
-
let googleConfig = await dbCore.getScopedConfig(db, {
|
|
178
|
-
type: constants.Config.GOOGLE,
|
|
179
|
-
})
|
|
180
|
-
|
|
175
|
+
let googleConfig = await configs.getGoogleConfig()
|
|
181
176
|
if (!googleConfig) {
|
|
182
|
-
|
|
183
|
-
clientID: env.GOOGLE_CLIENT_ID,
|
|
184
|
-
clientSecret: env.GOOGLE_CLIENT_SECRET,
|
|
185
|
-
}
|
|
177
|
+
throw new HTTPError("Google config not found", 400)
|
|
186
178
|
}
|
|
187
179
|
|
|
188
180
|
const oauthClient = new OAuth2Client({
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
events,
|
|
3
|
+
DocumentType,
|
|
4
|
+
SEPARATOR,
|
|
5
|
+
UNICODE_MAX,
|
|
6
|
+
} from "@budibase/backend-core"
|
|
2
7
|
import {
|
|
3
8
|
Config,
|
|
4
9
|
isSMTPConfig,
|
|
@@ -9,15 +14,16 @@ import {
|
|
|
9
14
|
} from "@budibase/types"
|
|
10
15
|
import env from "./../../../../environment"
|
|
11
16
|
|
|
17
|
+
export const getConfigParams = () => {
|
|
18
|
+
return {
|
|
19
|
+
include_docs: true,
|
|
20
|
+
startkey: `${DocumentType.CONFIG}${SEPARATOR}`,
|
|
21
|
+
endkey: `${DocumentType.CONFIG}${SEPARATOR}${UNICODE_MAX}`,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
12
25
|
const getConfigs = async (globalDb: any): Promise<Config[]> => {
|
|
13
|
-
const response = await globalDb.allDocs(
|
|
14
|
-
dbUtils.getConfigParams(
|
|
15
|
-
{},
|
|
16
|
-
{
|
|
17
|
-
include_docs: true,
|
|
18
|
-
}
|
|
19
|
-
)
|
|
20
|
-
)
|
|
26
|
+
const response = await globalDb.allDocs(getConfigParams())
|
|
21
27
|
return response.rows.map((row: any) => row.doc)
|
|
22
28
|
}
|
|
23
29
|
|
|
@@ -8,9 +8,8 @@ jest.mock("@budibase/backend-core", () => {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
})
|
|
11
|
-
const {
|
|
11
|
+
const { context, db: dbCore } = require("@budibase/backend-core")
|
|
12
12
|
const TestConfig = require("../../../tests/utilities/TestConfiguration")
|
|
13
|
-
const { TENANT_ID } = require("../../../tests/utilities/structures")
|
|
14
13
|
|
|
15
14
|
// mock email view creation
|
|
16
15
|
|
|
@@ -26,8 +25,8 @@ describe("run", () => {
|
|
|
26
25
|
afterAll(config.end)
|
|
27
26
|
|
|
28
27
|
it("runs successfully", async () => {
|
|
29
|
-
await
|
|
30
|
-
const globalDb =
|
|
28
|
+
await config.doInTenant(async () => {
|
|
29
|
+
const globalDb = context.getGlobalDB()
|
|
31
30
|
await migration.run(globalDb)
|
|
32
31
|
expect(dbCore.createNewUserEmailView).toHaveBeenCalledTimes(1)
|
|
33
32
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Mimic configs test configuration from worker, creation configs directly in database
|
|
2
2
|
|
|
3
3
|
import * as structures from "./structures"
|
|
4
|
-
import {
|
|
4
|
+
import { configs } from "@budibase/backend-core"
|
|
5
5
|
import { Config } from "@budibase/types"
|
|
6
6
|
|
|
7
7
|
export const saveSettingsConfig = async (globalDb: any) => {
|
|
@@ -25,7 +25,7 @@ export const saveSmtpConfig = async (globalDb: any) => {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const saveConfig = async (config: Config, globalDb: any) => {
|
|
28
|
-
config._id =
|
|
28
|
+
config._id = configs.generateConfigID(config.type)
|
|
29
29
|
|
|
30
30
|
let response
|
|
31
31
|
try {
|
package/src/tests/jestEnv.ts
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
basicScreen,
|
|
22
22
|
basicLayout,
|
|
23
23
|
basicWebhook,
|
|
24
|
-
TENANT_ID,
|
|
25
24
|
} from "./structures"
|
|
26
25
|
import {
|
|
27
26
|
constants,
|
|
@@ -41,8 +40,8 @@ import { generateUserMetadataID } from "../../db/utils"
|
|
|
41
40
|
import { startup } from "../../startup"
|
|
42
41
|
import supertest from "supertest"
|
|
43
42
|
import {
|
|
43
|
+
App,
|
|
44
44
|
AuthToken,
|
|
45
|
-
Database,
|
|
46
45
|
Datasource,
|
|
47
46
|
Row,
|
|
48
47
|
SourceName,
|
|
@@ -63,7 +62,7 @@ class TestConfiguration {
|
|
|
63
62
|
started: boolean
|
|
64
63
|
appId: string | null
|
|
65
64
|
allApps: any[]
|
|
66
|
-
app
|
|
65
|
+
app?: App
|
|
67
66
|
prodApp: any
|
|
68
67
|
prodAppId: any
|
|
69
68
|
user: any
|
|
@@ -73,7 +72,7 @@ class TestConfiguration {
|
|
|
73
72
|
linkedTable: any
|
|
74
73
|
automation: any
|
|
75
74
|
datasource: any
|
|
76
|
-
tenantId
|
|
75
|
+
tenantId?: string
|
|
77
76
|
defaultUserValues: DefaultUserValues
|
|
78
77
|
|
|
79
78
|
constructor(openServer = true) {
|
|
@@ -89,7 +88,6 @@ class TestConfiguration {
|
|
|
89
88
|
}
|
|
90
89
|
this.appId = null
|
|
91
90
|
this.allApps = []
|
|
92
|
-
this.tenantId = null
|
|
93
91
|
this.defaultUserValues = this.populateDefaultUserValues()
|
|
94
92
|
}
|
|
95
93
|
|
|
@@ -154,19 +152,10 @@ class TestConfiguration {
|
|
|
154
152
|
|
|
155
153
|
// use a new id as the name to avoid name collisions
|
|
156
154
|
async init(appName = newid()) {
|
|
157
|
-
this.defaultUserValues = this.populateDefaultUserValues()
|
|
158
|
-
if (context.isMultiTenant()) {
|
|
159
|
-
this.tenantId = structures.tenant.id()
|
|
160
|
-
}
|
|
161
|
-
|
|
162
155
|
if (!this.started) {
|
|
163
156
|
await startup()
|
|
164
157
|
}
|
|
165
|
-
|
|
166
|
-
this.globalUserId = this.user._id
|
|
167
|
-
this.userMetadataId = generateUserMetadataID(this.globalUserId)
|
|
168
|
-
|
|
169
|
-
return this.createApp(appName)
|
|
158
|
+
return this.newTenant(appName)
|
|
170
159
|
}
|
|
171
160
|
|
|
172
161
|
end() {
|
|
@@ -182,24 +171,22 @@ class TestConfiguration {
|
|
|
182
171
|
}
|
|
183
172
|
|
|
184
173
|
// MODES
|
|
185
|
-
|
|
174
|
+
setMultiTenancy = (value: boolean) => {
|
|
186
175
|
env._set("MULTI_TENANCY", value)
|
|
187
176
|
coreEnv._set("MULTI_TENANCY", value)
|
|
188
177
|
}
|
|
189
178
|
|
|
190
|
-
|
|
179
|
+
setSelfHosted = (value: boolean) => {
|
|
191
180
|
env._set("SELF_HOSTED", value)
|
|
192
181
|
coreEnv._set("SELF_HOSTED", value)
|
|
193
182
|
}
|
|
194
183
|
|
|
195
184
|
modeCloud = () => {
|
|
196
|
-
this
|
|
197
|
-
this.#setMultiTenancy(true)
|
|
185
|
+
this.setSelfHosted(false)
|
|
198
186
|
}
|
|
199
187
|
|
|
200
188
|
modeSelf = () => {
|
|
201
|
-
this
|
|
202
|
-
this.#setMultiTenancy(false)
|
|
189
|
+
this.setSelfHosted(true)
|
|
203
190
|
}
|
|
204
191
|
|
|
205
192
|
// UTILS
|
|
@@ -354,6 +341,8 @@ class TestConfiguration {
|
|
|
354
341
|
})
|
|
355
342
|
}
|
|
356
343
|
|
|
344
|
+
// HEADERS
|
|
345
|
+
|
|
357
346
|
defaultHeaders(extras = {}) {
|
|
358
347
|
const tenantId = this.getTenantId()
|
|
359
348
|
const authObj: AuthToken = {
|
|
@@ -374,6 +363,7 @@ class TestConfiguration {
|
|
|
374
363
|
`${constants.Cookie.CurrentApp}=${appToken}`,
|
|
375
364
|
],
|
|
376
365
|
[constants.Header.CSRF_TOKEN]: this.defaultUserValues.csrfToken,
|
|
366
|
+
Host: this.tenantHost(),
|
|
377
367
|
...extras,
|
|
378
368
|
}
|
|
379
369
|
|
|
@@ -383,10 +373,6 @@ class TestConfiguration {
|
|
|
383
373
|
return headers
|
|
384
374
|
}
|
|
385
375
|
|
|
386
|
-
getTenantId() {
|
|
387
|
-
return this.tenantId || TENANT_ID
|
|
388
|
-
}
|
|
389
|
-
|
|
390
376
|
publicHeaders({ prodApp = true } = {}) {
|
|
391
377
|
const appId = prodApp ? this.prodAppId : this.appId
|
|
392
378
|
|
|
@@ -397,9 +383,7 @@ class TestConfiguration {
|
|
|
397
383
|
headers[constants.Header.APP_ID] = appId
|
|
398
384
|
}
|
|
399
385
|
|
|
400
|
-
|
|
401
|
-
headers[constants.Header.TENANT_ID] = this.tenantId
|
|
402
|
-
}
|
|
386
|
+
headers[constants.Header.TENANT_ID] = this.getTenantId()
|
|
403
387
|
|
|
404
388
|
return headers
|
|
405
389
|
}
|
|
@@ -413,6 +397,34 @@ class TestConfiguration {
|
|
|
413
397
|
return this.login({ email, roleId, builder, prodApp })
|
|
414
398
|
}
|
|
415
399
|
|
|
400
|
+
// TENANCY
|
|
401
|
+
|
|
402
|
+
tenantHost() {
|
|
403
|
+
const tenantId = this.getTenantId()
|
|
404
|
+
const platformHost = new URL(coreEnv.PLATFORM_URL).host.split(":")[0]
|
|
405
|
+
return `${tenantId}.${platformHost}`
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
getTenantId() {
|
|
409
|
+
if (!this.tenantId) {
|
|
410
|
+
throw new Error("no test tenant id - init has not been called")
|
|
411
|
+
}
|
|
412
|
+
return this.tenantId
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
async newTenant(appName = newid()): Promise<App> {
|
|
416
|
+
this.defaultUserValues = this.populateDefaultUserValues()
|
|
417
|
+
this.tenantId = structures.tenant.id()
|
|
418
|
+
this.user = await this.globalUser()
|
|
419
|
+
this.globalUserId = this.user._id
|
|
420
|
+
this.userMetadataId = generateUserMetadataID(this.globalUserId)
|
|
421
|
+
return this.createApp(appName)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
doInTenant(task: any) {
|
|
425
|
+
return context.doInTenant(this.getTenantId(), task)
|
|
426
|
+
}
|
|
427
|
+
|
|
416
428
|
// API
|
|
417
429
|
|
|
418
430
|
async generateApiKey(userId = this.defaultUserValues.globalUserId) {
|
|
@@ -432,7 +444,7 @@ class TestConfiguration {
|
|
|
432
444
|
}
|
|
433
445
|
|
|
434
446
|
// APP
|
|
435
|
-
async createApp(appName: string) {
|
|
447
|
+
async createApp(appName: string): Promise<App> {
|
|
436
448
|
// create dev app
|
|
437
449
|
// clear any old app
|
|
438
450
|
this.appId = null
|
|
@@ -442,7 +454,7 @@ class TestConfiguration {
|
|
|
442
454
|
null,
|
|
443
455
|
controllers.app.create
|
|
444
456
|
)
|
|
445
|
-
this.appId = this.app
|
|
457
|
+
this.appId = this.app?.appId!
|
|
446
458
|
})
|
|
447
459
|
return await context.doInAppContext(this.appId, async () => {
|
|
448
460
|
// create production app
|