From 3eb7ec909e419d76ddb1bc4b685f105b701f1196 Mon Sep 17 00:00:00 2001 From: Antoine Moreaux Date: Mon, 6 Jan 2025 12:33:57 +0100 Subject: [PATCH] refactor(workspace, users, billing): remove default workspace + rename (#9360) Replaced user-based parameterization with workspace-focused logic across seed scripts, mocks, and billing services. Removed redundant `user` references and standardized to `workspace` to align with updated business rules. Adjusted mock data and tests to reflect these changes. Fix https://github.com/twentyhq/twenty/issues/9295 --- .../__stories__/CommandMenu.stories.tsx | 4 ++-- .../RelationManyFieldInput.stories.tsx | 4 ++-- .../RelationToOneFieldInput.stories.tsx | 4 ++-- .../useSetNextOnboardingStatus.test.ts | 4 ++-- .../__stories__/SupportDropdown.stories.tsx | 4 ++-- .../src/testing/mock-data/users.ts | 10 +++++----- .../database/typeorm-seeds/core/demo/index.ts | 2 +- .../database/typeorm-seeds/core/demo/users.ts | 17 +++++++++++------ .../src/database/typeorm-seeds/core/index.ts | 2 +- .../src/database/typeorm-seeds/core/users.ts | 18 ------------------ .../core-modules/billing/billing.resolver.ts | 7 +++---- .../services/billing-subscription.service.ts | 10 ++++------ 12 files changed, 35 insertions(+), 51 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index 9ac70add4..fb0c8bf13 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -10,7 +10,7 @@ import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { - mockDefaultWorkspace, + mockCurrentWorkspace, mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; import { sleep } from '~/utils/sleep'; @@ -54,7 +54,7 @@ const meta: Meta = { isCommandMenuOpenedState, ); - setCurrentWorkspace(mockDefaultWorkspace); + setCurrentWorkspace(mockCurrentWorkspace); setCurrentWorkspaceMember(mockedWorkspaceMemberData); setIsCommandMenuOpened(true); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx index 3a4cd095e..9c33267d4 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationManyFieldInput.stories.tsx @@ -13,7 +13,7 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { - mockDefaultWorkspace, + mockCurrentWorkspace, mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; @@ -26,7 +26,7 @@ const RelationWorkspaceSetterEffect = () => { ); useEffect(() => { - setCurrentWorkspace(mockDefaultWorkspace); + setCurrentWorkspace(mockCurrentWorkspace); setCurrentWorkspaceMember(mockedWorkspaceMemberData); }, [setCurrentWorkspace, setCurrentWorkspaceMember]); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx index 550a3aa9d..34692439b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx @@ -13,7 +13,7 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { - mockDefaultWorkspace, + mockCurrentWorkspace, mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; @@ -32,7 +32,7 @@ const RelationWorkspaceSetterEffect = () => { ); useEffect(() => { - setCurrentWorkspace(mockDefaultWorkspace); + setCurrentWorkspace(mockCurrentWorkspace); setCurrentWorkspaceMember(mockedWorkspaceMemberData); }, [setCurrentWorkspace, setCurrentWorkspaceMember]); diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts index 260e3d6aa..af5b54423 100644 --- a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts +++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts @@ -7,7 +7,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { - mockDefaultWorkspace, + mockCurrentWorkspace, mockedUserData, } from '~/testing/mock-data/users'; @@ -35,7 +35,7 @@ const renderHooks = ( act(() => { result.current.setCurrentUser({ ...mockedUserData, onboardingStatus }); result.current.setCurrentWorkspace({ - ...mockDefaultWorkspace, + ...mockCurrentWorkspace, currentBillingSubscription: withCurrentBillingSubscription ? { id: v4(), status: SubscriptionStatus.Active } : undefined, diff --git a/packages/twenty-front/src/modules/support/components/__stories__/SupportDropdown.stories.tsx b/packages/twenty-front/src/modules/support/components/__stories__/SupportDropdown.stories.tsx index 530181235..c8f3d50e8 100644 --- a/packages/twenty-front/src/modules/support/components/__stories__/SupportDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/support/components/__stories__/SupportDropdown.stories.tsx @@ -9,7 +9,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { supportChatState } from '@/client-config/states/supportChatState'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { - mockDefaultWorkspace, + mockCurrentWorkspace, mockedUserData, mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; @@ -29,7 +29,7 @@ const meta: Meta = { currentWorkspaceMemberState, ); - setCurrentWorkspace(mockDefaultWorkspace); + setCurrentWorkspace(mockCurrentWorkspace); setCurrentWorkspaceMember(mockedWorkspaceMemberData); setCurrentUser(mockedUserData); setSupportChat({ supportDriver: 'front', supportFrontChatId: '1234' }); diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 8748baf68..c9a55bebb 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -36,7 +36,7 @@ export const avatarUrl = export const workspaceLogoUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACb0lEQVR4nO2VO4taQRTHr3AblbjxEVlwCwVhg7BoqqCIjy/gAyyFWNlYBOxsfH0KuxgQGwXRUkGuL2S7i1barGAgiwbdW93SnGOc4BonPiKahf3DwXFmuP/fPM4ZlvmlTxAhCBdzHnEQWYiv7Mr4C3NeuVYhQYDPzOUUQgDLBQGcLHNhvQK8DACPx8PTxiqVyvISG43GbyaT6Qfpn06n0m63e/tPAPF4vJ1MJu8kEsnWTCkWi1yr1RKGw+GDRqPBOTfr44vFQvD7/Q/lcpmaaVQAr9fLp1IpO22c47hGOBz+MB6PH+Vy+VYDAL8qlUoGtVotzOfzq4MAgsHgE/6KojiQyWR/bKVSqbSszHFM8Pl8z1YK48JsNltCOBwOnrYLO+8AAIjb+nHbycoTiUQfDJ7tFq4YAHiVSmXBxcD41u8flQU8z7fhzO0r83atVns3Go3u9Xr9x0O/RQXo9/tsIBBg6vX606a52Wz+bZ7P5/WwG29gxSJzhKgA6XTaDoFNF+krFAocmC//4yWEcSf2wTm7mCO19xFgSsKOLI16vV7b7XY7mRNoLwA0JymJ5uQIzgIAuX5PzDElT2m+E8BqtQ4ymcx7Yq7T6a6ZE4sKgOadTucaCwkxp1UzlEKh0GDxIXOwDWHAdi6Xe3swQDQa/Q7mywoolUpvsaptymazDWKxmBHTlWXZm405BFZoNpuGgwEmk4mE2SGtVivii4f1AO7J3ZopkQCQj7Ar1FeRChCJRJzVapX6DKNIfSc1Ax+wtQWQ55h6bH8FWDfYV4fO3wlwDr0C/BcADYiTPCxHqIEA2QsCZAkAKnRGkMbKN/sTX5YHPQ1e7SkAAAAASUVORK5CYII='; -export const mockDefaultWorkspace: Workspace = { +export const mockCurrentWorkspace: Workspace = { subdomain: 'acme.twenty.com', id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w', displayName: 'Twenty', @@ -107,9 +107,9 @@ export const mockedUserData: MockedUser = { supportUserHash: 'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d', workspaceMember: mockedWorkspaceMemberData, - currentWorkspace: mockDefaultWorkspace, + currentWorkspace: mockCurrentWorkspace, locale: 'en', - workspaces: [{ workspace: mockDefaultWorkspace }], + workspaces: [{ workspace: mockCurrentWorkspace }], workspaceMembers: [mockedWorkspaceMemberData], onboardingStatus: OnboardingStatus.Completed, userVars: {}, @@ -129,9 +129,9 @@ export const mockedOnboardingUserData = ( supportUserHash: '4fb61d34ed3a4aeda2476d4b308b5162db9e1809b2b8277e6fdc6efc4a609254', workspaceMember: null, - currentWorkspace: mockDefaultWorkspace, + currentWorkspace: mockCurrentWorkspace, locale: 'en', - workspaces: [{ workspace: mockDefaultWorkspace }], + workspaces: [{ workspace: mockCurrentWorkspace }], onboardingStatus: onboardingStatus || null, }; }; diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/demo/index.ts b/packages/twenty-server/src/database/typeorm-seeds/core/demo/index.ts index 8eebbc3ed..c1e7e4e52 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/demo/index.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/demo/index.ts @@ -21,7 +21,7 @@ export const seedCoreSchema = async ( const schemaName = 'core'; await seedWorkspaces(workspaceDataSource, schemaName, workspaceId); - await seedUsers(workspaceDataSource, schemaName, workspaceId); + await seedUsers(workspaceDataSource, schemaName); await seedUserWorkspaces(workspaceDataSource, schemaName, workspaceId); }; diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/demo/users.ts b/packages/twenty-server/src/database/typeorm-seeds/core/demo/users.ts index f4406a473..fcc0ede75 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/demo/users.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/demo/users.ts @@ -13,7 +13,6 @@ export const DEMO_SEED_USER_IDS = { export const seedUsers = async ( workspaceDataSource: DataSource, schemaName: string, - workspaceId: string, ) => { await workspaceDataSource .createQueryBuilder() @@ -56,16 +55,22 @@ export const seedUsers = async ( }; export const deleteUsersByWorkspace = async ( - workspaceDataSource: DataSource, + dataSource: DataSource, schemaName: string, workspaceId: string, ) => { - await workspaceDataSource + const user = await dataSource + .createQueryBuilder(`${schemaName}.${tableName}`, 'user') + .leftJoinAndSelect('user.workspaces', 'userWorkspace') + .where(`userWorkspace."workspaceId" = :workspaceId`, { + workspaceId, + }) + .getMany(); + + await dataSource .createQueryBuilder() .delete() .from(`${schemaName}.${tableName}`) - .where(`"${tableName}"."defaultWorkspaceId" = :workspaceId`, { - workspaceId, - }) + .where(`"${tableName}"."id" IN (:...ids)`, { ids: user.map((u) => u.id) }) .execute(); }; diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/index.ts b/packages/twenty-server/src/database/typeorm-seeds/core/index.ts index 8dcd3212d..2e686e076 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/index.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/index.ts @@ -12,7 +12,7 @@ export const seedCoreSchema = async ( const schemaName = 'core'; await seedWorkspaces(workspaceDataSource, schemaName, workspaceId); - await seedUsers(workspaceDataSource, schemaName, workspaceId); + await seedUsers(workspaceDataSource, schemaName); await seedUserWorkspaces(workspaceDataSource, schemaName, workspaceId); await seedFeatureFlags(workspaceDataSource, schemaName, workspaceId); }; diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/users.ts b/packages/twenty-server/src/database/typeorm-seeds/core/users.ts index a146c9cd4..b538ec26e 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/users.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/users.ts @@ -1,7 +1,5 @@ import { DataSource } from 'typeorm'; -// import { SeedWorkspaceId } from 'src/database/typeorm-seeds/core/workspaces'; - const tableName = 'user'; export const DEV_SEED_USER_IDS = { @@ -13,7 +11,6 @@ export const DEV_SEED_USER_IDS = { export const seedUsers = async ( workspaceDataSource: DataSource, schemaName: string, - workspaceId: string, ) => { await workspaceDataSource .createQueryBuilder() @@ -54,18 +51,3 @@ export const seedUsers = async ( ]) .execute(); }; - -export const deleteUsersByWorkspace = async ( - workspaceDataSource: DataSource, - schemaName: string, - workspaceId: string, -) => { - await workspaceDataSource - .createQueryBuilder() - .delete() - .from(`${schemaName}.${tableName}`) - .where(`"${tableName}"."defaultWorkspaceId" = :workspaceId`, { - workspaceId, - }) - .execute(); -}; diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts index df2d4469d..d32d3bf55 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts @@ -37,9 +37,8 @@ export class BillingResolver { } @Query(() => SessionEntity) - @UseGuards(WorkspaceAuthGuard, UserAuthGuard) + @UseGuards(WorkspaceAuthGuard) async billingPortalSession( - @AuthUser() user: User, @AuthWorkspace() workspace: Workspace, @Args() { returnUrlPath }: BillingSessionInput, ) { @@ -89,8 +88,8 @@ export class BillingResolver { @Mutation(() => UpdateBillingEntity) @UseGuards(WorkspaceAuthGuard) - async updateBillingSubscription(@AuthUser() user: User) { - await this.billingSubscriptionService.applyBillingSubscription(user); + async updateBillingSubscription(@AuthWorkspace() workspace: Workspace) { + await this.billingSubscriptionService.applyBillingSubscription(workspace); return { success: true }; } diff --git a/packages/twenty-server/src/engine/core-modules/billing/services/billing-subscription.service.ts b/packages/twenty-server/src/engine/core-modules/billing/services/billing-subscription.service.ts index f2ebf2d07..ce550fe3d 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/services/billing-subscription.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/services/billing-subscription.service.ts @@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm'; import assert from 'assert'; -import { User } from '@sentry/node'; import Stripe from 'stripe'; import { Not, Repository } from 'typeorm'; @@ -15,6 +14,7 @@ import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/bill import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum'; import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @Injectable() export class BillingSubscriptionService { @@ -114,9 +114,9 @@ export class BillingSubscriptionService { return entitlement.value; } - async applyBillingSubscription(user: User) { + async applyBillingSubscription(workspace: Workspace) { const billingSubscription = await this.getCurrentBillingSubscriptionOrThrow( - { workspaceId: user.defaultWorkspaceId }, + { workspaceId: workspace.id }, ); const newInterval = @@ -125,9 +125,7 @@ export class BillingSubscriptionService { : SubscriptionInterval.Year; const billingSubscriptionItem = - await this.getCurrentBillingSubscriptionItemOrThrow( - user.defaultWorkspaceId, - ); + await this.getCurrentBillingSubscriptionItemOrThrow(workspace.id); const productPrice = await this.stripeService.getStripePrice( AvailableProduct.BasePlan,