diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-backfill-workspace-version.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-backfill-workspace-version.command.ts new file mode 100644 index 000000000000..eec8dbe8a9c7 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-backfill-workspace-version.command.ts @@ -0,0 +1,59 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import { Repository } from 'typeorm'; + +import { BatchActiveWorkspacesMigrationCommandRunner } from 'src/database/commands/migration-command/batch-active-workspaces-migration-command.runner'; +import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; + +@MigrationCommand({ + name: 'backfill-workspace-version', + description: 'Backfill workspace version field to "0.43"', + version: '0.43', +}) +export class BackfillWorkspaceVersionCommand extends BatchActiveWorkspacesMigrationCommandRunner { + constructor( + @InjectRepository(Workspace, 'core') + protected readonly workspaceRepository: Repository, + protected readonly twentyORMGlobalManager: TwentyORMGlobalManager, + ) { + super(workspaceRepository, twentyORMGlobalManager); + } + + async runMigrationCommandOnWorkspace( + workspaceId: string, + index: number, + total: number, + ): Promise { + try { + this.logger.log( + `Running version backfill for workspace ${workspaceId} ${index + 1}/${total}`, + ); + + await this.backfillWorkspaceVersion(workspaceId); + + this.logger.log( + chalk.green(`Command completed for workspace ${workspaceId}.`), + ); + } catch (error) { + this.logger.log( + chalk.red(`Error in workspace ${workspaceId} - ${error.message}`), + ); + } + } + + private async backfillWorkspaceVersion(workspaceId: string): Promise { + await this.workspaceRepository.update( + { id: workspaceId }, + { version: '0.43' }, + ); + + this.logger.log( + chalk.green( + `Successfully backfilled version to "0.43" for workspace ${workspaceId}`, + ), + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-upgrade-version.module.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-upgrade-version.module.ts index 579c101e7e25..8342ec1540c4 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-upgrade-version.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-43/0-43-upgrade-version.module.ts @@ -4,6 +4,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { MigrationCommandModule } from 'src/database/commands/migration-command/miration-command.module'; import { StandardizationOfActorCompositeContextTypeCommand } from 'src/database/commands/upgrade-version/0-42/0-42-standardization-of-actor-composite-context-type'; import { AddTasksAssignedToMeViewCommand } from 'src/database/commands/upgrade-version/0-43/0-43-add-tasks-assigned-to-me-view.command'; +import { BackfillWorkspaceVersionCommand } from 'src/database/commands/upgrade-version/0-43/0-43-backfill-workspace-version.command'; import { MigrateRelationsToFieldMetadataCommand } from 'src/database/commands/upgrade-version/0-43/0-43-migrate-relations-to-field-metadata.command'; import { MigrateSearchVectorOnNoteAndTaskEntitiesCommand } from 'src/database/commands/upgrade-version/0-43/0-43-migrate-search-vector-on-note-and-task-entities.command'; import { UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand } from 'src/database/commands/upgrade-version/0-43/0-43-update-default-view-record-opening-on-workflow-objects.command'; @@ -32,6 +33,7 @@ import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/wor ], providers: [ AddTasksAssignedToMeViewCommand, + BackfillWorkspaceVersionCommand, MigrateSearchVectorOnNoteAndTaskEntitiesCommand, UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand, StandardizationOfActorCompositeContextTypeCommand, 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 2a48c2463c68..6d597282b7f6 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts @@ -1,6 +1,7 @@ import { WorkspaceActivationStatus } from 'twenty-shared'; import { DataSource } from 'typeorm'; +import { getAppVersion } from 'src/engine/core-modules/utils/version.util'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; const tableName = 'workspace'; @@ -22,6 +23,7 @@ export const seedWorkspaces = async ( | 'logo' | 'subdomain' | 'activationStatus' + | 'version' >; } = { [SEED_APPLE_WORKSPACE_ID]: { @@ -31,6 +33,7 @@ export const seedWorkspaces = async ( inviteHash: 'apple.dev-invite-hash', logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png', activationStatus: WorkspaceActivationStatus.ACTIVE, + version: getAppVersion(), }, [SEED_ACME_WORKSPACE_ID]: { id: workspaceId, @@ -39,6 +42,7 @@ export const seedWorkspaces = async ( inviteHash: 'acme.dev-invite-hash', logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png', activationStatus: WorkspaceActivationStatus.ACTIVE, + version: getAppVersion(), }, }; diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts index a8e7f0487523..26bb5132241c 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts @@ -38,6 +38,7 @@ import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { UserService } from 'src/engine/core-modules/user/services/user.service'; import { User } from 'src/engine/core-modules/user/user.entity'; +import { getAppVersion } from 'src/engine/core-modules/utils/version.util'; import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; @@ -356,6 +357,7 @@ export class SignInUpService { inviteHash: v4(), activationStatus: WorkspaceActivationStatus.PENDING_CREATION, logo, + version: getAppVersion(), }); const workspace = await this.workspaceRepository.save(workspaceToCreate); diff --git a/packages/twenty-server/src/engine/core-modules/utils/version.util.ts b/packages/twenty-server/src/engine/core-modules/utils/version.util.ts new file mode 100644 index 000000000000..25d683252723 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/utils/version.util.ts @@ -0,0 +1,13 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; + +export const getAppVersion = (): string | null => { + try { + const packageJsonPath = join(__dirname, '../../../../package.json'); + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')); + + return packageJson.version; + } catch (error) { + return null; + } +};