@budibase/server 2.7.20-alpha.0 → 2.7.20

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.
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  ConnectionInfo,
3
- Datasource,
4
3
  DatasourceFeature,
5
4
  DatasourceFieldType,
6
5
  DatasourcePlus,
@@ -20,15 +19,13 @@ import { OAuth2Client } from "google-auth-library"
20
19
  import { buildExternalTableId, finaliseExternalTables } from "./utils"
21
20
  import { GoogleSpreadsheet, GoogleSpreadsheetRow } from "google-spreadsheet"
22
21
  import fetch from "node-fetch"
23
- import { cache, configs, context, HTTPError } from "@budibase/backend-core"
24
- import { dataFilters, utils } from "@budibase/shared-core"
22
+ import { configs, HTTPError } from "@budibase/backend-core"
23
+ import { dataFilters } from "@budibase/shared-core"
25
24
  import { GOOGLE_SHEETS_PRIMARY_KEY } from "../constants"
26
- import sdk from "../sdk"
27
25
 
28
26
  interface GoogleSheetsConfig {
29
27
  spreadsheetId: string
30
28
  auth: OAuthClientConfig
31
- continueSetupId?: string
32
29
  }
33
30
 
34
31
  interface OAuthClientConfig {
@@ -75,7 +72,7 @@ const SCHEMA: Integration = {
75
72
  },
76
73
  datasource: {
77
74
  spreadsheetId: {
78
- display: "Spreadsheet URL",
75
+ display: "Google Sheet URL",
79
76
  type: DatasourceFieldType.STRING,
80
77
  required: true,
81
78
  },
@@ -210,8 +207,6 @@ class GoogleSheetsIntegration implements DatasourcePlus {
210
207
 
211
208
  async connect() {
212
209
  try {
213
- await setupCreationAuth(this.config)
214
-
215
210
  // Initialise oAuth client
216
211
  let googleConfig = await configs.getGoogleDatasourceConfig()
217
212
  if (!googleConfig) {
@@ -274,24 +269,24 @@ class GoogleSheetsIntegration implements DatasourcePlus {
274
269
  }
275
270
 
276
271
  async buildSchema(datasourceId: string, entities: Record<string, Table>) {
272
+ // not fully configured yet
273
+ if (!this.config.auth) {
274
+ return
275
+ }
277
276
  await this.connect()
278
277
  const sheets = this.client.sheetsByIndex
279
278
  const tables: Record<string, Table> = {}
280
- await utils.parallelForeach(
281
- sheets,
282
- async sheet => {
283
- // must fetch rows to determine schema
284
- await sheet.getRows({ limit: 0, offset: 0 })
285
-
286
- const id = buildExternalTableId(datasourceId, sheet.title)
287
- tables[sheet.title] = this.getTableSchema(
288
- sheet.title,
289
- sheet.headerValues,
290
- id
291
- )
292
- },
293
- 10
294
- )
279
+ for (let sheet of sheets) {
280
+ // must fetch rows to determine schema
281
+ await sheet.getRows()
282
+
283
+ const id = buildExternalTableId(datasourceId, sheet.title)
284
+ tables[sheet.title] = this.getTableSchema(
285
+ sheet.title,
286
+ sheet.headerValues,
287
+ id
288
+ )
289
+ }
295
290
  const final = finaliseExternalTables(tables, entities)
296
291
  this.tables = final.tables
297
292
  this.schemaErrors = final.errors
@@ -571,18 +566,6 @@ class GoogleSheetsIntegration implements DatasourcePlus {
571
566
  }
572
567
  }
573
568
 
574
- export async function setupCreationAuth(datasouce: GoogleSheetsConfig) {
575
- if (datasouce.continueSetupId) {
576
- const appId = context.getAppId()
577
- const tokens = await cache.get(
578
- `datasource:creation:${appId}:google:${datasouce.continueSetupId}`
579
- )
580
-
581
- datasouce.auth = tokens.tokens
582
- delete datasouce.continueSetupId
583
- }
584
- }
585
-
586
569
  export default {
587
570
  schema: SCHEMA,
588
571
  integration: GoogleSheetsIntegration,
@@ -351,7 +351,7 @@ const SCHEMA: Integration = getSchema()
351
351
 
352
352
  class MongoIntegration implements IntegrationBase {
353
353
  private config: MongoDBConfig
354
- private client: MongoClient
354
+ private client: any
355
355
 
356
356
  constructor(config: MongoDBConfig) {
357
357
  this.config = config
@@ -372,8 +372,6 @@ class MongoIntegration implements IntegrationBase {
372
372
  response.connected = true
373
373
  } catch (e: any) {
374
374
  response.error = e.message as string
375
- } finally {
376
- await this.client.close()
377
375
  }
378
376
  return response
379
377
  }
@@ -382,7 +380,7 @@ class MongoIntegration implements IntegrationBase {
382
380
  return this.client.connect()
383
381
  }
384
382
 
385
- createObjectIds(json: any) {
383
+ createObjectIds(json: any): object {
386
384
  const self = this
387
385
  function interpolateObjectIds(json: any) {
388
386
  for (let field of Object.keys(json)) {
@@ -322,8 +322,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
322
322
  await this.openConnection()
323
323
  const columnsResponse: { rows: PostgresColumn[] } =
324
324
  await this.client.query(this.COLUMNS_SQL)
325
- const names = columnsResponse.rows.map(row => row.table_name)
326
- return [...new Set(names)]
325
+ return columnsResponse.rows.map(row => row.table_name)
327
326
  } finally {
328
327
  await this.closeConnection()
329
328
  }
@@ -103,7 +103,7 @@ export default async (ctx: UserCtx, next: any) => {
103
103
  userId,
104
104
  globalId,
105
105
  roleId,
106
- role: await roles.getRole(roleId, { defaultPublic: true }),
106
+ role: await roles.getRole(roleId),
107
107
  }
108
108
  }
109
109
 
@@ -1,4 +1,4 @@
1
- import { db as dbCore, encryption, objectStore } from "@budibase/backend-core"
1
+ import { db as dbCore, objectStore } from "@budibase/backend-core"
2
2
  import { budibaseTempDir } from "../../../utilities/budibaseDir"
3
3
  import { streamFile, createTempFolder } from "../../../utilities/fileSystem"
4
4
  import { ObjectStoreBuckets } from "../../../constants"
@@ -18,8 +18,7 @@ import { join } from "path"
18
18
  import env from "../../../environment"
19
19
 
20
20
  const uuid = require("uuid/v4")
21
- import tar from "tar"
22
-
21
+ const tar = require("tar")
23
22
  const MemoryStream = require("memorystream")
24
23
 
25
24
  interface DBDumpOpts {
@@ -31,18 +30,16 @@ interface ExportOpts extends DBDumpOpts {
31
30
  tar?: boolean
32
31
  excludeRows?: boolean
33
32
  excludeLogs?: boolean
34
- encryptPassword?: string
35
33
  }
36
34
 
37
35
  function tarFilesToTmp(tmpDir: string, files: string[]) {
38
- const fileName = `${uuid()}.tar.gz`
39
- const exportFile = join(budibaseTempDir(), fileName)
36
+ const exportFile = join(budibaseTempDir(), `${uuid()}.tar.gz`)
40
37
  tar.create(
41
38
  {
42
39
  sync: true,
43
40
  gzip: true,
44
41
  file: exportFile,
45
- noDirRecurse: false,
42
+ recursive: true,
46
43
  cwd: tmpDir,
47
44
  },
48
45
  files
@@ -127,7 +124,6 @@ export async function exportApp(appId: string, config?: ExportOpts) {
127
124
  )
128
125
  }
129
126
  }
130
-
131
127
  const downloadedPath = join(tmpPath, appPath)
132
128
  if (fs.existsSync(downloadedPath)) {
133
129
  const allFiles = fs.readdirSync(downloadedPath)
@@ -145,27 +141,12 @@ export async function exportApp(appId: string, config?: ExportOpts) {
145
141
  filter: defineFilter(config?.excludeRows, config?.excludeLogs),
146
142
  exportPath: dbPath,
147
143
  })
148
-
149
- if (config?.encryptPassword) {
150
- for (let file of fs.readdirSync(tmpPath)) {
151
- const path = join(tmpPath, file)
152
-
153
- await encryption.encryptFile(
154
- { dir: tmpPath, filename: file },
155
- config.encryptPassword
156
- )
157
-
158
- fs.rmSync(path)
159
- }
160
- }
161
-
162
144
  // if tar requested, return where the tarball is
163
145
  if (config?.tar) {
164
146
  // now the tmpPath contains both the DB export and attachments, tar this
165
147
  const tarPath = tarFilesToTmp(tmpPath, fs.readdirSync(tmpPath))
166
148
  // cleanup the tmp export files as tarball returned
167
149
  fs.rmSync(tmpPath, { recursive: true, force: true })
168
-
169
150
  return tarPath
170
151
  }
171
152
  // tar not requested, turn the directory where export is
@@ -180,20 +161,11 @@ export async function exportApp(appId: string, config?: ExportOpts) {
180
161
  * @param {boolean} excludeRows Flag to state whether the export should include data.
181
162
  * @returns {*} a readable stream of the backup which is written in real time
182
163
  */
183
- export async function streamExportApp({
184
- appId,
185
- excludeRows,
186
- encryptPassword,
187
- }: {
188
- appId: string
189
- excludeRows: boolean
190
- encryptPassword?: string
191
- }) {
164
+ export async function streamExportApp(appId: string, excludeRows: boolean) {
192
165
  const tmpPath = await exportApp(appId, {
193
166
  excludeRows,
194
167
  excludeLogs: true,
195
168
  tar: true,
196
- encryptPassword,
197
169
  })
198
170
  return streamFile(tmpPath)
199
171
  }
@@ -1,4 +1,4 @@
1
- import { db as dbCore, encryption, objectStore } from "@budibase/backend-core"
1
+ import { db as dbCore, objectStore } from "@budibase/backend-core"
2
2
  import { Database, Row } from "@budibase/types"
3
3
  import { getAutomationParams, TABLE_ROW_PREFIX } from "../../../db/utils"
4
4
  import { budibaseTempDir } from "../../../utilities/budibaseDir"
@@ -20,7 +20,6 @@ type TemplateType = {
20
20
  file?: {
21
21
  type: string
22
22
  path: string
23
- password?: string
24
23
  }
25
24
  key?: string
26
25
  }
@@ -124,22 +123,6 @@ export function untarFile(file: { path: string }) {
124
123
  return tmpPath
125
124
  }
126
125
 
127
- async function decryptFiles(path: string, password: string) {
128
- try {
129
- for (let file of fs.readdirSync(path)) {
130
- const inputPath = join(path, file)
131
- const outputPath = inputPath.replace(/\.enc$/, "")
132
- await encryption.decryptFile(inputPath, outputPath, password)
133
- fs.rmSync(inputPath)
134
- }
135
- } catch (err: any) {
136
- if (err.message === "incorrect header check") {
137
- throw new Error("File cannot be imported")
138
- }
139
- throw err
140
- }
141
- }
142
-
143
126
  export function getGlobalDBFile(tmpPath: string) {
144
127
  return fs.readFileSync(join(tmpPath, GLOBAL_DB_EXPORT_FILE), "utf8")
145
128
  }
@@ -160,9 +143,6 @@ export async function importApp(
160
143
  template.file && fs.lstatSync(template.file.path).isDirectory()
161
144
  if (template.file && (isTar || isDirectory)) {
162
145
  const tmpPath = isTar ? untarFile(template.file) : template.file.path
163
- if (isTar && template.file.password) {
164
- await decryptFiles(tmpPath, template.file.password)
165
- }
166
146
  const contents = fs.readdirSync(tmpPath)
167
147
  // have to handle object import
168
148
  if (contents.length) {
@@ -164,6 +164,5 @@ export function mergeConfigs(update: Datasource, old: Datasource) {
164
164
  delete update.config[key]
165
165
  }
166
166
  }
167
-
168
167
  return update
169
168
  }
@@ -9,7 +9,7 @@ import {
9
9
  env as coreEnv,
10
10
  } from "@budibase/backend-core"
11
11
  import { updateAppRole } from "./global"
12
- import { BBContext, User, EmailInvite } from "@budibase/types"
12
+ import { BBContext, User } from "@budibase/types"
13
13
 
14
14
  export function request(ctx?: BBContext, request?: any) {
15
15
  if (!request.headers) {
@@ -65,25 +65,15 @@ async function checkResponse(
65
65
  }
66
66
 
67
67
  // have to pass in the tenant ID as this could be coming from an automation
68
- export async function sendSmtpEmail({
69
- to,
70
- from,
71
- subject,
72
- contents,
73
- cc,
74
- bcc,
75
- automation,
76
- invite,
77
- }: {
78
- to: string
79
- from: string
80
- subject: string
81
- contents: string
82
- cc: string
83
- bcc: string
68
+ export async function sendSmtpEmail(
69
+ to: string,
70
+ from: string,
71
+ subject: string,
72
+ contents: string,
73
+ cc: string,
74
+ bcc: string,
84
75
  automation: boolean
85
- invite?: EmailInvite
86
- }) {
76
+ ) {
87
77
  // tenant ID will be set in header
88
78
  const response = await fetch(
89
79
  checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`),
@@ -98,7 +88,6 @@ export async function sendSmtpEmail({
98
88
  bcc,
99
89
  purpose: "custom",
100
90
  automation,
101
- invite,
102
91
  },
103
92
  })
104
93
  )
@@ -1,74 +0,0 @@
1
- import * as workerRequests from "../../utilities/workerRequests"
2
-
3
- jest.mock("../../utilities/workerRequests", () => ({
4
- sendSmtpEmail: jest.fn(),
5
- }))
6
-
7
- function generateResponse(to: string, from: string) {
8
- return {
9
- success: true,
10
- response: {
11
- accepted: [to],
12
- envelope: {
13
- from: from,
14
- to: [to],
15
- },
16
- message: `Email sent to ${to}.`,
17
- },
18
- }
19
- }
20
-
21
- const setup = require("./utilities")
22
-
23
- describe("test the outgoing webhook action", () => {
24
- let inputs
25
- let config = setup.getConfig()
26
- beforeAll(async () => {
27
- await config.init()
28
- })
29
-
30
- afterAll(setup.afterAll)
31
-
32
- it("should be able to run the action", async () => {
33
- jest
34
- .spyOn(workerRequests, "sendSmtpEmail")
35
- .mockImplementationOnce(async () =>
36
- generateResponse("user1@test.com", "admin@test.com")
37
- )
38
- const invite = {
39
- startTime: new Date(),
40
- endTime: new Date(),
41
- summary: "summary",
42
- location: "location",
43
- url: "url",
44
- }
45
- inputs = {
46
- to: "user1@test.com",
47
- from: "admin@test.com",
48
- subject: "hello",
49
- contents: "testing",
50
- cc: "cc",
51
- bcc: "bcc",
52
- addInvite: true,
53
- ...invite,
54
- }
55
- let resp = generateResponse(inputs.to, inputs.from)
56
- const res = await setup.runStep(
57
- setup.actions.SEND_EMAIL_SMTP.stepId,
58
- inputs
59
- )
60
- expect(res.response).toEqual(resp)
61
- expect(res.success).toEqual(true)
62
- expect(workerRequests.sendSmtpEmail).toHaveBeenCalledTimes(1)
63
- expect(workerRequests.sendSmtpEmail).toHaveBeenCalledWith({
64
- to: "user1@test.com",
65
- from: "admin@test.com",
66
- subject: "hello",
67
- contents: "testing",
68
- cc: "cc",
69
- bcc: "bcc",
70
- invite,
71
- automation: true,
72
- })
73
- })
74
- })