diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.spec.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.spec.ts index 69505d84d7..c34d0e16ba 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.spec.ts @@ -55,7 +55,10 @@ describe('UserService', () => { }, { provide: WorkspaceService, - useValue: { deleteWorkspace: jest.fn() }, + useValue: { + deleteWorkspace: jest.fn(), + suspendWorkspace: jest.fn(), + }, }, { provide: WorkspaceDomainsService, @@ -386,7 +389,8 @@ describe('UserService', () => { const res = await service.deleteUser('u2'); - expect(workspaceService.deleteWorkspace).toHaveBeenCalledWith('w2'); + expect(workspaceService.suspendWorkspace).toHaveBeenCalledWith('w2'); + expect(workspaceService.deleteWorkspace).toHaveBeenCalledWith('w2', true); expect(res).toMatchObject({ id: 'u2' }); }); diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts index b2f70ba3b9..63e9eb498d 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts @@ -10,10 +10,12 @@ import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils'; import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace'; import { type QueryRunner, In, IsNull, Not, Repository } from 'typeorm'; +import { CoreEntityCacheService } from 'src/engine/core-entity-cache/services/core-entity-cache.service'; import { AuthException, AuthExceptionCode, } from 'src/engine/core-modules/auth/auth.exception'; +import { type AuthContextUser } from 'src/engine/core-modules/auth/types/auth-context.type'; import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service'; import { EmailVerificationTrigger } from 'src/engine/core-modules/email-verification/email-verification.constants'; import { EmailVerificationService } from 'src/engine/core-modules/email-verification/services/email-verification.service'; @@ -27,7 +29,7 @@ import { UpdateWorkspaceMemberEmailJob, UpdateWorkspaceMemberEmailJobData, } from 'src/engine/core-modules/user/jobs/update-workspace-member-email.job'; -import { type AuthContextUser } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkspaceMemberTranspiler } from 'src/engine/core-modules/user/services/workspace-member-transpiler.service'; import { UserEntity } from 'src/engine/core-modules/user/user.entity'; import { UserExceptionCode } from 'src/engine/core-modules/user/user.exception'; import { userValidator } from 'src/engine/core-modules/user/user.validate'; @@ -39,11 +41,9 @@ import { PermissionsExceptionMessage, } from 'src/engine/metadata-modules/permissions/permissions.exception'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; -import { CoreEntityCacheService } from 'src/engine/core-entity-cache/services/core-entity-cache.service'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { WorkspaceMemberTranspiler } from 'src/engine/core-modules/user/services/workspace-member-transpiler.service'; // oxlint-disable-next-line twenty/inject-workspace-repository export class UserService extends TypeOrmQueryService { @@ -322,7 +322,8 @@ export class UserService extends TypeOrmQueryService { const userWorkspaceId = userWorkspace.id; if (workspaceMembers.length === 1) { - await this.workspaceService.deleteWorkspace(workspaceId); + await this.workspaceService.suspendWorkspace(workspaceId); + await this.workspaceService.deleteWorkspace(workspaceId, true); return; } diff --git a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts index 9eff76e620..a37f12cf3b 100644 --- a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts @@ -131,7 +131,7 @@ describe('Successful user and workspace creation', () => { ); }); - it('should delete workspace and related metadata entities when last user is deleted', async () => { + it('should suspend and soft-delete workspace when last user is deleted', async () => { const uniqueEmail = `test-delete-${randomUUID()}@example.com`; const { data } = await signUp({ @@ -253,16 +253,11 @@ describe('Successful user and workspace creation', () => { [workspaceId], ); - expect(workspaceAfterDeletion).toHaveLength(0); - - for (const table of tablesToVerify) { - const result = await testDataSource.query( - `SELECT COUNT(*) as count FROM core."${table}" WHERE "workspaceId" = $1`, - [workspaceId], - ); - const count = parseInt(result[0].count); - - expect({ count, table }).toEqual({ count: 0, table }); - } + expect(workspaceAfterDeletion).toHaveLength(1); + expect(workspaceAfterDeletion[0].activationStatus).toBe( + WorkspaceActivationStatus.SUSPENDED, + ); + expect(workspaceAfterDeletion[0].suspendedAt).not.toBeNull(); + expect(workspaceAfterDeletion[0].deletedAt).not.toBeNull(); }); });