From 7ac24492016328e3c42e87484947e6f60eb24216 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 10:08:42 +0000 Subject: [PATCH 01/10] Working on typing TestConfiguration.ts. --- .../src/api/routes/tests/application.spec.ts | 6 + packages/server/src/app.ts | 2 +- .../src/tests/utilities/TestConfiguration.ts | 224 ++++++++---------- 3 files changed, 107 insertions(+), 125 deletions(-) diff --git a/packages/server/src/api/routes/tests/application.spec.ts b/packages/server/src/api/routes/tests/application.spec.ts index dbe4eb51ae..78f021ac5d 100644 --- a/packages/server/src/api/routes/tests/application.spec.ts +++ b/packages/server/src/api/routes/tests/application.spec.ts @@ -248,4 +248,10 @@ describe("/applications", () => { expect(devLogs.data.length).toBe(0) }) }) + + describe("permissions", () => { + it("should return the list of apps the user has access to", async () => { + const user = config.user + }) + }) }) diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 4e84422dec..aa96a30b00 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -29,6 +29,6 @@ start().catch(err => { throw err }) -export function getServer() { +export function getServer(): Server { return server } diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 22bb66b130..5333f1ebf2 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -49,6 +49,7 @@ import { AuthToken, Automation, CreateViewRequest, + Ctx, Datasource, FieldType, INTERNAL_TABLE_SOURCE_ID, @@ -68,6 +69,8 @@ import { import API from "./api" import { cloneDeep } from "lodash" import jwt, { Secret } from "jsonwebtoken" +import { Server } from "http" +import { userDetailListType } from "aws-sdk/clients/iam" mocks.licenses.init(pro) @@ -82,16 +85,16 @@ export interface TableToBuild extends Omit { } export default class TestConfiguration { - server: any - request: supertest.SuperTest | undefined + server?: Server + request?: supertest.SuperTest started: boolean - appId: string | null + appId?: string allApps: any[] app?: App - prodApp: any - prodAppId: any - user: any - userMetadataId: any + prodApp?: App + prodAppId?: string + user?: User + userMetadataId?: string table?: Table automation: any datasource?: Datasource @@ -99,10 +102,6 @@ export default class TestConfiguration { api: API csrfToken?: string - private get globalUserId() { - return this.user._id - } - constructor(openServer = true) { if (openServer) { // use a random port because it doesn't matter @@ -114,7 +113,7 @@ export default class TestConfiguration { } else { this.started = false } - this.appId = null + this.appId = undefined this.allApps = [] this.api = new API(this) @@ -134,37 +133,49 @@ export default class TestConfiguration { getAppId() { if (!this.appId) { - throw "appId has not been initialised properly" + throw new Error("appId has not been initialised properly") } - return this.appId } getProdAppId() { + if (!this.prodAppId) { + throw new Error( + "prodAppId has not been initialised, call config.init() first" + ) + } return this.prodAppId } + getUser(): User { + if (!this.user) { + throw new Error("User has not been initialised, call config.init() first") + } + return this.user + } + getUserDetails() { + const user = this.getUser() return { - globalId: this.globalUserId, - email: this.user.email, - firstName: this.user.firstName, - lastName: this.user.lastName, + globalId: user._id!, + email: user.email, + firstName: user.firstName, + lastName: user.lastName, } } async doInContext( - appId: string | null, + appId: string | undefined, task: () => Promise ): Promise { - if (!appId) { - appId = this.appId - } - const tenant = this.getTenantId() return tenancy.doInTenant(tenant, () => { + if (!appId) { + appId = this.appId + } + // check if already in a context - if (context.getAppId() == null && appId !== null) { + if (context.getAppId() == null && appId) { return context.doInAppContext(appId, async () => { return task() }) @@ -259,7 +270,11 @@ export default class TestConfiguration { // UTILS - _req(body: any, params: any, controlFunc: any) { + _req, Res, Context extends Ctx>( + handler: (ctx: Context) => Promise, + body?: Req, + params?: Record + ) { // create a fake request ctx const request: any = {} const appId = this.appId @@ -278,29 +293,19 @@ export default class TestConfiguration { throw new Error(`Error ${status} - ${message}`) } return this.doInContext(appId, async () => { - await controlFunc(request) + await handler(request) return request.body }) } // USER / AUTH - async globalUser( - config: { - id?: string - firstName?: string - lastName?: string - builder?: boolean - admin?: boolean - email?: string - roles?: any - } = {} - ): Promise { + async globalUser(config: Partial = {}): Promise { const { - id = `us_${newid()}`, + _id = `us_${newid()}`, firstName = generator.first(), lastName = generator.last(), - builder = true, - admin = false, + builder = { global: true }, + admin = { global: false }, email = generator.email(), roles, } = config @@ -308,72 +313,30 @@ export default class TestConfiguration { const db = tenancy.getTenantDB(this.getTenantId()) let existing try { - existing = await db.get(id) + existing = await db.get(_id) } catch (err) { existing = { email } } const user: User = { - _id: id, + _id: _id, ...existing, roles: roles || {}, tenantId: this.getTenantId(), firstName, lastName, } - await sessions.createASession(id, { + await sessions.createASession(_id, { sessionId: "sessionid", tenantId: this.getTenantId(), csrfToken: this.csrfToken, }) - if (builder) { - user.builder = { global: true } - } else { - user.builder = { global: false } - } - if (admin) { - user.admin = { global: true } - } else { - user.admin = { global: false } - } const resp = await db.put(user) - return { - _rev: resp.rev, - ...user, - } + return { _rev: resp.rev, ...user } } - async createUser( - user: { - id?: string - firstName?: string - lastName?: string - email?: string - builder?: boolean - admin?: boolean - roles?: UserRoles - } = {} - ): Promise { - const { - id, - firstName = generator.first(), - lastName = generator.last(), - email = generator.email(), - builder = true, - admin, - roles, - } = user - - const globalId = !id ? `us_${Math.random()}` : `us_${id}` - const resp = await this.globalUser({ - id: globalId, - firstName, - lastName, - email, - builder, - admin, - roles: roles || {}, - }) - await cache.user.invalidateUser(globalId) + async createUser(user: Partial = {}): Promise { + const resp = await this.globalUser(user) + await cache.user.invalidateUser(resp._id!) return resp } @@ -381,7 +344,7 @@ export default class TestConfiguration { return context.doInTenant(this.tenantId!, async () => { const baseGroup = structures.userGroups.userGroup() baseGroup.roles = { - [this.prodAppId]: roleId, + [this.getProdAppId()]: roleId, } const { id, rev } = await pro.sdk.groups.save(baseGroup) return { @@ -404,8 +367,18 @@ export default class TestConfiguration { }) } - async login({ roleId, userId, builder, prodApp = false }: any = {}) { - const appId = prodApp ? this.prodAppId : this.appId + async login({ + roleId, + userId, + builder, + prodApp, + }: { + roleId: string + userId: string + builder: boolean + prodApp: boolean + }) { + const appId = prodApp ? this.getProdAppId() : this.getAppId() return context.doInAppContext(appId, async () => { userId = !userId ? `us_uuid1` : userId if (!this.request) { @@ -414,9 +387,9 @@ export default class TestConfiguration { // make sure the user exists in the global DB if (roleId !== roles.BUILTIN_ROLE_IDS.PUBLIC) { await this.globalUser({ - id: userId, - builder, - roles: { [this.prodAppId]: roleId }, + _id: userId, + builder: { global: builder }, + roles: { [appId]: roleId }, }) } await sessions.createASession(userId, { @@ -445,8 +418,9 @@ export default class TestConfiguration { defaultHeaders(extras = {}, prodApp = false) { const tenantId = this.getTenantId() + const user = this.getUser() const authObj: AuthToken = { - userId: this.globalUserId, + userId: user._id!, sessionId: "sessionid", tenantId, } @@ -498,7 +472,7 @@ export default class TestConfiguration { builder = false, prodApp = true, } = {}) { - return this.login({ email, roleId, builder, prodApp }) + return this.login({ userId: email, roleId, builder, prodApp }) } // TENANCY @@ -521,7 +495,7 @@ export default class TestConfiguration { this.tenantId = structures.tenant.id() this.user = await this.globalUser() - this.userMetadataId = generateUserMetadataID(this.user._id) + this.userMetadataId = generateUserMetadataID(this.user._id!) return this.createApp(appName) } @@ -532,7 +506,11 @@ export default class TestConfiguration { // API - async generateApiKey(userId = this.user._id) { + async generateApiKey(userId?: string) { + const user = this.getUser() + if (!userId) { + userId = user._id! + } const db = tenancy.getTenantDB(this.getTenantId()) const id = dbCore.generateDevInfoID(userId) let devInfo: any @@ -552,13 +530,15 @@ export default class TestConfiguration { async createApp(appName: string): Promise { // create dev app // clear any old app - this.appId = null + this.appId = undefined this.app = await context.doInTenant(this.tenantId!, async () => { - const app = await this._req({ name: appName }, null, appController.create) + const app = (await this._req(appController.create, { + name: appName, + })) as App this.appId = app.appId! return app }) - return await context.doInAppContext(this.getAppId(), async () => { + return await context.doInAppContext(this.app.appId!, async () => { // create production app this.prodApp = await this.publish() @@ -570,7 +550,7 @@ export default class TestConfiguration { } async publish() { - await this._req(null, null, deployController.publishApp) + await this._req(deployController.publishApp) // @ts-ignore const prodAppId = this.getAppId().replace("_dev", "") this.prodAppId = prodAppId @@ -582,13 +562,11 @@ export default class TestConfiguration { } async unpublish() { - const response = await this._req( - null, - { appId: this.appId }, - appController.unpublish - ) - this.prodAppId = null - this.prodApp = null + const response = await this._req(appController.unpublish, { + appId: this.appId, + }) + this.prodAppId = undefined + this.prodApp = undefined return response } @@ -716,8 +694,7 @@ export default class TestConfiguration { // ROLE async createRole(config?: any) { - config = config || basicRole() - return this._req(config, null, roleController.save) + return this._req(roleController.save, config || basicRole()) } // VIEW @@ -730,7 +707,7 @@ export default class TestConfiguration { tableId: this.table!._id, name: generator.guid(), } - return this._req(view, null, viewController.v1.save) + return this._req(viewController.v1.save, view) } async createView( @@ -760,13 +737,13 @@ export default class TestConfiguration { delete config._rev } this.automation = ( - await this._req(config, null, automationController.create) + await this._req(automationController.create, config) ).automation return this.automation } async getAllAutomations() { - return this._req(null, null, automationController.fetch) + return this._req(automationController.fetch) } async deleteAutomation(automation?: any) { @@ -774,11 +751,10 @@ export default class TestConfiguration { if (!automation) { return } - return this._req( - null, - { id: automation._id, rev: automation._rev }, - automationController.destroy - ) + return this._req(automationController.destroy, { + id: automation._id, + rev: automation._rev, + }) } async createWebhook(config?: any) { @@ -787,7 +763,7 @@ export default class TestConfiguration { } config = config || basicWebhook(this.automation._id) - return (await this._req(config, null, webhookController.save)).webhook + return (await this._req(webhookController.save, config)).webhook } // DATASOURCE @@ -871,21 +847,21 @@ export default class TestConfiguration { throw "No datasource created for query." } config = config || basicQuery(this.datasource!._id!) - return this._req(config, null, queryController.save) + return this._req(queryController.save, config) } // SCREEN async createScreen(config?: any) { config = config || basicScreen() - return this._req(config, null, screenController.save) + return this._req(screenController.save, config) } // LAYOUT async createLayout(config?: any) { config = config || basicLayout() - return await this._req(config, null, layoutController.save) + return await this._req(layoutController.save, config) } } From c81ca66aa4aa45b445cda8c7d66e26b31efe4d5a Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 11:16:26 +0000 Subject: [PATCH 02/10] Get tests passing again. --- .../server/src/api/routes/tests/user.spec.ts | 12 ++++--- .../server/src/migrations/tests/index.spec.ts | 14 ++++---- .../sdk/app/applications/tests/sync.spec.ts | 14 ++++---- .../server/src/sdk/users/tests/utils.spec.ts | 34 ++++++++++++++----- .../src/tests/utilities/TestConfiguration.ts | 24 ++++++++----- 5 files changed, 63 insertions(+), 35 deletions(-) diff --git a/packages/server/src/api/routes/tests/user.spec.ts b/packages/server/src/api/routes/tests/user.spec.ts index e6349099d7..076ee064dc 100644 --- a/packages/server/src/api/routes/tests/user.spec.ts +++ b/packages/server/src/api/routes/tests/user.spec.ts @@ -27,15 +27,17 @@ describe("/users", () => { describe("fetch", () => { it("returns a list of users from an instance db", async () => { - await config.createUser({ id: "uuidx" }) - await config.createUser({ id: "uuidy" }) + const id1 = `us_${utils.newid()}` + const id2 = `us_${utils.newid()}` + await config.createUser({ _id: id1 }) + await config.createUser({ _id: id2 }) const res = await config.api.user.fetch() expect(res.length).toBe(3) const ids = res.map(u => u._id) - expect(ids).toContain(`ro_ta_users_us_uuidx`) - expect(ids).toContain(`ro_ta_users_us_uuidy`) + expect(ids).toContain(`ro_ta_users_${id1}`) + expect(ids).toContain(`ro_ta_users_${id2}`) }) it("should apply authorization to endpoint", async () => { @@ -54,7 +56,7 @@ describe("/users", () => { describe("update", () => { it("should be able to update the user", async () => { const user: UserMetadata = await config.createUser({ - id: `us_update${utils.newid()}`, + _id: `us_update${utils.newid()}`, }) user.roleId = roles.BUILTIN_ROLE_IDS.BASIC delete user._rev diff --git a/packages/server/src/migrations/tests/index.spec.ts b/packages/server/src/migrations/tests/index.spec.ts index c01040593a..236776cd3f 100644 --- a/packages/server/src/migrations/tests/index.spec.ts +++ b/packages/server/src/migrations/tests/index.spec.ts @@ -40,7 +40,7 @@ describe("migrations", () => { describe("backfill", () => { it("runs app db migration", async () => { - await config.doInContext(null, async () => { + await config.doInContext(undefined, async () => { await clearMigrations() await config.createAutomation() await config.createAutomation(structures.newAutomation()) @@ -93,18 +93,18 @@ describe("migrations", () => { }) it("runs global db migration", async () => { - await config.doInContext(null, async () => { + await config.doInContext(undefined, async () => { await clearMigrations() - const appId = config.prodAppId + const appId = config.getProdAppId() const roles = { [appId]: "role_12345" } await config.createUser({ - builder: false, - admin: true, + builder: { global: false }, + admin: { global: true }, roles, }) // admin only await config.createUser({ - builder: false, - admin: false, + builder: { global: false }, + admin: { global: false }, roles, }) // non admin non builder await config.createTable() diff --git a/packages/server/src/sdk/app/applications/tests/sync.spec.ts b/packages/server/src/sdk/app/applications/tests/sync.spec.ts index 1d28ed977c..a53bdb0bd7 100644 --- a/packages/server/src/sdk/app/applications/tests/sync.spec.ts +++ b/packages/server/src/sdk/app/applications/tests/sync.spec.ts @@ -43,8 +43,8 @@ async function createUser(email: string, roles: UserRoles, builder?: boolean) { const user = await config.createUser({ email, roles, - builder: builder || false, - admin: false, + builder: { global: builder || false }, + admin: { global: false }, }) await context.doInContext(config.appId!, async () => { await events.user.created(user) @@ -55,10 +55,10 @@ async function createUser(email: string, roles: UserRoles, builder?: boolean) { async function removeUserRole(user: User) { const final = await config.globalUser({ ...user, - id: user._id, + _id: user._id, roles: {}, - builder: false, - admin: false, + builder: { global: false }, + admin: { global: false }, }) await context.doInContext(config.appId!, async () => { await events.user.updated(final) @@ -69,8 +69,8 @@ async function createGroupAndUser(email: string) { groupUser = await config.createUser({ email, roles: {}, - builder: false, - admin: false, + builder: { global: false }, + admin: { global: false }, }) group = await config.createGroup() await config.addUserToGroup(group._id!, groupUser._id!) diff --git a/packages/server/src/sdk/users/tests/utils.spec.ts b/packages/server/src/sdk/users/tests/utils.spec.ts index efe790d49b..6f1c5afd3d 100644 --- a/packages/server/src/sdk/users/tests/utils.spec.ts +++ b/packages/server/src/sdk/users/tests/utils.spec.ts @@ -22,15 +22,18 @@ describe("syncGlobalUsers", () => { expect(metadata).toHaveLength(1) expect(metadata).toEqual([ expect.objectContaining({ - _id: db.generateUserMetadataID(config.user._id), + _id: db.generateUserMetadataID(config.getUser()._id!), }), ]) }) }) it("admin and builders users are synced", async () => { - const user1 = await config.createUser({ admin: true }) - const user2 = await config.createUser({ admin: false, builder: true }) + const user1 = await config.createUser({ admin: { global: true } }) + const user2 = await config.createUser({ + admin: { global: false }, + builder: { global: true }, + }) await config.doInContext(config.appId, async () => { expect(await rawUserMetadata()).toHaveLength(1) await syncGlobalUsers() @@ -51,7 +54,10 @@ describe("syncGlobalUsers", () => { }) it("app users are not synced if not specified", async () => { - const user = await config.createUser({ admin: false, builder: false }) + const user = await config.createUser({ + admin: { global: false }, + builder: { global: false }, + }) await config.doInContext(config.appId, async () => { await syncGlobalUsers() @@ -68,8 +74,14 @@ describe("syncGlobalUsers", () => { it("app users are added when group is assigned to app", async () => { await config.doInTenant(async () => { const group = await proSdk.groups.save(structures.userGroups.userGroup()) - const user1 = await config.createUser({ admin: false, builder: false }) - const user2 = await config.createUser({ admin: false, builder: false }) + const user1 = await config.createUser({ + admin: { global: false }, + builder: { global: false }, + }) + const user2 = await config.createUser({ + admin: { global: false }, + builder: { global: false }, + }) await proSdk.groups.addUsers(group.id, [user1._id!, user2._id!]) await config.doInContext(config.appId, async () => { @@ -103,8 +115,14 @@ describe("syncGlobalUsers", () => { it("app users are removed when app is removed from user group", async () => { await config.doInTenant(async () => { const group = await proSdk.groups.save(structures.userGroups.userGroup()) - const user1 = await config.createUser({ admin: false, builder: false }) - const user2 = await config.createUser({ admin: false, builder: false }) + const user1 = await config.createUser({ + admin: { global: false }, + builder: { global: false }, + }) + const user2 = await config.createUser({ + admin: { global: false }, + builder: { global: false }, + }) await proSdk.groups.updateGroupApps(group.id, { appsToAdd: [ { appId: config.prodAppId!, roleId: roles.BUILTIN_ROLE_IDS.BASIC }, diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 5333f1ebf2..f6f0992585 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -307,23 +307,28 @@ export default class TestConfiguration { builder = { global: true }, admin = { global: false }, email = generator.email(), - roles, + tenantId = this.getTenantId(), + roles = {}, } = config const db = tenancy.getTenantDB(this.getTenantId()) - let existing + let existing: Partial = {} try { existing = await db.get(_id) } catch (err) { - existing = { email } + // ignore } const user: User = { - _id: _id, + _id, ...existing, - roles: roles || {}, - tenantId: this.getTenantId(), + ...config, + email, + roles, + tenantId, firstName, lastName, + builder, + admin, } await sessions.createASession(_id, { sessionId: "sessionid", @@ -331,7 +336,10 @@ export default class TestConfiguration { csrfToken: this.csrfToken, }) const resp = await db.put(user) - return { _rev: resp.rev, ...user } + return { + _rev: resp.rev, + ...user, + } } async createUser(user: Partial = {}): Promise { @@ -751,7 +759,7 @@ export default class TestConfiguration { if (!automation) { return } - return this._req(automationController.destroy, { + return this._req(automationController.destroy, undefined, { id: automation._id, rev: automation._rev, }) From fde5825589f49a8e025499de997c2734990aebdf Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 11:20:42 +0000 Subject: [PATCH 03/10] Fix type checks. --- packages/server/src/api/routes/tests/row.spec.ts | 2 +- .../functions/usageQuotas/tests/syncApps.spec.ts | 2 +- .../functions/usageQuotas/tests/syncCreators.spec.ts | 4 ++-- .../functions/usageQuotas/tests/syncRows.spec.ts | 2 +- .../functions/usageQuotas/tests/syncUsers.spec.ts | 2 +- .../server/src/sdk/app/rows/tests/internal.spec.ts | 10 +++++----- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 239da36351..726e493b2d 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -110,7 +110,7 @@ describe.each([ config.api.row.get(tbl_Id, id, { expectStatus: status }) const getRowUsage = async () => { - const { total } = await config.doInContext(null, () => + const { total } = await config.doInContext(undefined, () => quotas.getCurrentUsageValues(QuotaUsageType.STATIC, StaticQuotaName.ROWS) ) return total diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts index d0d50395b2..1d4d4d0f71 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts @@ -13,7 +13,7 @@ describe("syncApps", () => { afterAll(config.end) it("runs successfully", async () => { - return config.doInContext(null, async () => { + return config.doInContext(undefined, async () => { // create the usage quota doc and mock usages await quotas.getQuotaUsage() await quotas.setUsage(3, StaticQuotaName.APPS, QuotaUsageType.STATIC) diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncCreators.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncCreators.spec.ts index 75fa9f217e..93b7d4949b 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncCreators.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncCreators.spec.ts @@ -12,8 +12,8 @@ describe("syncCreators", () => { afterAll(config.end) it("syncs creators", async () => { - return config.doInContext(null, async () => { - await config.createUser({ admin: true }) + return config.doInContext(undefined, async () => { + await config.createUser({ admin: { global: true } }) await syncCreators.run() diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts index e644d605b6..730278683c 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts @@ -14,7 +14,7 @@ describe("syncRows", () => { afterAll(config.end) it("runs successfully", async () => { - return config.doInContext(null, async () => { + return config.doInContext(undefined, async () => { // create the usage quota doc and mock usages await quotas.getQuotaUsage() await quotas.setUsage(300, StaticQuotaName.ROWS, QuotaUsageType.STATIC) diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts index f7500c8b4d..2731cc041d 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts @@ -12,7 +12,7 @@ describe("syncUsers", () => { afterAll(config.end) it("syncs users", async () => { - return config.doInContext(null, async () => { + return config.doInContext(undefined, async () => { await config.createUser() await syncUsers.run() diff --git a/packages/server/src/sdk/app/rows/tests/internal.spec.ts b/packages/server/src/sdk/app/rows/tests/internal.spec.ts index dda41d5720..3908ef83ed 100644 --- a/packages/server/src/sdk/app/rows/tests/internal.spec.ts +++ b/packages/server/src/sdk/app/rows/tests/internal.spec.ts @@ -81,7 +81,7 @@ describe("sdk >> rows >> internal", () => { const response = await internalSdk.save( table._id!, row, - config.user._id + config.getUser()._id ) expect(response).toEqual({ @@ -129,7 +129,7 @@ describe("sdk >> rows >> internal", () => { const response = await internalSdk.save( table._id!, row, - config.user._id + config.getUser()._id ) expect(response).toEqual({ @@ -190,15 +190,15 @@ describe("sdk >> rows >> internal", () => { await config.doInContext(config.appId, async () => { for (const row of makeRows(5)) { - await internalSdk.save(table._id!, row, config.user._id) + await internalSdk.save(table._id!, row, config.getUser()._id) } await Promise.all( makeRows(10).map(row => - internalSdk.save(table._id!, row, config.user._id) + internalSdk.save(table._id!, row, config.getUser()._id) ) ) for (const row of makeRows(5)) { - await internalSdk.save(table._id!, row, config.user._id) + await internalSdk.save(table._id!, row, config.getUser()._id) } }) From bfb0064289a24561db92d46a73f9702997ebe27e Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 11:46:58 +0000 Subject: [PATCH 04/10] More types. --- .../server/src/api/controllers/automation.ts | 4 +- .../src/api/routes/tests/automation.spec.ts | 4 +- .../src/api/routes/tests/backup.spec.ts | 2 +- .../src/api/routes/tests/webhook.spec.ts | 4 +- .../src/tests/utilities/TestConfiguration.ts | 60 ++++++++++++------- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index 186b68f3b7..b7c29efa6f 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -72,7 +72,9 @@ function cleanAutomationInputs(automation: Automation) { return automation } -export async function create(ctx: UserCtx) { +export async function create( + ctx: UserCtx +) { const db = context.getAppDB() let automation = ctx.request.body automation.appId = ctx.appId diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index 178189555d..ee8fc7d544 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -394,7 +394,7 @@ describe("/automations", () => { it("deletes a automation by its ID", async () => { const automation = await config.createAutomation() const res = await request - .delete(`/api/automations/${automation.id}/${automation.rev}`) + .delete(`/api/automations/${automation._id}/${automation._rev}`) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) @@ -408,7 +408,7 @@ describe("/automations", () => { await checkBuilderEndpoint({ config, method: "DELETE", - url: `/api/automations/${automation.id}/${automation._rev}`, + url: `/api/automations/${automation._id}/${automation._rev}`, }) }) }) diff --git a/packages/server/src/api/routes/tests/backup.spec.ts b/packages/server/src/api/routes/tests/backup.spec.ts index acfac783db..becbeb5480 100644 --- a/packages/server/src/api/routes/tests/backup.spec.ts +++ b/packages/server/src/api/routes/tests/backup.spec.ts @@ -44,7 +44,7 @@ describe("/backups", () => { expect(headers["content-disposition"]).toEqual( `attachment; filename="${ - config.getApp()!.name + config.getApp().name }-export-${mocks.date.MOCK_DATE.getTime()}.tar.gz"` ) }) diff --git a/packages/server/src/api/routes/tests/webhook.spec.ts b/packages/server/src/api/routes/tests/webhook.spec.ts index 38f84852b4..48a6da38bf 100644 --- a/packages/server/src/api/routes/tests/webhook.spec.ts +++ b/packages/server/src/api/routes/tests/webhook.spec.ts @@ -36,7 +36,7 @@ describe("/webhooks", () => { const automation = await config.createAutomation() const res = await request .put(`/api/webhooks`) - .send(basicWebhook(automation._id)) + .send(basicWebhook(automation._id!)) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) @@ -145,7 +145,7 @@ describe("/webhooks", () => { let automation = collectAutomation() let newAutomation = await config.createAutomation(automation) let syncWebhook = await config.createWebhook( - basicWebhook(newAutomation._id) + basicWebhook(newAutomation._id!) ) // replicate changes before checking webhook diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index f6f0992585..599675bd4e 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -61,7 +61,7 @@ import { Table, TableSourceType, User, - UserRoles, + UserCtx, View, WithRequired, } from "@budibase/types" @@ -70,7 +70,6 @@ import API from "./api" import { cloneDeep } from "lodash" import jwt, { Secret } from "jsonwebtoken" import { Server } from "http" -import { userDetailListType } from "aws-sdk/clients/iam" mocks.licenses.init(pro) @@ -89,14 +88,14 @@ export default class TestConfiguration { request?: supertest.SuperTest started: boolean appId?: string - allApps: any[] + allApps: App[] app?: App prodApp?: App prodAppId?: string user?: User userMetadataId?: string table?: Table - automation: any + automation?: Automation datasource?: Datasource tenantId?: string api: API @@ -124,16 +123,26 @@ export default class TestConfiguration { } getApp() { + if (!this.app) { + throw new Error("app has not been initialised, call config.init() first") + } return this.app } getProdApp() { + if (!this.prodApp) { + throw new Error( + "prodApp has not been initialised, call config.init() first" + ) + } return this.prodApp } getAppId() { if (!this.appId) { - throw new Error("appId has not been initialised properly") + throw new Error( + "appId has not been initialised, call config.init() first" + ) } return this.appId } @@ -164,6 +173,15 @@ export default class TestConfiguration { } } + getAutomation() { + if (!this.automation) { + throw new Error( + "automation has not been initialised, call config.init() first" + ) + } + return this.automation + } + async doInContext( appId: string | undefined, task: () => Promise @@ -270,11 +288,11 @@ export default class TestConfiguration { // UTILS - _req, Res, Context extends Ctx>( - handler: (ctx: Context) => Promise, + _req, Res>( + handler: (ctx: UserCtx) => Promise, body?: Req, params?: Record - ) { + ): Promise { // create a fake request ctx const request: any = {} const appId = this.appId @@ -539,19 +557,20 @@ export default class TestConfiguration { // create dev app // clear any old app this.appId = undefined - this.app = await context.doInTenant(this.tenantId!, async () => { - const app = (await this._req(appController.create, { - name: appName, - })) as App - this.appId = app.appId! - return app - }) + this.app = await context.doInTenant( + this.tenantId!, + async () => + (await this._req(appController.create, { + name: appName, + })) as App + ) + this.appId = this.app.appId return await context.doInAppContext(this.app.appId!, async () => { // create production app this.prodApp = await this.publish() this.allApps.push(this.prodApp) - this.allApps.push(this.app) + this.allApps.push(this.app!) return this.app! }) @@ -739,14 +758,13 @@ export default class TestConfiguration { // AUTOMATION - async createAutomation(config?: any) { + async createAutomation(config?: Automation) { config = config || basicAutomation() if (config._rev) { delete config._rev } - this.automation = ( - await this._req(automationController.create, config) - ).automation + const res = await this._req(automationController.create, config) + this.automation = res.automation return this.automation } @@ -769,7 +787,7 @@ export default class TestConfiguration { if (!this.automation) { throw "Must create an automation before creating webhook." } - config = config || basicWebhook(this.automation._id) + config = config || basicWebhook(this.automation._id!) return (await this._req(webhookController.save, config)).webhook } From a9392b2176dc9847d4d08bad832364cffe310600 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 12:13:13 +0000 Subject: [PATCH 05/10] More types. --- .../server/src/api/controllers/automation.ts | 3 +- packages/server/src/api/controllers/layout.ts | 4 +- .../server/src/api/controllers/query/index.ts | 2 +- packages/server/src/api/controllers/screen.ts | 10 ++++- .../src/api/routes/tests/datasource.spec.ts | 4 +- .../routes/tests/queries/query.seq.spec.ts | 9 ++-- .../routes/tests/utilities/TestFunctions.ts | 12 ++++-- packages/server/src/constants/layouts.ts | 4 +- packages/server/src/constants/screens.ts | 5 +-- .../src/tests/utilities/TestConfiguration.ts | 42 ++++++++++++------- .../server/src/tests/utilities/structures.ts | 6 ++- packages/types/src/documents/app/layout.ts | 5 +++ packages/types/src/documents/app/screen.ts | 1 + 13 files changed, 72 insertions(+), 35 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index b7c29efa6f..d1bd580331 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -25,6 +25,7 @@ import { getActionDefinitions as actionDefs } from "../../automations/actions" import sdk from "../../sdk" import { builderSocket } from "../../websockets" import env from "../../environment" +import { DocumentDestroyResponse } from "@budibase/nano" async function getActionDefinitions() { return removeDeprecated(await actionDefs()) @@ -209,7 +210,7 @@ export async function find(ctx: UserCtx) { ctx.body = await db.get(ctx.params.id) } -export async function destroy(ctx: UserCtx) { +export async function destroy(ctx: UserCtx) { const db = context.getAppDB() const automationId = ctx.params.id const oldAutomation = await db.get(automationId) diff --git a/packages/server/src/api/controllers/layout.ts b/packages/server/src/api/controllers/layout.ts index 69e4ad91ed..1a15432b88 100644 --- a/packages/server/src/api/controllers/layout.ts +++ b/packages/server/src/api/controllers/layout.ts @@ -1,9 +1,9 @@ import { EMPTY_LAYOUT } from "../../constants/layouts" import { generateLayoutID, getScreenParams } from "../../db/utils" import { events, context } from "@budibase/backend-core" -import { BBContext, Layout } from "@budibase/types" +import { BBContext, Layout, UserCtx } from "@budibase/types" -export async function save(ctx: BBContext) { +export async function save(ctx: UserCtx) { const db = context.getAppDB() let layout = ctx.request.body diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index 768c921150..973718ba48 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -73,7 +73,7 @@ const _import = async (ctx: UserCtx) => { } export { _import as import } -export async function save(ctx: UserCtx) { +export async function save(ctx: UserCtx) { const db = context.getAppDB() const query: Query = ctx.request.body diff --git a/packages/server/src/api/controllers/screen.ts b/packages/server/src/api/controllers/screen.ts index 446fe2e5fa..ee8e0ff892 100644 --- a/packages/server/src/api/controllers/screen.ts +++ b/packages/server/src/api/controllers/screen.ts @@ -7,7 +7,13 @@ import { roles, } from "@budibase/backend-core" import { updateAppPackage } from "./application" -import { Plugin, ScreenProps, BBContext, Screen } from "@budibase/types" +import { + Plugin, + ScreenProps, + BBContext, + Screen, + UserCtx, +} from "@budibase/types" import { builderSocket } from "../../websockets" export async function fetch(ctx: BBContext) { @@ -31,7 +37,7 @@ export async function fetch(ctx: BBContext) { ) } -export async function save(ctx: BBContext) { +export async function save(ctx: UserCtx) { const db = context.getAppDB() let screen = ctx.request.body diff --git a/packages/server/src/api/routes/tests/datasource.spec.ts b/packages/server/src/api/routes/tests/datasource.spec.ts index 41229b0a2a..032da71b80 100644 --- a/packages/server/src/api/routes/tests/datasource.spec.ts +++ b/packages/server/src/api/routes/tests/datasource.spec.ts @@ -86,7 +86,7 @@ describe("/datasources", () => { }) // check variables in cache let contents = await checkCacheForDynamicVariable( - query._id, + query._id!, "variable3" ) expect(contents.rows.length).toEqual(1) @@ -102,7 +102,7 @@ describe("/datasources", () => { expect(res.body.errors).toBeUndefined() // check variables no longer in cache - contents = await checkCacheForDynamicVariable(query._id, "variable3") + contents = await checkCacheForDynamicVariable(query._id!, "variable3") expect(contents).toBe(null) }) }) diff --git a/packages/server/src/api/routes/tests/queries/query.seq.spec.ts b/packages/server/src/api/routes/tests/queries/query.seq.spec.ts index 52d35fa782..2bbc8366ea 100644 --- a/packages/server/src/api/routes/tests/queries/query.seq.spec.ts +++ b/packages/server/src/api/routes/tests/queries/query.seq.spec.ts @@ -467,7 +467,10 @@ describe("/queries", () => { queryString: "test={{ variable3 }}", }) // check its in cache - const contents = await checkCacheForDynamicVariable(base._id, "variable3") + const contents = await checkCacheForDynamicVariable( + base._id!, + "variable3" + ) expect(contents.rows.length).toEqual(1) const responseBody = await preview(datasource, { path: "www.failonce.com", @@ -490,7 +493,7 @@ describe("/queries", () => { queryString: "test={{ variable3 }}", }) // check its in cache - let contents = await checkCacheForDynamicVariable(base._id, "variable3") + let contents = await checkCacheForDynamicVariable(base._id!, "variable3") expect(contents.rows.length).toEqual(1) // delete the query @@ -500,7 +503,7 @@ describe("/queries", () => { .expect(200) // check variables no longer in cache - contents = await checkCacheForDynamicVariable(base._id, "variable3") + contents = await checkCacheForDynamicVariable(base._id!, "variable3") expect(contents).toBe(null) }) }) diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts index 53e90396aa..0576b1e748 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts @@ -4,6 +4,7 @@ import { AppStatus } from "../../../../db/utils" import { roles, tenancy, context, db } from "@budibase/backend-core" import env from "../../../../environment" import Nano from "@budibase/nano" +import TestConfiguration from "src/tests/utilities/TestConfiguration" class Request { appId: any @@ -52,10 +53,10 @@ export const clearAllApps = async ( }) } -export const clearAllAutomations = async (config: any) => { +export const clearAllAutomations = async (config: TestConfiguration) => { const automations = await config.getAllAutomations() for (let auto of automations) { - await context.doInAppContext(config.appId, async () => { + await context.doInAppContext(config.getAppId(), async () => { await config.deleteAutomation(auto) }) } @@ -101,7 +102,12 @@ export const checkBuilderEndpoint = async ({ method, url, body, -}: any) => { +}: { + config: TestConfiguration + method: string + url: string + body: any +}) => { const headers = await config.login({ userId: "us_fail", builder: false, diff --git a/packages/server/src/constants/layouts.ts b/packages/server/src/constants/layouts.ts index 835a5d2e15..f4eb337c2d 100644 --- a/packages/server/src/constants/layouts.ts +++ b/packages/server/src/constants/layouts.ts @@ -1,9 +1,11 @@ +import { Layout } from "@budibase/types" + export const BASE_LAYOUT_PROP_IDS = { PRIVATE: "layout_private_master", PUBLIC: "layout_public_master", } -export const EMPTY_LAYOUT = { +export const EMPTY_LAYOUT: Layout = { componentLibraries: ["@budibase/standard-components"], title: "{{ name }}", favicon: "./_shared/favicon.png", diff --git a/packages/server/src/constants/screens.ts b/packages/server/src/constants/screens.ts index 6c88b0f957..1107289ea0 100644 --- a/packages/server/src/constants/screens.ts +++ b/packages/server/src/constants/screens.ts @@ -1,5 +1,6 @@ import { roles } from "@budibase/backend-core" import { BASE_LAYOUT_PROP_IDS } from "./layouts" +import { Screen } from "@budibase/types" export function createHomeScreen( config: { @@ -9,10 +10,8 @@ export function createHomeScreen( roleId: roles.BUILTIN_ROLE_IDS.BASIC, route: "/", } -) { +): Screen { return { - description: "", - url: "", layoutId: BASE_LAYOUT_PROP_IDS.PRIVATE, props: { _id: "d834fea2-1b3e-4320-ab34-f9009f5ecc59", diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 599675bd4e..70794934cc 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -53,9 +53,12 @@ import { Datasource, FieldType, INTERNAL_TABLE_SOURCE_ID, + Layout, + Query, RelationshipFieldMetadata, RelationshipType, Row, + Screen, SearchParams, SourceName, Table, @@ -63,6 +66,7 @@ import { User, UserCtx, View, + Webhook, WithRequired, } from "@budibase/types" @@ -182,6 +186,15 @@ export default class TestConfiguration { return this.automation } + getDatasource() { + if (!this.datasource) { + throw new Error( + "datasource has not been initialised, call config.init() first" + ) + } + return this.datasource + } + async doInContext( appId: string | undefined, task: () => Promise @@ -288,10 +301,10 @@ export default class TestConfiguration { // UTILS - _req, Res>( + _req | void, Res>( handler: (ctx: UserCtx) => Promise, body?: Req, - params?: Record + params?: Record ): Promise { // create a fake request ctx const request: any = {} @@ -399,7 +412,7 @@ export default class TestConfiguration { builder, prodApp, }: { - roleId: string + roleId?: string userId: string builder: boolean prodApp: boolean @@ -415,7 +428,7 @@ export default class TestConfiguration { await this.globalUser({ _id: userId, builder: { global: builder }, - roles: { [appId]: roleId }, + roles: { [appId]: roleId || roles.BUILTIN_ROLE_IDS.BASIC }, }) } await sessions.createASession(userId, { @@ -772,7 +785,7 @@ export default class TestConfiguration { return this._req(automationController.fetch) } - async deleteAutomation(automation?: any) { + async deleteAutomation(automation?: Automation) { automation = automation || this.automation if (!automation) { return @@ -783,7 +796,7 @@ export default class TestConfiguration { }) } - async createWebhook(config?: any) { + async createWebhook(config?: Webhook) { if (!this.automation) { throw "Must create an automation before creating webhook." } @@ -811,7 +824,7 @@ export default class TestConfiguration { return { ...this.datasource, _id: this.datasource!._id! } } - async restDatasource(cfg?: any) { + async restDatasource(cfg?: Record) { return this.createDatasource({ datasource: { ...basicDatasource().datasource, @@ -868,24 +881,23 @@ export default class TestConfiguration { // QUERY - async createQuery(config?: any) { - if (!this.datasource && !config) { - throw "No datasource created for query." - } - config = config || basicQuery(this.datasource!._id!) - return this._req(queryController.save, config) + async createQuery(config?: Query) { + return this._req( + queryController.save, + config || basicQuery(this.getDatasource()._id!) + ) } // SCREEN - async createScreen(config?: any) { + async createScreen(config?: Screen) { config = config || basicScreen() return this._req(screenController.save, config) } // LAYOUT - async createLayout(config?: any) { + async createLayout(config?: Layout) { config = config || basicLayout() return await this._req(layoutController.save, config) } diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index 2fecf15fd6..5b50bd1175 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -22,6 +22,8 @@ import { INTERNAL_TABLE_SOURCE_ID, TableSourceType, Query, + Webhook, + WebhookActionType, } from "@budibase/types" import { LoopInput, LoopStepType } from "../../definitions/automations" @@ -407,12 +409,12 @@ export function basicLayout() { return cloneDeep(EMPTY_LAYOUT) } -export function basicWebhook(automationId: string) { +export function basicWebhook(automationId: string): Webhook { return { live: true, name: "webhook", action: { - type: "automation", + type: WebhookActionType.AUTOMATION, target: automationId, }, } diff --git a/packages/types/src/documents/app/layout.ts b/packages/types/src/documents/app/layout.ts index 06542f680d..51ce511712 100644 --- a/packages/types/src/documents/app/layout.ts +++ b/packages/types/src/documents/app/layout.ts @@ -1,6 +1,11 @@ import { Document } from "../document" export interface Layout extends Document { + componentLibraries: string[] + title: string + favicon: string + stylesheets: string[] props: any layoutId?: string + name?: string } diff --git a/packages/types/src/documents/app/screen.ts b/packages/types/src/documents/app/screen.ts index 58c00ef3d6..4977c79b0b 100644 --- a/packages/types/src/documents/app/screen.ts +++ b/packages/types/src/documents/app/screen.ts @@ -22,4 +22,5 @@ export interface Screen extends Document { routing: ScreenRouting props: ScreenProps name?: string + pluginAdded?: boolean } From 07b3d83ebb9df55f4567905169a342cbaa6ae2a7 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 12:14:03 +0000 Subject: [PATCH 06/10] Remove test skeleton. --- packages/server/src/api/routes/tests/application.spec.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/server/src/api/routes/tests/application.spec.ts b/packages/server/src/api/routes/tests/application.spec.ts index 78f021ac5d..dbe4eb51ae 100644 --- a/packages/server/src/api/routes/tests/application.spec.ts +++ b/packages/server/src/api/routes/tests/application.spec.ts @@ -248,10 +248,4 @@ describe("/applications", () => { expect(devLogs.data.length).toBe(0) }) }) - - describe("permissions", () => { - it("should return the list of apps the user has access to", async () => { - const user = config.user - }) - }) }) From 237634386c153291d3f8627e8af95a02c4fe4866 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 12:19:08 +0000 Subject: [PATCH 07/10] More typing fixes. --- packages/backend-core/src/docIds/ids.ts | 4 ++-- .../server/src/api/routes/tests/utilities/TestFunctions.ts | 2 +- packages/server/src/tests/utilities/TestConfiguration.ts | 2 +- packages/worker/src/tests/TestConfiguration.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend-core/src/docIds/ids.ts b/packages/backend-core/src/docIds/ids.ts index 02176109da..9627b2b94c 100644 --- a/packages/backend-core/src/docIds/ids.ts +++ b/packages/backend-core/src/docIds/ids.ts @@ -74,7 +74,7 @@ export function getGlobalIDFromUserMetadataID(id: string) { * Generates a template ID. * @param ownerId The owner/user of the template, this could be global or a workspace level. */ -export function generateTemplateID(ownerId: any) { +export function generateTemplateID(ownerId: string) { return `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}` } @@ -105,7 +105,7 @@ export function prefixRoleID(name: string) { * Generates a new dev info document ID - this is scoped to a user. * @returns The new dev info ID which info for dev (like api key) can be stored under. */ -export const generateDevInfoID = (userId: any) => { +export const generateDevInfoID = (userId: string) => { return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}` } diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts index 0576b1e748..8a843551ac 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts @@ -106,7 +106,7 @@ export const checkBuilderEndpoint = async ({ config: TestConfiguration method: string url: string - body: any + body?: any }) => { const headers = await config.login({ userId: "us_fail", diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 70794934cc..21605b7a5e 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -539,7 +539,7 @@ export default class TestConfiguration { return this.createApp(appName) } - doInTenant(task: any) { + doInTenant(task: () => T) { return context.doInTenant(this.getTenantId(), task) } diff --git a/packages/worker/src/tests/TestConfiguration.ts b/packages/worker/src/tests/TestConfiguration.ts index df6726eed1..3ebfb5f020 100644 --- a/packages/worker/src/tests/TestConfiguration.ts +++ b/packages/worker/src/tests/TestConfiguration.ts @@ -280,7 +280,7 @@ class TestConfiguration { const db = context.getGlobalDB() - const id = dbCore.generateDevInfoID(this.user!._id) + const id = dbCore.generateDevInfoID(this.user!._id!) // TODO: dry this.apiKey = encryption.encrypt( `${this.tenantId}${dbCore.SEPARATOR}${utils.newid()}` From 223a268483f968e851450fe3c5ef5e2c8a7ea218 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 28 Feb 2024 16:35:15 +0000 Subject: [PATCH 08/10] Respond to PR feedback. --- packages/server/src/api/controllers/automation.ts | 4 ++-- packages/server/src/api/controllers/layout.ts | 12 ++++++++++-- packages/types/src/api/web/automation.ts | 3 +++ packages/types/src/api/web/index.ts | 2 ++ packages/types/src/api/web/layout.ts | 5 +++++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 packages/types/src/api/web/automation.ts create mode 100644 packages/types/src/api/web/layout.ts diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index d1bd580331..b986b5232b 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -20,12 +20,12 @@ import { AutomationActionStepId, AutomationResults, UserCtx, + DeleteAutomationResponse, } from "@budibase/types" import { getActionDefinitions as actionDefs } from "../../automations/actions" import sdk from "../../sdk" import { builderSocket } from "../../websockets" import env from "../../environment" -import { DocumentDestroyResponse } from "@budibase/nano" async function getActionDefinitions() { return removeDeprecated(await actionDefs()) @@ -210,7 +210,7 @@ export async function find(ctx: UserCtx) { ctx.body = await db.get(ctx.params.id) } -export async function destroy(ctx: UserCtx) { +export async function destroy(ctx: UserCtx) { const db = context.getAppDB() const automationId = ctx.params.id const oldAutomation = await db.get(automationId) diff --git a/packages/server/src/api/controllers/layout.ts b/packages/server/src/api/controllers/layout.ts index 1a15432b88..c0406f50ac 100644 --- a/packages/server/src/api/controllers/layout.ts +++ b/packages/server/src/api/controllers/layout.ts @@ -1,9 +1,17 @@ import { EMPTY_LAYOUT } from "../../constants/layouts" import { generateLayoutID, getScreenParams } from "../../db/utils" import { events, context } from "@budibase/backend-core" -import { BBContext, Layout, UserCtx } from "@budibase/types" +import { + BBContext, + Layout, + SaveLayoutRequest, + SaveLayoutResponse, + UserCtx, +} from "@budibase/types" -export async function save(ctx: UserCtx) { +export async function save( + ctx: UserCtx +) { const db = context.getAppDB() let layout = ctx.request.body diff --git a/packages/types/src/api/web/automation.ts b/packages/types/src/api/web/automation.ts new file mode 100644 index 0000000000..c1f3d01b2f --- /dev/null +++ b/packages/types/src/api/web/automation.ts @@ -0,0 +1,3 @@ +import { DocumentDestroyResponse } from "@budibase/nano" + +export interface DeleteAutomationResponse extends DocumentDestroyResponse {} diff --git a/packages/types/src/api/web/index.ts b/packages/types/src/api/web/index.ts index ab18add208..62d8ce8280 100644 --- a/packages/types/src/api/web/index.ts +++ b/packages/types/src/api/web/index.ts @@ -11,3 +11,5 @@ export * from "./global" export * from "./pagination" export * from "./searchFilter" export * from "./cookies" +export * from "./automation" +export * from "./layout" diff --git a/packages/types/src/api/web/layout.ts b/packages/types/src/api/web/layout.ts new file mode 100644 index 0000000000..50512777ef --- /dev/null +++ b/packages/types/src/api/web/layout.ts @@ -0,0 +1,5 @@ +import { Layout } from "../../documents" + +export interface SaveLayoutRequest extends Layout {} + +export interface SaveLayoutResponse extends Layout {} From 0205db104d3340d3e587e75eb295172306b52a94 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:15:01 +0000 Subject: [PATCH 09/10] FIX: clicking on design tab while data tab loads does not navigate correctly (#13152) * If still loading, try navigation later * Set active tab even if still loading * Refactor - timeout not needed! --- .../pages/builder/app/[application]/_layout.svelte | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte index c7f8c98e73..dd66f5bc34 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -69,11 +69,12 @@ // brought back to the same screen. const topItemNavigate = path => () => { const activeTopNav = $layout.children.find(c => $isActive(c.path)) - if (!activeTopNav) return - builderStore.setPreviousTopNavPath( - activeTopNav.path, - window.location.pathname - ) + if (activeTopNav) { + builderStore.setPreviousTopNavPath( + activeTopNav.path, + window.location.pathname + ) + } $goto($builderStore.previousTopNavPath[path] || path) } From 8a109ffe6a4e1bf8064f609272918885dab8fb28 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 29 Feb 2024 09:38:13 +0000 Subject: [PATCH 10/10] Bump version to 2.20.13 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index e1a469adf1..1b559f217d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.20.12", + "version": "2.20.13", "npmClient": "yarn", "packages": [ "packages/*",