@budibase/worker 2.4.43 → 2.4.44-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/package.json +6 -6
- package/src/api/controllers/global/auth.ts +0 -5
- package/src/api/controllers/global/configs.ts +49 -0
- package/src/api/controllers/global/self.ts +1 -14
- package/src/api/controllers/global/users.ts +2 -3
- package/src/api/controllers/system/environment.ts +1 -0
- package/src/api/controllers/system/tenants.ts +4 -0
- package/src/api/routes/global/tests/configs.spec.ts +3 -0
- package/src/api/routes/system/tests/environment.spec.ts +1 -0
- package/src/constants/index.ts +1 -0
- package/src/constants/templates/core.hbs +33 -0
- package/src/constants/templates/index.ts +1 -0
- package/src/index.ts +2 -0
- package/src/sdk/tenants/tenants.ts +7 -0
- package/src/tests/TestConfiguration.ts +2 -0
- package/src/tests/api/tenants.ts +2 -0
- package/src/tests/jestSetup.ts +5 -1
- package/src/utilities/configs.ts +27 -0
- package/src/utilities/email.ts +13 -4
- package/src/utilities/templates.ts +9 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.4.
|
|
4
|
+
"version": "2.4.44-alpha.1",
|
|
5
5
|
"description": "Budibase background service",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"author": "Budibase",
|
|
37
37
|
"license": "GPL-3.0",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@budibase/backend-core": "
|
|
40
|
-
"@budibase/pro": "2.4.
|
|
41
|
-
"@budibase/string-templates": "
|
|
42
|
-
"@budibase/types": "
|
|
39
|
+
"@budibase/backend-core": "2.4.44-alpha.1",
|
|
40
|
+
"@budibase/pro": "2.4.44-alpha.0",
|
|
41
|
+
"@budibase/string-templates": "2.4.44-alpha.1",
|
|
42
|
+
"@budibase/types": "2.4.44-alpha.1",
|
|
43
43
|
"@koa/router": "8.0.8",
|
|
44
44
|
"@sentry/node": "6.17.7",
|
|
45
45
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
"typescript": "4.7.3",
|
|
102
102
|
"update-dotenv": "1.1.1"
|
|
103
103
|
},
|
|
104
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "2597bbe05cd384874fad4f4da9ffd525117dcacf"
|
|
105
105
|
}
|
|
@@ -50,11 +50,6 @@ async function passportCallback(
|
|
|
50
50
|
setCookie(ctx, token, Cookie.Auth, { sign: false })
|
|
51
51
|
// set the token in a header as well for APIs
|
|
52
52
|
ctx.set(Header.TOKEN, token)
|
|
53
|
-
// get rid of any app cookies on login
|
|
54
|
-
// have to check test because this breaks cypress
|
|
55
|
-
if (!env.isTest()) {
|
|
56
|
-
clearCookie(ctx, Cookie.CurrentApp)
|
|
57
|
-
}
|
|
58
53
|
}
|
|
59
54
|
|
|
60
55
|
export const login = async (ctx: Ctx<LoginRequest>, next: any) => {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
tenancy,
|
|
12
12
|
} from "@budibase/backend-core"
|
|
13
13
|
import { checkAnyUserExists } from "../../../utilities/users"
|
|
14
|
+
import { getLicensedConfig } from "../../../utilities/configs"
|
|
14
15
|
import {
|
|
15
16
|
Config,
|
|
16
17
|
ConfigType,
|
|
@@ -211,6 +212,38 @@ export async function save(ctx: UserCtx<Config>) {
|
|
|
211
212
|
ctx.throw(400, err)
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
// Ignore branding changes if the license does not permit it
|
|
216
|
+
// Favicon and Logo Url are excluded.
|
|
217
|
+
try {
|
|
218
|
+
const brandingEnabled = await pro.features.isBrandingEnabled()
|
|
219
|
+
if (existingConfig?.config && !brandingEnabled) {
|
|
220
|
+
const {
|
|
221
|
+
emailBrandingEnabled,
|
|
222
|
+
testimonialsEnabled,
|
|
223
|
+
platformTitle,
|
|
224
|
+
metaDescription,
|
|
225
|
+
loginHeading,
|
|
226
|
+
loginButton,
|
|
227
|
+
metaImageUrl,
|
|
228
|
+
metaTitle,
|
|
229
|
+
} = existingConfig.config
|
|
230
|
+
|
|
231
|
+
body.config = {
|
|
232
|
+
...body.config,
|
|
233
|
+
emailBrandingEnabled,
|
|
234
|
+
testimonialsEnabled,
|
|
235
|
+
platformTitle,
|
|
236
|
+
metaDescription,
|
|
237
|
+
loginHeading,
|
|
238
|
+
loginButton,
|
|
239
|
+
metaImageUrl,
|
|
240
|
+
metaTitle,
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.error("There was an issue retrieving the license", e)
|
|
245
|
+
}
|
|
246
|
+
|
|
214
247
|
try {
|
|
215
248
|
body._id = configs.generateConfigID(type)
|
|
216
249
|
const response = await configs.save(body)
|
|
@@ -276,6 +309,9 @@ export async function publicSettings(
|
|
|
276
309
|
// settings
|
|
277
310
|
const configDoc = await configs.getSettingsConfigDoc()
|
|
278
311
|
const config = configDoc.config
|
|
312
|
+
|
|
313
|
+
const branding = await pro.branding.getBrandingConfig(config)
|
|
314
|
+
|
|
279
315
|
// enrich the logo url - empty url means deleted
|
|
280
316
|
if (config.logoUrl && config.logoUrl !== "") {
|
|
281
317
|
config.logoUrl = objectStore.getGlobalFileUrl(
|
|
@@ -285,8 +321,19 @@ export async function publicSettings(
|
|
|
285
321
|
)
|
|
286
322
|
}
|
|
287
323
|
|
|
324
|
+
if (branding.faviconUrl && branding.faviconUrl !== "") {
|
|
325
|
+
// @ts-ignore
|
|
326
|
+
config.faviconUrl = objectStore.getGlobalFileUrl(
|
|
327
|
+
"settings",
|
|
328
|
+
"faviconUrl",
|
|
329
|
+
branding.faviconUrl
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
|
|
288
333
|
// google
|
|
289
334
|
const googleConfig = await configs.getGoogleConfig()
|
|
335
|
+
const googleDatasourceConfigured =
|
|
336
|
+
!!(await configs.getGoogleDatasourceConfig())
|
|
290
337
|
const preActivated = googleConfig && googleConfig.activated == null
|
|
291
338
|
const google = preActivated || !!googleConfig?.activated
|
|
292
339
|
const _googleCallbackUrl = await googleCallbackUrl(googleConfig)
|
|
@@ -305,7 +352,9 @@ export async function publicSettings(
|
|
|
305
352
|
_rev: configDoc._rev,
|
|
306
353
|
config: {
|
|
307
354
|
...config,
|
|
355
|
+
...branding,
|
|
308
356
|
google,
|
|
357
|
+
googleDatasourceConfigured,
|
|
309
358
|
oidc,
|
|
310
359
|
isSSOEnforced,
|
|
311
360
|
oidcCallbackUrl: _oidcCallbackUrl,
|
|
@@ -2,7 +2,6 @@ import * as userSdk from "../../../sdk/users"
|
|
|
2
2
|
import {
|
|
3
3
|
featureFlags,
|
|
4
4
|
tenancy,
|
|
5
|
-
constants,
|
|
6
5
|
db as dbCore,
|
|
7
6
|
utils,
|
|
8
7
|
encryption,
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
import env from "../../../environment"
|
|
12
11
|
import { groups } from "@budibase/pro"
|
|
13
12
|
import { UpdateSelfRequest, UpdateSelfResponse, UserCtx } from "@budibase/types"
|
|
14
|
-
const {
|
|
13
|
+
const { newid } = utils
|
|
15
14
|
|
|
16
15
|
function newTestApiKey() {
|
|
17
16
|
return env.ENCRYPTED_TEST_PUBLIC_API_KEY
|
|
@@ -71,16 +70,6 @@ export async function fetchAPIKey(ctx: any) {
|
|
|
71
70
|
ctx.body = cleanupDevInfo(devInfo)
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
const checkCurrentApp = (ctx: any) => {
|
|
75
|
-
const appCookie = getCookie(ctx, constants.Cookie.CurrentApp)
|
|
76
|
-
if (appCookie && !tenancy.isUserInAppTenant(appCookie.appId)) {
|
|
77
|
-
// there is a currentapp cookie from another tenant
|
|
78
|
-
// remove the cookie as this is incompatible with the builder
|
|
79
|
-
// due to builder and admin permissions being removed
|
|
80
|
-
clearCookie(ctx, constants.Cookie.CurrentApp)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
73
|
/**
|
|
85
74
|
* Add the attributes that are session based to the current user.
|
|
86
75
|
*/
|
|
@@ -101,8 +90,6 @@ export async function getSelf(ctx: any) {
|
|
|
101
90
|
id: userId,
|
|
102
91
|
}
|
|
103
92
|
|
|
104
|
-
checkCurrentApp(ctx)
|
|
105
|
-
|
|
106
93
|
// get the main body of the user
|
|
107
94
|
const user = await userSdk.getUser(userId)
|
|
108
95
|
ctx.body = await groups.enrichUserRolesFromGroups(user)
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
getInviteCodes,
|
|
4
4
|
updateInviteCode,
|
|
5
5
|
} from "../../../utilities/redis"
|
|
6
|
-
// import sdk from "../../../sdk"
|
|
7
6
|
import * as userSdk from "../../../sdk/users"
|
|
8
7
|
import env from "../../../environment"
|
|
9
8
|
import {
|
|
@@ -26,11 +25,11 @@ import {
|
|
|
26
25
|
import {
|
|
27
26
|
accounts,
|
|
28
27
|
cache,
|
|
29
|
-
errors,
|
|
30
28
|
events,
|
|
31
29
|
migrations,
|
|
32
30
|
tenancy,
|
|
33
31
|
platform,
|
|
32
|
+
ErrorCode,
|
|
34
33
|
} from "@budibase/backend-core"
|
|
35
34
|
import { checkAnyUserExists } from "../../../utilities/users"
|
|
36
35
|
import { isEmailConfigured } from "../../../utilities/email"
|
|
@@ -421,7 +420,7 @@ export const inviteAccept = async (
|
|
|
421
420
|
email: user.email,
|
|
422
421
|
}
|
|
423
422
|
} catch (err: any) {
|
|
424
|
-
if (err.code ===
|
|
423
|
+
if (err.code === ErrorCode.USAGE_LIMIT_EXCEEDED) {
|
|
425
424
|
// explicitly re-throw limit exceeded errors
|
|
426
425
|
ctx.throw(400, err)
|
|
427
426
|
}
|
|
@@ -7,6 +7,7 @@ export const fetch = async (ctx: BBContext) => {
|
|
|
7
7
|
cloud: !env.SELF_HOSTED,
|
|
8
8
|
accountPortalUrl: env.ACCOUNT_PORTAL_URL,
|
|
9
9
|
disableAccountPortal: env.DISABLE_ACCOUNT_PORTAL,
|
|
10
|
+
baseUrl: env.PLATFORM_URL,
|
|
10
11
|
// in test need to pretend its in production for the UI (Cypress)
|
|
11
12
|
isDev: env.isDev() && !env.isTest(),
|
|
12
13
|
}
|
|
@@ -286,14 +286,17 @@ describe("configs", () => {
|
|
|
286
286
|
type: "settings",
|
|
287
287
|
config: {
|
|
288
288
|
company: "Budibase",
|
|
289
|
+
emailBrandingEnabled: true,
|
|
289
290
|
logoUrl: "",
|
|
290
291
|
analyticsEnabled: false,
|
|
291
292
|
google: false,
|
|
293
|
+
googleDatasourceConfigured: false,
|
|
292
294
|
googleCallbackUrl: `http://localhost:10000/api/global/auth/${config.tenantId}/google/callback`,
|
|
293
295
|
isSSOEnforced: false,
|
|
294
296
|
oidc: false,
|
|
295
297
|
oidcCallbackUrl: `http://localhost:10000/api/global/auth/${config.tenantId}/oidc/callback`,
|
|
296
298
|
platformUrl: "http://localhost:10000",
|
|
299
|
+
testimonialsEnabled: true,
|
|
297
300
|
},
|
|
298
301
|
}
|
|
299
302
|
delete body._rev
|
package/src/constants/index.ts
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{{#if enableEmailBranding}}
|
|
2
|
+
<tr>
|
|
3
|
+
<td cellpadding="0" cellspacing="0">
|
|
4
|
+
<table
|
|
5
|
+
align="center"
|
|
6
|
+
width="570"
|
|
7
|
+
cellpadding="0"
|
|
8
|
+
cellspacing="0"
|
|
9
|
+
role="presentation"
|
|
10
|
+
>
|
|
11
|
+
<tbody>
|
|
12
|
+
<tr>
|
|
13
|
+
<td
|
|
14
|
+
style="padding:0 35px; padding-top: 15px;"
|
|
15
|
+
cellpadding="0"
|
|
16
|
+
cellspacing="0"
|
|
17
|
+
>
|
|
18
|
+
<img
|
|
19
|
+
width="32px"
|
|
20
|
+
style="margin-right:16px; vertical-align: middle;"
|
|
21
|
+
alt="Budibase Logo"
|
|
22
|
+
src="https://i.imgur.com/Xhdt1YP.png"
|
|
23
|
+
/>
|
|
24
|
+
<strong style="vertical-align: middle; font-size: 1.1em">
|
|
25
|
+
Budibase
|
|
26
|
+
</strong>
|
|
27
|
+
</td>
|
|
28
|
+
</tr>
|
|
29
|
+
</tbody>
|
|
30
|
+
</table>
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
{{/if}}
|
|
@@ -21,6 +21,7 @@ export const EmailTemplates = {
|
|
|
21
21
|
join(__dirname, "welcome.hbs")
|
|
22
22
|
),
|
|
23
23
|
[EmailTemplatePurpose.CUSTOM]: readStaticFile(join(__dirname, "custom.hbs")),
|
|
24
|
+
[EmailTemplatePurpose.CORE]: readStaticFile(join(__dirname, "core.hbs")),
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export function addBaseTemplates(templates: Template[], type?: string) {
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
middleware,
|
|
22
22
|
queue,
|
|
23
23
|
env as coreEnv,
|
|
24
|
+
timers,
|
|
24
25
|
} from "@budibase/backend-core"
|
|
25
26
|
db.init()
|
|
26
27
|
import Koa from "koa"
|
|
@@ -91,6 +92,7 @@ server.on("close", async () => {
|
|
|
91
92
|
}
|
|
92
93
|
shuttingDown = true
|
|
93
94
|
console.log("Server Closed")
|
|
95
|
+
timers.cleanup()
|
|
94
96
|
await redis.shutdown()
|
|
95
97
|
await events.shutdown()
|
|
96
98
|
await queue.shutdown()
|
|
@@ -74,3 +74,10 @@ async function removeTenantUsers(tenantId: string) {
|
|
|
74
74
|
throw err
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
export async function tenantInfo(tenantId: string) {
|
|
79
|
+
const globalDbName = tenancy.getGlobalDBName(tenantId)
|
|
80
|
+
return {
|
|
81
|
+
exists: await dbCore.dbExists(globalDbName),
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/tests/api/tenants.ts
CHANGED
|
@@ -2,8 +2,10 @@ import TestConfiguration from "../TestConfiguration"
|
|
|
2
2
|
import { TestAPI, TestAPIOpts } from "./base"
|
|
3
3
|
|
|
4
4
|
export class TenantAPI extends TestAPI {
|
|
5
|
+
config: TestConfiguration
|
|
5
6
|
constructor(config: TestConfiguration) {
|
|
6
7
|
super(config)
|
|
8
|
+
this.config = config
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
delete = (tenantId: string, opts?: TestAPIOpts) => {
|
package/src/tests/jestSetup.ts
CHANGED
|
@@ -2,7 +2,7 @@ import "./logging"
|
|
|
2
2
|
|
|
3
3
|
import { mocks, testContainerUtils } from "@budibase/backend-core/tests"
|
|
4
4
|
import env from "../environment"
|
|
5
|
-
import { env as coreEnv } from "@budibase/backend-core"
|
|
5
|
+
import { env as coreEnv, timers } from "@budibase/backend-core"
|
|
6
6
|
|
|
7
7
|
// must explicitly enable fetch mock
|
|
8
8
|
mocks.fetch.enable()
|
|
@@ -21,3 +21,7 @@ if (!process.env.CI) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
testContainerUtils.setupEnv(env, coreEnv)
|
|
24
|
+
|
|
25
|
+
afterAll(() => {
|
|
26
|
+
timers.cleanup()
|
|
27
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as pro from "@budibase/pro"
|
|
2
|
+
|
|
3
|
+
export async function getLicensedConfig() {
|
|
4
|
+
let licensedConfig: object = {}
|
|
5
|
+
const defaults = {
|
|
6
|
+
emailBrandingEnabled: true,
|
|
7
|
+
testimonialsEnabled: true,
|
|
8
|
+
platformTitle: undefined,
|
|
9
|
+
metaDescription: undefined,
|
|
10
|
+
loginHeading: undefined,
|
|
11
|
+
loginButton: undefined,
|
|
12
|
+
metaImageUrl: undefined,
|
|
13
|
+
metaTitle: undefined,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// License/Feature Checks
|
|
18
|
+
const enabled = await pro.features.isBrandingEnabled()
|
|
19
|
+
if (!enabled) {
|
|
20
|
+
licensedConfig = { ...defaults }
|
|
21
|
+
}
|
|
22
|
+
} catch (e) {
|
|
23
|
+
licensedConfig = { ...defaults }
|
|
24
|
+
console.info("Could not retrieve license", e)
|
|
25
|
+
}
|
|
26
|
+
return licensedConfig
|
|
27
|
+
}
|
package/src/utilities/email.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import env from "../environment"
|
|
2
2
|
import { EmailTemplatePurpose, TemplateType } from "../constants"
|
|
3
|
-
import { getTemplateByPurpose } from "../constants/templates"
|
|
3
|
+
import { getTemplateByPurpose, EmailTemplates } from "../constants/templates"
|
|
4
4
|
import { getSettingsTemplateContext } from "./templates"
|
|
5
5
|
import { processString } from "@budibase/string-templates"
|
|
6
6
|
import { getResetPasswordCode, getInviteCode } from "./redis"
|
|
@@ -109,11 +109,16 @@ async function buildEmail(
|
|
|
109
109
|
getTemplateByPurpose(TYPE, EmailTemplatePurpose.BASE),
|
|
110
110
|
getTemplateByPurpose(TYPE, purpose),
|
|
111
111
|
])
|
|
112
|
-
|
|
112
|
+
|
|
113
|
+
// Change from branding to core
|
|
114
|
+
let core = EmailTemplates[EmailTemplatePurpose.CORE]
|
|
115
|
+
|
|
116
|
+
if (!base || !body || !core) {
|
|
113
117
|
throw "Unable to build email, missing base components"
|
|
114
118
|
}
|
|
115
119
|
base = base.contents
|
|
116
120
|
body = body.contents
|
|
121
|
+
|
|
117
122
|
let name = user ? user.name : undefined
|
|
118
123
|
if (user && !name && user.firstName) {
|
|
119
124
|
name = user.lastName ? `${user.firstName} ${user.lastName}` : user.firstName
|
|
@@ -126,8 +131,12 @@ async function buildEmail(
|
|
|
126
131
|
user: user || {},
|
|
127
132
|
}
|
|
128
133
|
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
// Prepend the core template
|
|
135
|
+
const fullBody = core + body
|
|
136
|
+
|
|
137
|
+
body = await processString(fullBody, context)
|
|
138
|
+
|
|
139
|
+
// this should now be the core email HTML
|
|
131
140
|
return processString(base, {
|
|
132
141
|
...context,
|
|
133
142
|
body,
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { tenancy, configs } from "@budibase/backend-core"
|
|
2
|
+
import { SettingsInnerConfig } from "@budibase/types"
|
|
2
3
|
import {
|
|
3
4
|
InternalTemplateBinding,
|
|
4
5
|
LOGO_URL,
|
|
5
6
|
EmailTemplatePurpose,
|
|
6
7
|
} from "../constants"
|
|
7
8
|
import { checkSlashesInUrl } from "./index"
|
|
9
|
+
import { getLicensedConfig } from "./configs"
|
|
10
|
+
|
|
8
11
|
const BASE_COMPANY = "Budibase"
|
|
12
|
+
import * as pro from "@budibase/pro"
|
|
9
13
|
|
|
10
14
|
export async function getSettingsTemplateContext(
|
|
11
15
|
purpose: EmailTemplatePurpose,
|
|
12
16
|
code?: string | null
|
|
13
17
|
) {
|
|
14
|
-
|
|
18
|
+
const settings = await configs.getSettingsConfig()
|
|
19
|
+
const branding = await pro.branding.getBrandingConfig(settings)
|
|
15
20
|
const URL = settings.platformUrl
|
|
16
21
|
const context: any = {
|
|
17
22
|
[InternalTemplateBinding.LOGO_URL]:
|
|
@@ -25,6 +30,9 @@ export async function getSettingsTemplateContext(
|
|
|
25
30
|
[InternalTemplateBinding.CURRENT_DATE]: new Date().toISOString(),
|
|
26
31
|
[InternalTemplateBinding.CURRENT_YEAR]: new Date().getFullYear(),
|
|
27
32
|
}
|
|
33
|
+
|
|
34
|
+
context["enableEmailBranding"] = branding.emailBrandingEnabled === true
|
|
35
|
+
|
|
28
36
|
// attach purpose specific context
|
|
29
37
|
switch (purpose) {
|
|
30
38
|
case EmailTemplatePurpose.PASSWORD_RECOVERY:
|