diff --git a/packages/backend-core/src/users/db.ts b/packages/backend-core/src/users/db.ts index 59f698d99c..bd85097bbd 100644 --- a/packages/backend-core/src/users/db.ts +++ b/packages/backend-core/src/users/db.ts @@ -303,7 +303,7 @@ export class UserDB { static async bulkCreate( newUsersRequested: User[], - groups: string[] + groups?: string[] ): Promise { const tenantId = getTenantId() @@ -328,7 +328,7 @@ export class UserDB { }) continue } - newUser.userGroups = groups + newUser.userGroups = groups || [] newUsers.push(newUser) if (isCreator(newUser)) { newCreators.push(newUser) diff --git a/packages/types/src/api/web/user.ts b/packages/types/src/api/web/user.ts index 6db70f20d0..0de42622e6 100644 --- a/packages/types/src/api/web/user.ts +++ b/packages/types/src/api/web/user.ts @@ -50,6 +50,7 @@ export type InviteUsersRequest = InviteUserRequest[] export interface InviteUsersResponse { successful: { email: string }[] unsuccessful: { email: string; reason: string }[] + created?: boolean } export interface SearchUsersRequest { diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 6608fcde05..e904567674 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -17,6 +17,7 @@ import { Ctx, InviteUserRequest, InviteUsersRequest, + InviteUsersResponse, MigrationType, SaveUserResponse, SearchUsersRequest, @@ -250,7 +251,9 @@ export const tenantUserLookup = async (ctx: any) => { /* Encapsulate the app user onboarding flows here. */ -export const onboardUsers = async (ctx: Ctx) => { +export const onboardUsers = async ( + ctx: Ctx +) => { if (await isEmailConfigured()) { await inviteMultiple(ctx) return @@ -272,10 +275,10 @@ export const onboardUsers = async (ctx: Ctx) => { } }) - let resp = await userSdk.db.bulkCreate(users, []) - resp.successful.forEach(user => { + let resp = await userSdk.db.bulkCreate(users) + for (const user of resp.successful) { user.password = createdPasswords[user.email] - }) + } ctx.body = { ...resp, created: true } } diff --git a/packages/worker/src/api/routes/global/tests/users.spec.ts b/packages/worker/src/api/routes/global/tests/users.spec.ts index ce2c9347b4..a85933255a 100644 --- a/packages/worker/src/api/routes/global/tests/users.spec.ts +++ b/packages/worker/src/api/routes/global/tests/users.spec.ts @@ -669,4 +669,25 @@ describe("/api/global/users", () => { expect(response.body.message).toBe("Unable to delete self.") }) }) + + describe("POST /api/global/users/onboard", () => { + it("should successfully onboard a user", async () => { + const response = await config.api.users.onboardUser([ + { email: structures.users.newEmail(), userInfo: {} }, + ]) + expect(response.successful.length).toBe(1) + expect(response.unsuccessful.length).toBe(0) + }) + + it("should not onboard a user who has been invited", async () => { + const email = structures.users.newEmail() + await config.api.users.sendUserInvite(sendMailMock, email) + + const response = await config.api.users.onboardUser([ + { email, userInfo: {} }, + ]) + expect(response.successful.length).toBe(0) + expect(response.unsuccessful.length).toBe(1) + }) + }) }) diff --git a/packages/worker/src/tests/api/users.ts b/packages/worker/src/tests/api/users.ts index ca25e2f9ca..5ecd1447ca 100644 --- a/packages/worker/src/tests/api/users.ts +++ b/packages/worker/src/tests/api/users.ts @@ -5,6 +5,7 @@ import { User, CreateAdminUserRequest, SearchQuery, + InviteUsersResponse, } from "@budibase/types" import structures from "../structures" import { generator } from "@budibase/backend-core/tests" @@ -176,4 +177,24 @@ export class UserAPI extends TestAPI { .expect("Content-Type", /json/) .expect(200) } + + onboardUser = async ( + req: InviteUsersRequest + ): Promise => { + const resp = await this.request + .post(`/api/global/users/onboard`) + .send(req) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + + if (resp.status !== 200) { + throw new Error( + `request failed with status ${resp.status} and body ${JSON.stringify( + resp.body + )}` + ) + } + + return resp.body as InviteUsersResponse + } }