@budibase/server 2.7.7-alpha.2 → 2.7.9
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.fbee8e8b.js → index.358319af.js} +364 -364
- package/builder/assets/{index.b33e8ad5.css → index.a86e2071.css} +1 -1
- package/builder/index.html +2 -2
- package/dist/automation.js +42 -112
- package/dist/automation.js.map +3 -3
- package/dist/index.js +42 -116
- package/dist/index.js.map +3 -3
- package/dist/query.js +20 -24
- package/dist/query.js.map +3 -3
- package/package.json +8 -8
- package/src/api/controllers/datasource.ts +1 -13
- package/src/automations/steps/sendSmtpEmail.ts +4 -55
- package/src/automations/tests/sendSmtpEmail.spec.js +71 -0
- package/src/integrations/googlesheets.ts +2 -18
- package/src/sdk/app/datasources/datasources.ts +1 -1
- package/src/utilities/workerRequests.ts +9 -20
- package/src/automations/tests/sendSmtpEmail.spec.ts +0 -74
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.7.
|
|
4
|
+
"version": "2.7.9",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"license": "GPL-3.0",
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@apidevtools/swagger-parser": "10.0.3",
|
|
49
|
-
"@budibase/backend-core": "2.7.
|
|
50
|
-
"@budibase/client": "2.7.
|
|
51
|
-
"@budibase/pro": "2.7.
|
|
52
|
-
"@budibase/shared-core": "2.7.
|
|
53
|
-
"@budibase/string-templates": "2.7.
|
|
54
|
-
"@budibase/types": "2.7.
|
|
49
|
+
"@budibase/backend-core": "2.7.9",
|
|
50
|
+
"@budibase/client": "2.7.9",
|
|
51
|
+
"@budibase/pro": "2.7.9",
|
|
52
|
+
"@budibase/shared-core": "2.7.9",
|
|
53
|
+
"@budibase/string-templates": "2.7.9",
|
|
54
|
+
"@budibase/types": "2.7.9",
|
|
55
55
|
"@bull-board/api": "3.7.0",
|
|
56
56
|
"@bull-board/koa": "3.9.4",
|
|
57
57
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -195,5 +195,5 @@
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
},
|
|
198
|
-
"gitHead": "
|
|
198
|
+
"gitHead": "434f2c09066e92b3f81cafef982e8e36487c2c7a"
|
|
199
199
|
}
|
|
@@ -11,7 +11,7 @@ import { BuildSchemaErrors, InvalidColumns } from "../../constants"
|
|
|
11
11
|
import { getIntegration } from "../../integrations"
|
|
12
12
|
import { getDatasourceAndQuery } from "./row/utils"
|
|
13
13
|
import { invalidateDynamicVariables } from "../../threads/utils"
|
|
14
|
-
import { db as dbCore, context, events
|
|
14
|
+
import { db as dbCore, context, events } from "@budibase/backend-core"
|
|
15
15
|
import {
|
|
16
16
|
UserCtx,
|
|
17
17
|
Datasource,
|
|
@@ -25,11 +25,9 @@ import {
|
|
|
25
25
|
FetchDatasourceInfoResponse,
|
|
26
26
|
IntegrationBase,
|
|
27
27
|
DatasourcePlus,
|
|
28
|
-
SourceName,
|
|
29
28
|
} from "@budibase/types"
|
|
30
29
|
import sdk from "../../sdk"
|
|
31
30
|
import { builderSocket } from "../../websockets"
|
|
32
|
-
import { setupCreationAuth as googleSetupCreationAuth } from "../../integrations/googlesheets"
|
|
33
31
|
|
|
34
32
|
function getErrorTables(errors: any, errorType: string) {
|
|
35
33
|
return Object.entries(errors)
|
|
@@ -308,12 +306,6 @@ export async function update(ctx: UserCtx<any, UpdateDatasourceResponse>) {
|
|
|
308
306
|
builderSocket?.emitDatasourceUpdate(ctx, datasource)
|
|
309
307
|
}
|
|
310
308
|
|
|
311
|
-
const preSaveAction: Partial<Record<SourceName, any>> = {
|
|
312
|
-
[SourceName.GOOGLE_SHEETS]: async (datasource: Datasource) => {
|
|
313
|
-
await googleSetupCreationAuth(datasource.config as any)
|
|
314
|
-
},
|
|
315
|
-
}
|
|
316
|
-
|
|
317
309
|
export async function save(
|
|
318
310
|
ctx: UserCtx<CreateDatasourceRequest, CreateDatasourceResponse>
|
|
319
311
|
) {
|
|
@@ -335,10 +327,6 @@ export async function save(
|
|
|
335
327
|
setDefaultDisplayColumns(datasource)
|
|
336
328
|
}
|
|
337
329
|
|
|
338
|
-
if (preSaveAction[datasource.source]) {
|
|
339
|
-
await preSaveAction[datasource.source](datasource)
|
|
340
|
-
}
|
|
341
|
-
|
|
342
330
|
const dbResp = await db.put(datasource)
|
|
343
331
|
await events.datasource.created(datasource)
|
|
344
332
|
datasource._rev = dbResp.rev
|
|
@@ -48,35 +48,6 @@ export const definition: AutomationStepSchema = {
|
|
|
48
48
|
type: AutomationIOType.STRING,
|
|
49
49
|
title: "HTML Contents",
|
|
50
50
|
},
|
|
51
|
-
addInvite: {
|
|
52
|
-
type: AutomationIOType.BOOLEAN,
|
|
53
|
-
title: "Add calendar invite",
|
|
54
|
-
},
|
|
55
|
-
startTime: {
|
|
56
|
-
type: AutomationIOType.DATE,
|
|
57
|
-
title: "Start Time",
|
|
58
|
-
dependsOn: "addInvite",
|
|
59
|
-
},
|
|
60
|
-
endTime: {
|
|
61
|
-
type: AutomationIOType.DATE,
|
|
62
|
-
title: "End Time",
|
|
63
|
-
dependsOn: "addInvite",
|
|
64
|
-
},
|
|
65
|
-
summary: {
|
|
66
|
-
type: AutomationIOType.STRING,
|
|
67
|
-
title: "Meeting Summary",
|
|
68
|
-
dependsOn: "addInvite",
|
|
69
|
-
},
|
|
70
|
-
location: {
|
|
71
|
-
type: AutomationIOType.STRING,
|
|
72
|
-
title: "Location",
|
|
73
|
-
dependsOn: "addInvite",
|
|
74
|
-
},
|
|
75
|
-
url: {
|
|
76
|
-
type: AutomationIOType.STRING,
|
|
77
|
-
title: "URL",
|
|
78
|
-
dependsOn: "addInvite",
|
|
79
|
-
},
|
|
80
51
|
},
|
|
81
52
|
required: ["to", "from", "subject", "contents"],
|
|
82
53
|
},
|
|
@@ -97,43 +68,21 @@ export const definition: AutomationStepSchema = {
|
|
|
97
68
|
}
|
|
98
69
|
|
|
99
70
|
export async function run({ inputs }: AutomationStepInput) {
|
|
100
|
-
let {
|
|
101
|
-
to,
|
|
102
|
-
from,
|
|
103
|
-
subject,
|
|
104
|
-
contents,
|
|
105
|
-
cc,
|
|
106
|
-
bcc,
|
|
107
|
-
addInvite,
|
|
108
|
-
startTime,
|
|
109
|
-
endTime,
|
|
110
|
-
summary,
|
|
111
|
-
location,
|
|
112
|
-
url,
|
|
113
|
-
} = inputs
|
|
71
|
+
let { to, from, subject, contents, cc, bcc } = inputs
|
|
114
72
|
if (!contents) {
|
|
115
73
|
contents = "<h1>No content</h1>"
|
|
116
74
|
}
|
|
117
75
|
to = to || undefined
|
|
118
76
|
try {
|
|
119
|
-
let response = await sendSmtpEmail(
|
|
77
|
+
let response = await sendSmtpEmail(
|
|
120
78
|
to,
|
|
121
79
|
from,
|
|
122
80
|
subject,
|
|
123
81
|
contents,
|
|
124
82
|
cc,
|
|
125
83
|
bcc,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
? {
|
|
129
|
-
startTime,
|
|
130
|
-
endTime,
|
|
131
|
-
summary,
|
|
132
|
-
location,
|
|
133
|
-
url,
|
|
134
|
-
}
|
|
135
|
-
: undefined,
|
|
136
|
-
})
|
|
84
|
+
true
|
|
85
|
+
)
|
|
137
86
|
return {
|
|
138
87
|
success: true,
|
|
139
88
|
response,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
|
|
2
|
+
function generateResponse(to, from) {
|
|
3
|
+
return {
|
|
4
|
+
"success": true,
|
|
5
|
+
"response": {
|
|
6
|
+
"accepted": [
|
|
7
|
+
to
|
|
8
|
+
],
|
|
9
|
+
"envelope": {
|
|
10
|
+
"from": from,
|
|
11
|
+
"to": [
|
|
12
|
+
to
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"message": `Email sent to ${to}.`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const mockFetch = jest.fn(() => ({
|
|
22
|
+
headers: {
|
|
23
|
+
raw: () => {
|
|
24
|
+
return { "content-type": ["application/json"] }
|
|
25
|
+
},
|
|
26
|
+
get: () => ["application/json"],
|
|
27
|
+
},
|
|
28
|
+
json: jest.fn(() => response),
|
|
29
|
+
status: 200,
|
|
30
|
+
text: jest.fn(),
|
|
31
|
+
}))
|
|
32
|
+
jest.mock("node-fetch", () => mockFetch)
|
|
33
|
+
const setup = require("./utilities")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
describe("test the outgoing webhook action", () => {
|
|
37
|
+
let inputs
|
|
38
|
+
let config = setup.getConfig()
|
|
39
|
+
beforeAll(async () => {
|
|
40
|
+
await config.init()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
afterAll(setup.afterAll)
|
|
44
|
+
|
|
45
|
+
it("should be able to run the action", async () => {
|
|
46
|
+
inputs = {
|
|
47
|
+
to: "user1@test.com",
|
|
48
|
+
from: "admin@test.com",
|
|
49
|
+
subject: "hello",
|
|
50
|
+
contents: "testing",
|
|
51
|
+
}
|
|
52
|
+
let resp = generateResponse(inputs.to, inputs.from)
|
|
53
|
+
mockFetch.mockImplementationOnce(() => ({
|
|
54
|
+
headers: {
|
|
55
|
+
raw: () => {
|
|
56
|
+
return { "content-type": ["application/json"] }
|
|
57
|
+
},
|
|
58
|
+
get: () => ["application/json"],
|
|
59
|
+
},
|
|
60
|
+
json: jest.fn(() => resp),
|
|
61
|
+
status: 200,
|
|
62
|
+
text: jest.fn(),
|
|
63
|
+
}))
|
|
64
|
+
const res = await setup.runStep(setup.actions.SEND_EMAIL_SMTP.stepId, inputs)
|
|
65
|
+
expect(res.response).toEqual(resp)
|
|
66
|
+
expect(res.success).toEqual(true)
|
|
67
|
+
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
})
|
|
@@ -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 {
|
|
22
|
+
import { configs, HTTPError } from "@budibase/backend-core"
|
|
24
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: "
|
|
75
|
+
display: "Google Sheet URL",
|
|
79
76
|
type: DatasourceFieldType.STRING,
|
|
80
77
|
required: true,
|
|
81
78
|
},
|
|
@@ -150,7 +147,6 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|
|
150
147
|
|
|
151
148
|
async testConnection(): Promise<ConnectionInfo> {
|
|
152
149
|
try {
|
|
153
|
-
await setupCreationAuth(this.config)
|
|
154
150
|
await this.connect()
|
|
155
151
|
return { connected: true }
|
|
156
152
|
} catch (e: any) {
|
|
@@ -570,18 +566,6 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|
|
570
566
|
}
|
|
571
567
|
}
|
|
572
568
|
|
|
573
|
-
export async function setupCreationAuth(datasouce: GoogleSheetsConfig) {
|
|
574
|
-
if (datasouce.continueSetupId) {
|
|
575
|
-
const appId = context.getAppId()
|
|
576
|
-
const tokens = await cache.get(
|
|
577
|
-
`datasource:creation:${appId}:google:${datasouce.continueSetupId}`
|
|
578
|
-
)
|
|
579
|
-
|
|
580
|
-
datasouce.auth = tokens.tokens
|
|
581
|
-
delete datasouce.continueSetupId
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
569
|
export default {
|
|
586
570
|
schema: SCHEMA,
|
|
587
571
|
integration: GoogleSheetsIntegration,
|
|
@@ -135,7 +135,7 @@ export function mergeConfigs(update: Datasource, old: Datasource) {
|
|
|
135
135
|
// specific to REST datasources, fix the auth configs again if required
|
|
136
136
|
if (hasAuthConfigs(update)) {
|
|
137
137
|
const configs = update.config.authConfigs as RestAuthConfig[]
|
|
138
|
-
const oldConfigs = old.config?.authConfigs as RestAuthConfig[]
|
|
138
|
+
const oldConfigs = (old.config?.authConfigs as RestAuthConfig[]) || []
|
|
139
139
|
for (let config of configs) {
|
|
140
140
|
if (config.type !== RestAuthType.BASIC) {
|
|
141
141
|
continue
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
})
|