@budibase/worker 3.23.27 → 3.23.29

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/worker",
3
3
  "email": "hi@budibase.com",
4
- "version": "3.23.27",
4
+ "version": "3.23.29",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -109,5 +109,5 @@
109
109
  }
110
110
  }
111
111
  },
112
- "gitHead": "78f31912a1a5454f0188e9e1df2022e236fb054e"
112
+ "gitHead": "e9bb53161a551bda13ab996da6cba563f6be5400"
113
113
  }
@@ -1,4 +1,8 @@
1
- import { GetTenantInfoResponse, UserCtx } from "@budibase/types"
1
+ import {
2
+ ActivationRequest,
3
+ GetTenantInfoResponse,
4
+ UserCtx,
5
+ } from "@budibase/types"
2
6
  import { LockRequest, LockReason } from "@budibase/types"
3
7
  import * as tenantSdk from "../../../sdk/tenants"
4
8
 
@@ -47,6 +51,27 @@ export async function lock(ctx: UserCtx<LockRequest, void>) {
47
51
  }
48
52
  }
49
53
 
54
+ export async function activation(ctx: UserCtx<ActivationRequest, void>) {
55
+ if (!ctx.internal) {
56
+ ctx.throw(403, "Only internal user can set activation for a tenant")
57
+ }
58
+
59
+ const { active } = ctx.request.body
60
+ if (typeof active !== "boolean") {
61
+ ctx.throw(403, "Only boolean values allowed for 'active' property")
62
+ }
63
+
64
+ const tenantId = ctx.params.tenantId
65
+
66
+ try {
67
+ await tenantSdk.setActivation(tenantId, active)
68
+ ctx.status = 204
69
+ } catch (err) {
70
+ ctx.log.error(err)
71
+ throw err
72
+ }
73
+ }
74
+
50
75
  export async function info(ctx: UserCtx<void, GetTenantInfoResponse>) {
51
76
  ctx.body = await tenantSdk.tenantInfo(ctx.params.tenantId)
52
77
  }
@@ -3,3 +3,7 @@ import { adminRoutes } from "../endpointGroups"
3
3
 
4
4
  adminRoutes.delete("/api/system/tenants/:tenantId", controller.destroy)
5
5
  adminRoutes.put("/api/system/tenants/:tenantId/lock", controller.lock)
6
+ adminRoutes.put(
7
+ "/api/system/tenants/:tenantId/activation",
8
+ controller.activation
9
+ )
@@ -7,6 +7,7 @@ jest.mock("../../../../sdk/tenants", () => ({
7
7
  lockTenant: jest.fn(),
8
8
  unlockTenant: jest.fn(),
9
9
  deleteTenant: jest.fn(),
10
+ setActivation: jest.fn(),
10
11
  }))
11
12
 
12
13
  describe("/api/global/tenants", () => {
@@ -147,4 +148,82 @@ describe("/api/global/tenants", () => {
147
148
  expect(tenantSdk.unlockTenant).not.toHaveBeenCalled()
148
149
  })
149
150
  })
151
+
152
+ describe("PUT /api/system/tenants/:tenantId/activation", () => {
153
+ it("allows activating tenant", async () => {
154
+ const user = await config.createTenant()
155
+
156
+ await config.api.tenants.activation(
157
+ user.tenantId,
158
+ {
159
+ active: true,
160
+ },
161
+ {
162
+ headers: config.internalAPIHeaders(),
163
+ }
164
+ )
165
+
166
+ expect(tenantSdk.setActivation).toHaveBeenCalledWith(user.tenantId, true)
167
+ })
168
+
169
+ it("allows deactivating tenant", async () => {
170
+ const user = await config.createTenant()
171
+
172
+ await config.api.tenants.activation(
173
+ user.tenantId,
174
+ {
175
+ active: false,
176
+ },
177
+ {
178
+ headers: config.internalAPIHeaders(),
179
+ }
180
+ )
181
+
182
+ expect(tenantSdk.setActivation).toHaveBeenCalledWith(user.tenantId, false)
183
+ })
184
+
185
+ it("rejects non-boolean active value", async () => {
186
+ const user = await config.createTenant()
187
+
188
+ const status = 403
189
+ const res = await config.api.tenants.activation(
190
+ user.tenantId,
191
+ {
192
+ active: "invalid" as any,
193
+ },
194
+ {
195
+ status,
196
+ headers: config.internalAPIHeaders(),
197
+ }
198
+ )
199
+
200
+ expect(res.body).toEqual({
201
+ message: "Only boolean values allowed for 'active' property",
202
+ status,
203
+ })
204
+ expect(tenantSdk.setActivation).not.toHaveBeenCalled()
205
+ })
206
+
207
+ it("rejects non-internal user", async () => {
208
+ const user = await config.createTenant()
209
+
210
+ const status = 403
211
+ const res = await config.api.tenants.activation(
212
+ user.tenantId,
213
+ {
214
+ active: true,
215
+ },
216
+ {
217
+ status,
218
+ headers: config.authHeaders(user),
219
+ }
220
+ )
221
+
222
+ expect(res.body).toEqual({
223
+ message: "Only internal user can set activation for a tenant",
224
+ status,
225
+ })
226
+ expect(tenantSdk.setActivation).not.toHaveBeenCalled()
227
+ })
228
+ })
150
229
  })
