From 12d33bc82379e2d37314c00831c3348d0f56752c Mon Sep 17 00:00:00 2001 From: Weiko Date: Wed, 4 Dec 2024 11:35:47 +0100 Subject: [PATCH 01/13] Add migration ci check --- .github/workflows/ci-server.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 82540a48a40c..a838c04f5249 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -78,7 +78,20 @@ jobs: - name: Worker / Run if: steps.changed-files.outputs.any_changed == 'true' run: npx nx run twenty-server:worker:ci - + - name: Server / Check for Pending Migrations + if: steps.changed-files.outputs.any_changed == 'true' + run: | + CORE_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate core-migration-check -d src/database/typeorm/core/core.datasource.ts || true) + METADATA_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate metadata-migration-check -d src/database/typeorm/metadata/metadata.datasource.ts || true) + CORE_MIGRATION_FILES=$(find . -name "core-migration-check*.ts" | wc -l) + METADATA_MIGRATION_FILES=$(find . -name "metadata-migration-check*.ts" | wc -l) + + if [ "$CORE_MIGRATION_FILES" -gt 0 ] || [ "$METADATA_MIGRATION_FILES" -gt 0 ]; then + echo "::error::Unexpected migration files were generated. Please create a proper migration manually." + echo "$CORE_MIGRATION_OUTPUT" + echo "$METADATA_MIGRATION_OUTPUT" + exit 1 + fi server-test: timeout-minutes: 30 runs-on: ubuntu-latest From 9b9e2284f02fed2cb9d4fd27ede5e340c6b046a7 Mon Sep 17 00:00:00 2001 From: Weiko Date: Wed, 4 Dec 2024 11:51:17 +0100 Subject: [PATCH 02/13] add cleanup --- .github/workflows/ci-server.yaml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index a838c04f5249..0dd8ba44e65c 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -79,19 +79,25 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' run: npx nx run twenty-server:worker:ci - name: Server / Check for Pending Migrations - if: steps.changed-files.outputs.any_changed == 'true' - run: | - CORE_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate core-migration-check -d src/database/typeorm/core/core.datasource.ts || true) - METADATA_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate metadata-migration-check -d src/database/typeorm/metadata/metadata.datasource.ts || true) - CORE_MIGRATION_FILES=$(find . -name "core-migration-check*.ts" | wc -l) - METADATA_MIGRATION_FILES=$(find . -name "metadata-migration-check*.ts" | wc -l) + if: steps.changed-files.outputs.any_changed == 'true' + run: | + METADATA_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate metadata-migration-check -d src/database/typeorm/metadata/metadata.datasource.ts || true) + + CORE_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate core-migration-check -d src/database/typeorm/core/core.datasource.ts || true) + + METADATA_MIGRATION_FILE=$(ls *metadata-migration-check.ts 2>/dev/null || echo "") + CORE_MIGRATION_FILE=$(ls *core-migration-check.ts 2>/dev/null || echo "") + + if [ -n "$METADATA_MIGRATION_FILE" ] || [ -n "$CORE_MIGRATION_FILE" ]; then + echo "::error::Unexpected migration files were generated. Please create a proper migration manually." + echo "$METADATA_MIGRATION_OUTPUT" + echo "$CORE_MIGRATION_OUTPUT" + + rm -f *metadata-migration-check.ts *core-migration-check.ts - if [ "$CORE_MIGRATION_FILES" -gt 0 ] || [ "$METADATA_MIGRATION_FILES" -gt 0 ]; then - echo "::error::Unexpected migration files were generated. Please create a proper migration manually." - echo "$CORE_MIGRATION_OUTPUT" - echo "$METADATA_MIGRATION_OUTPUT" - exit 1 - fi + exit 1 + fi + server-test: timeout-minutes: 30 runs-on: ubuntu-latest From bf412ea3030bd6c813ef28a261981ce4e13e1e8a Mon Sep 17 00:00:00 2001 From: Weiko Date: Wed, 4 Dec 2024 11:56:56 +0100 Subject: [PATCH 03/13] test trigger --- .../database/typeorm-seeds/core/workspaces.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts index d3dceb8a883e..ef269b930157 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts @@ -36,15 +36,15 @@ export const seedWorkspaces = async ( logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png', activationStatus: WorkspaceActivationStatus.ACTIVE, }, - [SEED_ACME_WORKSPACE_ID]: { - id: workspaceId, - displayName: 'Acme', - domainName: 'acme.dev', - subdomain: 'acme', - inviteHash: 'acme.dev-invite-hash', - logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png', - activationStatus: WorkspaceActivationStatus.ACTIVE, - }, + // [SEED_ACME_WORKSPACE_ID]: { + // id: workspaceId, + // displayName: 'Acme', + // domainName: 'acme.dev', + // subdomain: 'acme', + // inviteHash: 'acme.dev-invite-hash', + // logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png', + // activationStatus: WorkspaceActivationStatus.ACTIVE, + // }, }; await workspaceDataSource From c017ebc72cf3c39093abe6353d6cc685cb7183d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 4 Dec 2024 13:43:40 +0100 Subject: [PATCH 04/13] Fix path --- .github/workflows/ci-server.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 0dd8ba44e65c..9077eefee98a 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -85,15 +85,15 @@ jobs: CORE_MIGRATION_OUTPUT=$(npx nx run twenty-server:typeorm migration:generate core-migration-check -d src/database/typeorm/core/core.datasource.ts || true) - METADATA_MIGRATION_FILE=$(ls *metadata-migration-check.ts 2>/dev/null || echo "") - CORE_MIGRATION_FILE=$(ls *core-migration-check.ts 2>/dev/null || echo "") + METADATA_MIGRATION_FILE=$(ls packages/twenty-server/*metadata-migration-check.ts 2>/dev/null || echo "") + CORE_MIGRATION_FILE=$(ls packages/twenty-server/*core-migration-check.ts 2>/dev/null || echo "") if [ -n "$METADATA_MIGRATION_FILE" ] || [ -n "$CORE_MIGRATION_FILE" ]; then echo "::error::Unexpected migration files were generated. Please create a proper migration manually." echo "$METADATA_MIGRATION_OUTPUT" echo "$CORE_MIGRATION_OUTPUT" - rm -f *metadata-migration-check.ts *core-migration-check.ts + rm -f packages/twenty-server/*metadata-migration-check.ts packages/twenty-server/*core-migration-check.ts exit 1 fi From 64e4c986bf8f1dbfa0dafcef508710ab5c693583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 4 Dec 2024 14:14:52 +0100 Subject: [PATCH 05/13] Fix --- .../1733318043626-sso-missing-migration.ts | 68 +++++++++++++++++++ ...733318004066-missing-shortcut-migration.ts | 14 ++++ 2 files changed, 82 insertions(+) create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts create mode 100644 packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts new file mode 100644 index 000000000000..391d754ffc52 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts @@ -0,0 +1,68 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class SsoMissingMigration1733318043626 implements MigrationInterface { + name = 'SsoMissingMigration1733318043626' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_workspaceId"`); + await queryRunner.query(`DROP INDEX "core"."apptoken_unique_invitation_by_user_workspace"`); + await queryRunner.query(`DROP INDEX "core"."workspace_subdomain_unique_index"`); + await queryRunner.query(`ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdIsNullWhenTypeIsInvitation"`); + await queryRunner.query(`ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation"`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_OIDC"`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_SAML"`); + await queryRunner.query(`ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`); + await queryRunner.query(`CREATE TYPE "core"."workspaceSSOIdentityProvider_status_enum" AS ENUM('Active', 'Inactive', 'Error')`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" "core"."workspaceSSOIdentityProvider_status_enum" NOT NULL DEFAULT 'Active'`); + await queryRunner.query(`ALTER TYPE "core"."idp_type_enum" RENAME TO "idp_type_enum_old"`); + await queryRunner.query(`CREATE TYPE "core"."workspaceSSOIdentityProvider_type_enum" AS ENUM('OIDC', 'SAML')`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."workspaceSSOIdentityProvider_type_enum" USING "type"::"text"::"core"."workspaceSSOIdentityProvider_type_enum"`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`); + await queryRunner.query(`DROP TYPE "core"."idp_type_enum_old"`); + await queryRunner.query(`ALTER TYPE "core"."workspace_activationStatus_enum" RENAME TO "workspace_activationStatus_enum_old"`); + await queryRunner.query(`CREATE TYPE "core"."workspace_activationstatus_enum" AS ENUM('ONGOING_CREATION', 'PENDING_CREATION', 'ACTIVE', 'INACTIVE')`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationstatus_enum" USING "activationStatus"::"text"::"core"."workspace_activationstatus_enum"`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`); + await queryRunner.query(`DROP TYPE "core"."workspace_activationStatus_enum_old"`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93"`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" DROP NOT NULL`); + await queryRunner.query(`CREATE TYPE "core"."workspace_activationStatus_enum_old" AS ENUM('PENDING_CREATION', 'ONGOING_CREATION', 'ACTIVE', 'INACTIVE')`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationStatus_enum_old" USING "activationStatus"::"text"::"core"."workspace_activationStatus_enum_old"`); + await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`); + await queryRunner.query(`DROP TYPE "core"."workspace_activationstatus_enum"`); + await queryRunner.query(`ALTER TYPE "core"."workspace_activationStatus_enum_old" RENAME TO "workspace_activationStatus_enum"`); + await queryRunner.query(`CREATE TYPE "core"."idp_type_enum_old" AS ENUM('OIDC', 'SAML')`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."idp_type_enum_old" USING "type"::"text"::"core"."idp_type_enum_old"`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`); + await queryRunner.query(`DROP TYPE "core"."workspaceSSOIdentityProvider_type_enum"`); + await queryRunner.query(`ALTER TYPE "core"."idp_type_enum_old" RENAME TO "idp_type_enum"`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`); + await queryRunner.query(`DROP TYPE "core"."workspaceSSOIdentityProvider_status_enum"`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" character varying NOT NULL DEFAULT 'Active'`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_SAML" CHECK ((((type = 'SAML'::core.idp_type_enum) AND ("ssoURL" IS NOT NULL) AND (certificate IS NOT NULL)) OR (type = 'OIDC'::core.idp_type_enum)))`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_OIDC" CHECK ((((type = 'OIDC'::core.idp_type_enum) AND ("clientID" IS NOT NULL) AND ("clientSecret" IS NOT NULL)) OR (type = 'SAML'::core.idp_type_enum)))`); + await queryRunner.query(`ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation" CHECK (((type = 'INVITATION_TOKEN'::text) OR ("userId" IS NOT NULL)))`); + await queryRunner.query(`ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdIsNullWhenTypeIsInvitation" CHECK (((type <> 'INVITATION_TOKEN'::text) OR ("userId" IS NULL)))`); + await queryRunner.query(`CREATE UNIQUE INDEX "workspace_subdomain_unique_index" ON "core"."workspace" ("subdomain") `); + await queryRunner.query(`CREATE UNIQUE INDEX "apptoken_unique_invitation_by_user_workspace" ON "core"."appToken" ("workspaceId") WHERE (type = 'INVITATION_TOKEN'::text)`); + await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_workspaceId" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + +} diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts new file mode 100644 index 000000000000..2d275ff669ec --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MissingShortcutMigration1733318004066 implements MigrationInterface { + name = 'MissingShortcutMigration1733318004066' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "metadata"."IDX_objectMetadata_shortcut_upper_workspace"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_objectMetadata_shortcut_upper_workspace" ON "metadata"."objectMetadata" ("workspaceId") `); + } + +} From 22690f2885215efe570d699b60388a484badd275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 4 Dec 2024 15:39:04 +0100 Subject: [PATCH 06/13] Lint --- .../1733318043626-sso-missing-migration.ts | 235 +++++++++++++----- ...733318004066-missing-shortcut-migration.ts | 25 +- 2 files changed, 187 insertions(+), 73 deletions(-) diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts index 391d754ffc52..5b4b49b72b34 100644 --- a/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts +++ b/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts @@ -1,68 +1,177 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; export class SsoMissingMigration1733318043626 implements MigrationInterface { - name = 'SsoMissingMigration1733318043626' + name = 'SsoMissingMigration1733318043626'; - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_workspaceId"`); - await queryRunner.query(`DROP INDEX "core"."apptoken_unique_invitation_by_user_workspace"`); - await queryRunner.query(`DROP INDEX "core"."workspace_subdomain_unique_index"`); - await queryRunner.query(`ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdIsNullWhenTypeIsInvitation"`); - await queryRunner.query(`ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation"`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_OIDC"`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_SAML"`); - await queryRunner.query(`ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`); - await queryRunner.query(`CREATE TYPE "core"."workspaceSSOIdentityProvider_status_enum" AS ENUM('Active', 'Inactive', 'Error')`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" "core"."workspaceSSOIdentityProvider_status_enum" NOT NULL DEFAULT 'Active'`); - await queryRunner.query(`ALTER TYPE "core"."idp_type_enum" RENAME TO "idp_type_enum_old"`); - await queryRunner.query(`CREATE TYPE "core"."workspaceSSOIdentityProvider_type_enum" AS ENUM('OIDC', 'SAML')`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."workspaceSSOIdentityProvider_type_enum" USING "type"::"text"::"core"."workspaceSSOIdentityProvider_type_enum"`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`); - await queryRunner.query(`DROP TYPE "core"."idp_type_enum_old"`); - await queryRunner.query(`ALTER TYPE "core"."workspace_activationStatus_enum" RENAME TO "workspace_activationStatus_enum_old"`); - await queryRunner.query(`CREATE TYPE "core"."workspace_activationstatus_enum" AS ENUM('ONGOING_CREATION', 'PENDING_CREATION', 'ACTIVE', 'INACTIVE')`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationstatus_enum" USING "activationStatus"::"text"::"core"."workspace_activationstatus_enum"`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`); - await queryRunner.query(`DROP TYPE "core"."workspace_activationStatus_enum_old"`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93"`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" DROP NOT NULL`); - await queryRunner.query(`CREATE TYPE "core"."workspace_activationStatus_enum_old" AS ENUM('PENDING_CREATION', 'ONGOING_CREATION', 'ACTIVE', 'INACTIVE')`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationStatus_enum_old" USING "activationStatus"::"text"::"core"."workspace_activationStatus_enum_old"`); - await queryRunner.query(`ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`); - await queryRunner.query(`DROP TYPE "core"."workspace_activationstatus_enum"`); - await queryRunner.query(`ALTER TYPE "core"."workspace_activationStatus_enum_old" RENAME TO "workspace_activationStatus_enum"`); - await queryRunner.query(`CREATE TYPE "core"."idp_type_enum_old" AS ENUM('OIDC', 'SAML')`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."idp_type_enum_old" USING "type"::"text"::"core"."idp_type_enum_old"`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`); - await queryRunner.query(`DROP TYPE "core"."workspaceSSOIdentityProvider_type_enum"`); - await queryRunner.query(`ALTER TYPE "core"."idp_type_enum_old" RENAME TO "idp_type_enum"`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`); - await queryRunner.query(`DROP TYPE "core"."workspaceSSOIdentityProvider_status_enum"`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" character varying NOT NULL DEFAULT 'Active'`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_SAML" CHECK ((((type = 'SAML'::core.idp_type_enum) AND ("ssoURL" IS NOT NULL) AND (certificate IS NOT NULL)) OR (type = 'OIDC'::core.idp_type_enum)))`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_OIDC" CHECK ((((type = 'OIDC'::core.idp_type_enum) AND ("clientID" IS NOT NULL) AND ("clientSecret" IS NOT NULL)) OR (type = 'SAML'::core.idp_type_enum)))`); - await queryRunner.query(`ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation" CHECK (((type = 'INVITATION_TOKEN'::text) OR ("userId" IS NOT NULL)))`); - await queryRunner.query(`ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdIsNullWhenTypeIsInvitation" CHECK (((type <> 'INVITATION_TOKEN'::text) OR ("userId" IS NULL)))`); - await queryRunner.query(`CREATE UNIQUE INDEX "workspace_subdomain_unique_index" ON "core"."workspace" ("subdomain") `); - await queryRunner.query(`CREATE UNIQUE INDEX "apptoken_unique_invitation_by_user_workspace" ON "core"."appToken" ("workspaceId") WHERE (type = 'INVITATION_TOKEN'::text)`); - await queryRunner.query(`ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_workspaceId" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_workspaceId"`, + ); + await queryRunner.query( + `DROP INDEX "core"."apptoken_unique_invitation_by_user_workspace"`, + ); + await queryRunner.query( + `DROP INDEX "core"."workspace_subdomain_unique_index"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdIsNullWhenTypeIsInvitation"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."appToken" DROP CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_OIDC"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_SAML"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`, + ); + await queryRunner.query( + `CREATE TYPE "core"."workspaceSSOIdentityProvider_status_enum" AS ENUM('Active', 'Inactive', 'Error')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" "core"."workspaceSSOIdentityProvider_status_enum" NOT NULL DEFAULT 'Active'`, + ); + await queryRunner.query( + `ALTER TYPE "core"."idp_type_enum" RENAME TO "idp_type_enum_old"`, + ); + await queryRunner.query( + `CREATE TYPE "core"."workspaceSSOIdentityProvider_type_enum" AS ENUM('OIDC', 'SAML')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."workspaceSSOIdentityProvider_type_enum" USING "type"::"text"::"core"."workspaceSSOIdentityProvider_type_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`, + ); + await queryRunner.query(`DROP TYPE "core"."idp_type_enum_old"`); + await queryRunner.query( + `ALTER TYPE "core"."workspace_activationStatus_enum" RENAME TO "workspace_activationStatus_enum_old"`, + ); + await queryRunner.query( + `CREATE TYPE "core"."workspace_activationstatus_enum" AS ENUM('ONGOING_CREATION', 'PENDING_CREATION', 'ACTIVE', 'INACTIVE')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationstatus_enum" USING "activationStatus"::"text"::"core"."workspace_activationstatus_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`, + ); + await queryRunner.query( + `DROP TYPE "core"."workspace_activationStatus_enum_old"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "FK_bc8d8855198de1fbc32fba8df93"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "isMicrosoftAuthEnabled" DROP NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "isPasswordAuthEnabled" DROP NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "isGoogleAuthEnabled" DROP NOT NULL`, + ); + await queryRunner.query( + `CREATE TYPE "core"."workspace_activationStatus_enum_old" AS ENUM('PENDING_CREATION', 'ONGOING_CREATION', 'ACTIVE', 'INACTIVE')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" TYPE "core"."workspace_activationStatus_enum_old" USING "activationStatus"::"text"::"core"."workspace_activationStatus_enum_old"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspace" ALTER COLUMN "activationStatus" SET DEFAULT 'INACTIVE'`, + ); + await queryRunner.query( + `DROP TYPE "core"."workspace_activationstatus_enum"`, + ); + await queryRunner.query( + `ALTER TYPE "core"."workspace_activationStatus_enum_old" RENAME TO "workspace_activationStatus_enum"`, + ); + await queryRunner.query( + `CREATE TYPE "core"."idp_type_enum_old" AS ENUM('OIDC', 'SAML')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" TYPE "core"."idp_type_enum_old" USING "type"::"text"::"core"."idp_type_enum_old"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "type" SET DEFAULT 'OIDC'`, + ); + await queryRunner.query( + `DROP TYPE "core"."workspaceSSOIdentityProvider_type_enum"`, + ); + await queryRunner.query( + `ALTER TYPE "core"."idp_type_enum_old" RENAME TO "idp_type_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP COLUMN "status"`, + ); + await queryRunner.query( + `DROP TYPE "core"."workspaceSSOIdentityProvider_status_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD "status" character varying NOT NULL DEFAULT 'Active'`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" DROP NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" DROP NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_SAML" CHECK ((((type = 'SAML'::core.idp_type_enum) AND ("ssoURL" IS NOT NULL) AND (certificate IS NOT NULL)) OR (type = 'OIDC'::core.idp_type_enum)))`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_OIDC" CHECK ((((type = 'OIDC'::core.idp_type_enum) AND ("clientID" IS NOT NULL) AND ("clientSecret" IS NOT NULL)) OR (type = 'SAML'::core.idp_type_enum)))`, + ); + await queryRunner.query( + `ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdNotNullWhenTypeIsNotInvitation" CHECK (((type = 'INVITATION_TOKEN'::text) OR ("userId" IS NOT NULL)))`, + ); + await queryRunner.query( + `ALTER TABLE "core"."appToken" ADD CONSTRAINT "userIdIsNullWhenTypeIsInvitation" CHECK (((type <> 'INVITATION_TOKEN'::text) OR ("userId" IS NULL)))`, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "workspace_subdomain_unique_index" ON "core"."workspace" ("subdomain") `, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "apptoken_unique_invitation_by_user_workspace" ON "core"."appToken" ("workspaceId") WHERE (type = 'INVITATION_TOKEN'::text)`, + ); + await queryRunner.query( + `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "FK_workspaceId" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } } diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts index 2d275ff669ec..d0b7ea867207 100644 --- a/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1733318004066-missing-shortcut-migration.ts @@ -1,14 +1,19 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; -export class MissingShortcutMigration1733318004066 implements MigrationInterface { - name = 'MissingShortcutMigration1733318004066' +export class MissingShortcutMigration1733318004066 + implements MigrationInterface +{ + name = 'MissingShortcutMigration1733318004066'; - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "metadata"."IDX_objectMetadata_shortcut_upper_workspace"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_objectMetadata_shortcut_upper_workspace" ON "metadata"."objectMetadata" ("workspaceId") `); - } + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX "metadata"."IDX_objectMetadata_shortcut_upper_workspace"`, + ); + } + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_objectMetadata_shortcut_upper_workspace" ON "metadata"."objectMetadata" ("workspaceId") `, + ); + } } From cd12693e68c24afc6aa4b3c8fffbf0310e6b5503 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 12:02:34 +0100 Subject: [PATCH 07/13] fix migration --- .../database/typeorm-seeds/core/workspaces.ts | 18 +++++++++--------- .../1733318043626-sso-missing-migration.ts | 6 ------ .../key-value-pair/key-value-pair.entity.ts | 4 ++-- 3 files changed, 11 insertions(+), 17 deletions(-) rename packages/twenty-server/src/database/typeorm/core/migrations/{ => common}/1733318043626-sso-missing-migration.ts (96%) diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts index ef269b930157..d3dceb8a883e 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts @@ -36,15 +36,15 @@ export const seedWorkspaces = async ( logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png', activationStatus: WorkspaceActivationStatus.ACTIVE, }, - // [SEED_ACME_WORKSPACE_ID]: { - // id: workspaceId, - // displayName: 'Acme', - // domainName: 'acme.dev', - // subdomain: 'acme', - // inviteHash: 'acme.dev-invite-hash', - // logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png', - // activationStatus: WorkspaceActivationStatus.ACTIVE, - // }, + [SEED_ACME_WORKSPACE_ID]: { + id: workspaceId, + displayName: 'Acme', + domainName: 'acme.dev', + subdomain: 'acme', + inviteHash: 'acme.dev-invite-hash', + logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png', + activationStatus: WorkspaceActivationStatus.ACTIVE, + }, }; await workspaceDataSource diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1733318043626-sso-missing-migration.ts similarity index 96% rename from packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts rename to packages/twenty-server/src/database/typeorm/core/migrations/common/1733318043626-sso-missing-migration.ts index 5b4b49b72b34..e89fd3453a59 100644 --- a/packages/twenty-server/src/database/typeorm/core/migrations/1733318043626-sso-missing-migration.ts +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1733318043626-sso-missing-migration.ts @@ -25,9 +25,6 @@ export class SsoMissingMigration1733318043626 implements MigrationInterface { await queryRunner.query( `ALTER TABLE "core"."workspaceSSOIdentityProvider" DROP CONSTRAINT "CHK_SAML"`, ); - await queryRunner.query( - `ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" SET NOT NULL`, - ); await queryRunner.query( `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" SET NOT NULL`, ); @@ -149,9 +146,6 @@ export class SsoMissingMigration1733318043626 implements MigrationInterface { await queryRunner.query( `ALTER TABLE "core"."workspaceSSOIdentityProvider" ALTER COLUMN "name" DROP NOT NULL`, ); - await queryRunner.query( - `ALTER TABLE "core"."keyValuePair" ALTER COLUMN "textValueDeprecated" DROP NOT NULL`, - ); await queryRunner.query( `ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_SAML" CHECK ((((type = 'SAML'::core.idp_type_enum) AND ("ssoURL" IS NOT NULL) AND (certificate IS NOT NULL)) OR (type = 'OIDC'::core.idp_type_enum)))`, ); diff --git a/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts b/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts index b346001067c3..d9f947255784 100644 --- a/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts @@ -67,8 +67,8 @@ export class KeyValuePair { value: JSON; @Field(() => String) - @Column({ nullable: false, type: 'text' }) - textValueDeprecated: string; + @Column({ nullable: true, type: 'text' }) + textValueDeprecated: string | null; @Field(() => KeyValuePairType) @Column({ From 203ac2e9540f4db9a4265a8b21e66faad1119be3 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 15:14:58 +0100 Subject: [PATCH 08/13] remove billing FK with core tables --- .../database/typeorm/core/core.datasource.ts | 9 ++++-- .../1733753649142-removeBillingFKWithCore.ts | 31 +++++++++++++++++++ .../entities/billing-customer.entity.ts | 9 ------ .../entities/billing-entitlement.entity.ts | 7 ----- .../entities/billing-subscription.entity.ts | 7 ----- .../workspace/workspace.entity.ts | 18 ----------- 6 files changed, 37 insertions(+), 44 deletions(-) create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/1733753649142-removeBillingFKWithCore.ts diff --git a/packages/twenty-server/src/database/typeorm/core/core.datasource.ts b/packages/twenty-server/src/database/typeorm/core/core.datasource.ts index 0c052261c71a..1a6bd9ec6aa2 100644 --- a/packages/twenty-server/src/database/typeorm/core/core.datasource.ts +++ b/packages/twenty-server/src/database/typeorm/core/core.datasource.ts @@ -11,9 +11,12 @@ export const typeORMCoreModuleOptions: TypeOrmModuleOptions = { type: 'postgres', logging: ['error'], schema: 'core', - entities: [ - `${isJest ? '' : 'dist/'}src/engine/core-modules/**/*.entity{.ts,.js}`, - ], + entities: + process.env.IS_BILLING_ENABLED === 'true' + ? [`${isJest ? '' : 'dist/'}src/engine/core-modules/**/*.entity{.ts,.js}`] + : [ + `${isJest ? '' : 'dist/'}src/engine/core-modules/**/!(billing-*).entity{.ts,.js}`, + ], synchronize: false, migrationsRun: false, migrationsTableName: '_typeorm_migrations', diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/1733753649142-removeBillingFKWithCore.ts b/packages/twenty-server/src/database/typeorm/core/migrations/1733753649142-removeBillingFKWithCore.ts new file mode 100644 index 000000000000..1892627b6145 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/1733753649142-removeBillingFKWithCore.ts @@ -0,0 +1,31 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveBillingFKWithCore1733753649142 + implements MigrationInterface +{ + name = 'RemoveBillingFKWithCore1733753649142'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."billingEntitlement" DROP CONSTRAINT "FK_599121a93d8177b5d713b941982"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" DROP CONSTRAINT "FK_4abfb70314c18da69e1bee1954d"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingCustomer" DROP CONSTRAINT "FK_53c2ef50e9611082f83d760897d"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."billingCustomer" ADD CONSTRAINT "FK_53c2ef50e9611082f83d760897d" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingSubscription" ADD CONSTRAINT "FK_4abfb70314c18da69e1bee1954d" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "core"."billingEntitlement" ADD CONSTRAINT "FK_599121a93d8177b5d713b941982" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-customer.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-customer.entity.ts index f1b237b7ccc5..3b0b8be801ea 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-customer.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-customer.entity.ts @@ -5,8 +5,6 @@ import { Column, CreateDateColumn, Entity, - JoinColumn, - ManyToOne, OneToMany, PrimaryGeneratedColumn, Relation, @@ -17,7 +15,6 @@ import { import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { BillingEntitlement } from 'src/engine/core-modules/billing/entities/billing-entitlement.entity'; import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @Entity({ name: 'billingCustomer', schema: 'core' }) @ObjectType('billingCustomer') @@ -39,12 +36,6 @@ export class BillingCustomer { @UpdateDateColumn({ type: 'timestamptz' }) updatedAt: Date; - @ManyToOne(() => Workspace, (workspace) => workspace.billingCustomers, { - onDelete: 'CASCADE', - }) - @JoinColumn() - workspace: Relation; - @Column({ nullable: false, type: 'uuid' }) workspaceId: string; diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts index 927281f3ef0d..84ed85260b08 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts @@ -16,7 +16,6 @@ import { import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.entity'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @Entity({ name: 'billingEntitlement', schema: 'core' }) @ObjectType('billingEntitlement') @Unique('IndexOnFeatureKeyAndWorkspaceIdUnique', ['key', 'workspaceId']) @@ -33,12 +32,6 @@ export class BillingEntitlement { @Column({ nullable: false, type: 'uuid' }) workspaceId: string; - @ManyToOne(() => Workspace, (workspace) => workspace.billingEntitlements, { - onDelete: 'CASCADE', - }) - @JoinColumn() - workspace: Relation; - @Column({ nullable: false }) stripeCustomerId: string; diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts index e80d97bd27f2..d2ed20e5bc5c 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts @@ -20,7 +20,6 @@ import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entitie import { BillingSubscriptionCollectionMethod } from 'src/engine/core-modules/billing/enums/billing-subscription-collection-method.enum'; import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/billing-subscription-interval.enum'; import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum'; -import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' }); registerEnumType(SubscriptionInterval, { name: 'SubscriptionInterval' }); @@ -41,12 +40,6 @@ export class BillingSubscription { @UpdateDateColumn({ type: 'timestamptz' }) updatedAt: Date; - @ManyToOne(() => Workspace, (workspace) => workspace.billingSubscriptions, { - onDelete: 'CASCADE', - }) - @JoinColumn() - workspace: Relation; - @Column({ nullable: false, type: 'uuid' }) workspaceId: string; diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index 0380f4243ac6..b80ecad5ecce 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -119,24 +119,6 @@ export class Workspace { }) activationStatus: WorkspaceActivationStatus; - @OneToMany( - () => BillingSubscription, - (billingSubscription) => billingSubscription.workspace, - ) - billingSubscriptions: Relation; - - @OneToMany( - () => BillingCustomer, - (billingCustomer) => billingCustomer.workspace, - ) - billingCustomers: Relation; - - @OneToMany( - () => BillingEntitlement, - (billingEntitlement) => billingEntitlement.workspace, - ) - billingEntitlements: Relation; - @OneToMany( () => PostgresCredentials, (postgresCredentials) => postgresCredentials.workspace, From 2f127ba271e9878dc8478f485ba32e1e76d2ad9e Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 15:18:57 +0100 Subject: [PATCH 09/13] add run migration step --- .github/workflows/ci-server.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 9077eefee98a..76cb9634e165 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -75,6 +75,11 @@ jobs: run: | PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";' PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' + - name: Server / Run migrations + if: steps.changed-files.outputs.any_changed == 'true' + run: | + npx nx typeorm -- migration:run -d src/database/typeorm/core/core.datasource.ts + npx nx typeorm -- migration:run -d src/database/typeorm/metadata/metadata.datasource.ts - name: Worker / Run if: steps.changed-files.outputs.any_changed == 'true' run: npx nx run twenty-server:worker:ci From ea18118f9bb25fee9da6cecb3e683139eec69252 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 15:24:24 +0100 Subject: [PATCH 10/13] fix --- .github/workflows/ci-server.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 76cb9634e165..4267b6059a54 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -78,8 +78,8 @@ jobs: - name: Server / Run migrations if: steps.changed-files.outputs.any_changed == 'true' run: | - npx nx typeorm -- migration:run -d src/database/typeorm/core/core.datasource.ts - npx nx typeorm -- migration:run -d src/database/typeorm/metadata/metadata.datasource.ts + npx nx run twenty-server:typeorm -- migration:run -d src/database/typeorm/core/core.datasource.ts + npx nx run twenty-server:typeorm -- migration:run -d src/database/typeorm/metadata/metadata.datasource.ts - name: Worker / Run if: steps.changed-files.outputs.any_changed == 'true' run: npx nx run twenty-server:worker:ci From 12c43949d0a7ffa110650c4f63c02ab9e0ebcb31 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 15:43:30 +0100 Subject: [PATCH 11/13] fix --- .github/workflows/ci-server.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-server.yaml b/.github/workflows/ci-server.yaml index 4267b6059a54..54e0fd112da1 100644 --- a/.github/workflows/ci-server.yaml +++ b/.github/workflows/ci-server.yaml @@ -75,11 +75,8 @@ jobs: run: | PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";' PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' - - name: Server / Run migrations - if: steps.changed-files.outputs.any_changed == 'true' - run: | - npx nx run twenty-server:typeorm -- migration:run -d src/database/typeorm/core/core.datasource.ts - npx nx run twenty-server:typeorm -- migration:run -d src/database/typeorm/metadata/metadata.datasource.ts + npx nx run twenty-server:database:init:prod + npx nx run twenty-server:database:migrate:prod - name: Worker / Run if: steps.changed-files.outputs.any_changed == 'true' run: npx nx run twenty-server:worker:ci From 464f14f435830d160a241b41b88c18bc9deddf9b Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 15:50:53 +0100 Subject: [PATCH 12/13] Test if CI fails without migration --- .../src/engine/core-modules/workspace/workspace.entity.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index b80ecad5ecce..221c4475299d 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -143,6 +143,9 @@ export class Workspace { @Column({ default: '' }) databaseSchema: string; + @Column({ default: '' }) + testColumnForCICheck: string; + @Field() @Column() subdomain: string; From e657d2f821c9d8eb42dcad74f6097ea3f25cca66 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 9 Dec 2024 15:55:10 +0100 Subject: [PATCH 13/13] remove test now that it s working --- .../src/engine/core-modules/workspace/workspace.entity.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index 221c4475299d..b80ecad5ecce 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -143,9 +143,6 @@ export class Workspace { @Column({ default: '' }) databaseSchema: string; - @Column({ default: '' }) - testColumnForCICheck: string; - @Field() @Column() subdomain: string;