From 8576127b47abc5769806502f976a007e495b4bce Mon Sep 17 00:00:00 2001 From: martmull Date: Mon, 13 May 2024 14:18:45 +0200 Subject: [PATCH] Add migration to restrict users without workspaces (#5369) - update set null ON DELETE constraint to RESTRICT - update missing updates --- ...226719-updateInconsistentUserConstraint.ts | 43 +++++++++++++++++++ .../auth/services/token.service.spec.ts | 5 ++- .../engine/core-modules/user/user.entity.ts | 2 +- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/1715593226719-updateInconsistentUserConstraint.ts diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1715593226719-updateInconsistentUserConstraint.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1715593226719-updateInconsistentUserConstraint.ts new file mode 100644 index 000000000..ace85a0c5 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/1715593226719-updateInconsistentUserConstraint.ts @@ -0,0 +1,43 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UpdateInconsistentUserConstraint1715593226719 + implements MigrationInterface +{ + name = 'UpdateInconsistentUserConstraint1715593226719'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."user" DROP CONSTRAINT "FK_2ec910029395fa7655621c88908"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" TYPE text`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "interval" TYPE text`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" TYPE text`, + ); + await queryRunner.query( + `ALTER TABLE "core"."user" ADD CONSTRAINT "FK_2ec910029395fa7655621c88908" FOREIGN KEY ("defaultWorkspaceId") REFERENCES "core"."workspace"("id") ON DELETE RESTRICT ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."user" DROP CONSTRAINT "FK_2ec910029395fa7655621c88908"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" TYPE character varying`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "interval" TYPE character varying`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" TYPE character varying`, + ); + await queryRunner.query( + `ALTER TABLE "core"."user" ADD CONSTRAINT "FK_2ec910029395fa7655621c88908" FOREIGN KEY ("defaultWorkspaceId") REFERENCES "core"."workspace"("id") ON DELETE SET NULL ON UPDATE NO ACTION`, + ); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/token.service.spec.ts b/packages/twenty-server/src/engine/core-modules/auth/services/token.service.spec.ts index 1e5d63996..3c405a62b 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/token.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/token.service.spec.ts @@ -160,6 +160,9 @@ describe('TokenService', () => { }; const mockUser = { id: '1', email: 'user@example.com' }; + const mockedNewDate = new Date(); + + jest.spyOn(global, 'Date').mockImplementation(() => mockedNewDate); jest .spyOn(appTokenRepository, 'findOne') .mockResolvedValue(mockToken as AppToken); @@ -173,7 +176,7 @@ describe('TokenService', () => { where: { value: hashedToken, type: AppTokenType.PasswordResetToken, - expiresAt: MoreThan(new Date()), + expiresAt: MoreThan(mockedNewDate), revokedAt: IsNull(), }, }); diff --git a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts index 993d6ed1b..a4e665594 100644 --- a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts @@ -71,7 +71,7 @@ export class User { @Field(() => Workspace, { nullable: false }) @ManyToOne(() => Workspace, (workspace) => workspace.users, { - onDelete: 'SET NULL', + onDelete: 'RESTRICT', }) defaultWorkspace: Relation;