@@ -22,6 +22,20 @@ export async function unlockTenant(tenantId: string) {
22
22
  return await setLock(tenantId)
23
23
  }
24
24
 
25
+ export async function setActivation(tenantId: string, active: boolean) {
26
+ const db = tenancy.getTenantDB(tenantId)
27
+ const settingsConfig = await db.tryGet<SettingsConfig>(
28
+ configs.generateConfigID(ConfigType.SETTINGS)
29
+ )
30
+ if (!settingsConfig?.config) {
31
+ throw new Error(
32
+ `Cannot set activation. Settings config not found for tenant ${tenantId}`
33
+ )
34
+ }
35
+ settingsConfig.config.active = active
36
+ await db.put(settingsConfig)
37
+ }
38
+
25
39
  async function setLock(tenantId: string, lockReason?: LockReason) {
26
40
  const db = tenancy.getTenantDB(tenantId)
27
41
  const settingsConfig = await db.tryGet<SettingsConfig>(
@@ -1,5 +1,5 @@
1
1
  import { structures } from "../../../tests"
2
- import { lockTenant, unlockTenant } from "../tenants"
2
+ import { lockTenant, unlockTenant, setActivation } from "../tenants"
3
3
  import { configs, tenancy } from "@budibase/backend-core"
4
4
  import { LockReason, ConfigType, SettingsConfig } from "@budibase/types"
5
5
 
@@ -159,4 +159,83 @@ describe("tenants", () => {
159
159
  )
160
160
  })
161
161
  })
162
+
163
+ describe("setActivation", () => {
164
+ it("should activate tenant", async () => {
165
+ const tenantId = structures.tenant.id()
166
+
167
+ const settingsConfig: SettingsConfig = {
168
+ _id: "config_settings",
169
+ type: ConfigType.SETTINGS,
170
+ config: {},
171
+ }
172
+
173
+ mockDb.tryGet.mockResolvedValue(settingsConfig)
174
+
175
+ await setActivation(tenantId, true)
176
+
177
+ expect(mockDb.tryGet).toHaveBeenCalledWith(
178
+ configs.generateConfigID(ConfigType.SETTINGS)
179
+ )
180
+ expect(mockDb.put).toHaveBeenCalledWith({
181
+ ...settingsConfig,
182
+ config: {
183
+ ...settingsConfig.config,
184
+ active: true,
185
+ },
186
+ })
187
+ })
188
+
189
+ it("should deactivate tenant", async () => {
190
+ const tenantId = structures.tenant.id()
191
+
192
+ const settingsConfig: SettingsConfig = {
193
+ _id: "config_settings",
194
+ type: ConfigType.SETTINGS,
195
+ config: {
196
+ active: true,
197
+ },
198
+ }
199
+
200
+ mockDb.tryGet.mockResolvedValue(settingsConfig)
201
+
202
+ await setActivation(tenantId, false)
203
+
204
+ expect(mockDb.tryGet).toHaveBeenCalledWith(
205
+ configs.generateConfigID(ConfigType.SETTINGS)
206
+ )
207
+ expect(mockDb.put).toHaveBeenCalledWith({
208
+ ...settingsConfig,
209
+ config: {
210
+ ...settingsConfig.config,
211
+ active: false,
212
+ },
213
+ })
214
+ })
215
+
216
+ it("should throw error when settings config not found", async () => {
217
+ const tenantId = structures.tenant.id()
218
+
219
+ mockDb.tryGet.mockResolvedValue(null)
220
+
221
+ await expect(setActivation(tenantId, true)).rejects.toThrow(
222
+ `Cannot set activation. Settings config not found for tenant ${tenantId}`
223
+ )
224
+ })
225
+
226
+ it("should throw error when settings config has no config property", async () => {
227
+ const tenantId = structures.tenant.id()
228
+
229
+ const settingsConfig = {
230
+ _id: "config_settings",
231
+ type: ConfigType.SETTINGS,
232
+ }
233
+
234
+ mockDb.tryGet.mockResolvedValue(settingsConfig)
235
+
236
+ await expect(setActivation(tenantId, true)).rejects.toThrow(
237
+ `Cannot set activation. Settings config not found for tenant ${tenantId}`
238
+ )
239
+ })
240
+ })
162
241
  })
@@ -1,6 +1,6 @@
1
1
  import TestConfiguration from "../TestConfiguration"
2
2
  import { TestAPI, TestAPIOpts } from "./base"
3
- import { LockRequest } from "@budibase/types"
3
+ import { LockRequest, ActivationRequest } from "@budibase/types"
4
4
 
5
5
  export class TenantAPI extends TestAPI {
6
6
  config: TestConfiguration
@@ -23,4 +23,16 @@ export class TenantAPI extends TestAPI {
23
23
  .set(opts?.headers)
24
24
  .expect(opts?.status ? opts.status : 204)
25
25
  }
26
+
27
+ activation = (
28
+ tenantId: string,
29
+ body: ActivationRequest,
30
+ opts?: TestAPIOpts
31
+ ) => {
32
+ return this.request
33
+ .put(`/api/system/tenants/${tenantId}/activation`)
34
+ .send(body)
35
+ .set(opts?.headers)
36
+ .expect(opts?.status ? opts.status : 204)
37
+ }
26
38
  }