From 62afc94f2feeb94e245416bd8f504841621be071 Mon Sep 17 00:00:00 2001 From: blaisadmin Date: Thu, 21 May 2026 13:10:34 -0400 Subject: [PATCH] fixed adding new workspace at login --- backend/src/app.ts | 5 +- .../repositories/workspaceRepository.test.ts | 48 +++++++++++++++++++ .../src/repositories/workspaceRepository.ts | 18 +++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/backend/src/app.ts b/backend/src/app.ts index 10a10d5..af55def 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -74,6 +74,7 @@ import { createWorkspace, deleteWorkspaceMember, deleteWorkspaceIfEmpty, + ensureDefaultWorkspaceForUser, ensurePersonalWorkspaceForUser, findAlternateWorkspaceForUser, getPlatformAdminSummary, @@ -2061,7 +2062,7 @@ app.get('/api/auth/magic-link/verify', async (req: Request, res: Response, next: } await claimWorkspaceInvites(user!); - const receivingWorkspaceId = await ensurePersonalWorkspaceForUser(user!); + const receivingWorkspaceId = await ensureDefaultWorkspaceForUser(user!); const transferCompletion = await completePendingBirdTransfersForOwner(user!.email, receivingWorkspaceId); const memberships = await normalizeWorkspaceMembershipList(user!.id); const activeWorkspaceId = transferCompletion.completed > 0 ? receivingWorkspaceId : memberships[0]?.workspace.id ?? receivingWorkspaceId; @@ -2269,7 +2270,7 @@ const handleOAuthCallback = async (req: Request, res: Response, next: NextFuncti await linkAuthAccount(user!.id, providerKey, providerSubject, email); await claimWorkspaceInvites(user!); - const activeWorkspaceId = await ensurePersonalWorkspaceForUser(user!); + const activeWorkspaceId = await ensureDefaultWorkspaceForUser(user!); await completePendingBirdTransfersForOwner(user!.email, activeWorkspaceId); const { token } = await createAuthSession(user!.id, activeWorkspaceId); const redirectUrl = new URL(oauthState.redirect_to || frontendBaseUrl); diff --git a/backend/src/repositories/workspaceRepository.test.ts b/backend/src/repositories/workspaceRepository.test.ts index 486a899..2160bf1 100644 --- a/backend/src/repositories/workspaceRepository.test.ts +++ b/backend/src/repositories/workspaceRepository.test.ts @@ -4,6 +4,7 @@ import test from 'node:test'; import { createWorkspace, deleteWorkspaceIfEmpty, + ensureDefaultWorkspaceForUser, ensurePersonalWorkspaceForUser, findAlternateWorkspaceForUser, getPlatformAdminSummary, @@ -64,6 +65,53 @@ test('ensurePersonalWorkspaceForUser creates a fresh workspace instead of claimi assert.deepEqual(calls[2].params, [43, "Owner's Flock", 'owner@example.com']); }); +test('ensureDefaultWorkspaceForUser reuses an existing rescue workspace without creating a household flock', async () => { + const { calls } = mockDb({ + rowCount: 1, + rows: [{ workspace_id: 84 }], + }); + + const workspaceId = await ensureDefaultWorkspaceForUser(user); + + assert.equal(workspaceId, 84); + assert.equal(calls.length, 1); + assert.match(calls[0].text, /FROM workspace_members/); + assert.doesNotMatch(calls[0].text, /workspaces\.workspace_type = 'standard'/); +}); + +test('ensureDefaultWorkspaceForUser creates a household flock when the user has no workspace', async () => { + const { calls } = mockDb( + { + rowCount: 0, + rows: [], + }, + { + rowCount: 0, + rows: [], + }, + { + rowCount: 1, + rows: [{ next_id: 43 }], + }, + { + rowCount: 1, + rows: [], + }, + { + rowCount: 1, + rows: [], + }, + ); + + const workspaceId = await ensureDefaultWorkspaceForUser(user); + + assert.equal(workspaceId, 43); + assert.equal(calls.length, 5); + assert.match(calls[0].text, /FROM workspace_members/); + assert.match(calls[1].text, /workspaces\.workspace_type = 'standard'/); + assert.match(calls[3].text, /INSERT INTO workspaces/); +}); + test('createWorkspace inserts owner membership and returns the created workspace', async () => { const { calls } = mockDb( { rowCount: 1, rows: [] }, diff --git a/backend/src/repositories/workspaceRepository.ts b/backend/src/repositories/workspaceRepository.ts index 4940157..c3d9ff1 100644 --- a/backend/src/repositories/workspaceRepository.ts +++ b/backend/src/repositories/workspaceRepository.ts @@ -114,6 +114,24 @@ export const ensurePersonalWorkspaceForUser = async (user: UserRow) => { return workspaceId; }; +export const ensureDefaultWorkspaceForUser = async (user: UserRow) => { + const existing = await db.query<{ workspace_id: number }>( + `SELECT workspace_id + FROM workspace_members + INNER JOIN workspaces ON workspaces.id = workspace_members.workspace_id + WHERE workspace_members.user_id = $1 + ORDER BY workspaces.created_at ASC + LIMIT 1`, + [user.id], + ); + + if (existing.rowCount) { + return Number(existing.rows[0].workspace_id); + } + + return ensurePersonalWorkspaceForUser(user); +}; + export const claimWorkspaceInvites = async (user: UserRow) => { await db.query( `UPDATE workspace_members