diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-fix-email-field-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-fix-email-field-migration.command.ts new file mode 100644 index 0000000000..9356d7d920 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-fix-email-field-migration.command.ts @@ -0,0 +1,161 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import { isDefined } from 'class-validator'; +import { Command } from 'nest-commander'; +import { Repository } from 'typeorm'; + +import { + ActiveWorkspacesCommandOptions, + ActiveWorkspacesCommandRunner, +} from 'src/database/commands/active-workspaces.command'; +import { TypeORMService } from 'src/database/typeorm/typeorm.service'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service'; +import { PERSON_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { ViewService } from 'src/modules/view/services/view.service'; +@Command({ + name: 'upgrade-0.30:fix-email-field-migration', + description: + 'Fix migration - delete deprecated email fields and add emails to person views', +}) +export class FixEmailFieldsToEmailsCommand extends ActiveWorkspacesCommandRunner { + constructor( + @InjectRepository(Workspace, 'core') + protected readonly workspaceRepository: Repository, + @InjectRepository(FieldMetadataEntity, 'metadata') + private readonly fieldMetadataRepository: Repository, + private readonly fieldMetadataService: FieldMetadataService, + private readonly typeORMService: TypeORMService, + private readonly dataSourceService: DataSourceService, + private readonly viewService: ViewService, + ) { + super(workspaceRepository); + } + + async executeActiveWorkspacesCommand( + _passedParam: string[], + _options: ActiveWorkspacesCommandOptions, + workspaceIds: string[], + ): Promise { + this.logger.log('Running command to fix migration'); + + for (const workspaceId of workspaceIds) { + let dataSourceMetadata; + + this.logger.log(`Running command for workspace ${workspaceId}`); + try { + dataSourceMetadata = + await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceId( + workspaceId, + ); + + if (!dataSourceMetadata) { + throw new Error( + `Could not find dataSourceMetadata for workspace ${workspaceId}`, + ); + } + + const workspaceDataSource = + await this.typeORMService.connectToDataSource(dataSourceMetadata); + + if (!workspaceDataSource) { + throw new Error( + `Could not connect to dataSource for workspace ${workspaceId}`, + ); + } + } catch (error) { + this.logger.log( + chalk.red( + `Could not connect to workspace data source for workspace ${workspaceId}`, + ), + ); + continue; + } + + try { + const deprecatedPersonEmailFieldsMetadata = + await this.fieldMetadataRepository.findBy({ + standardId: PERSON_STANDARD_FIELD_IDS.email, + workspaceId: workspaceId, + }); + + const migratedEmailFieldMetadata = await this.fieldMetadataRepository + .findBy({ + standardId: PERSON_STANDARD_FIELD_IDS.emails, + workspaceId: workspaceId, + }) + .then((fields) => fields[0]); + + const personEmailFieldWasMigratedButHasDuplicate = + deprecatedPersonEmailFieldsMetadata.length > 0 && + isDefined(migratedEmailFieldMetadata); + + if (!personEmailFieldWasMigratedButHasDuplicate) { + this.logger.log( + chalk.yellow('No fields to migrate for workspace ' + workspaceId), + ); + continue; + } + + for (const deprecatedEmailFieldMetadata of deprecatedPersonEmailFieldsMetadata) { + await this.fieldMetadataService.deleteOneField( + { id: deprecatedEmailFieldMetadata.id }, + workspaceId, + ); + this.logger.log( + chalk.green(`Deleted email field for workspace ${workspaceId}.`), + ); + } + + const personObjectMetadaIdForWorkspace = + migratedEmailFieldMetadata.objectMetadataId; + + if (!isDefined(personObjectMetadaIdForWorkspace)) { + this.logger.log( + chalk.red( + `Could not find person object for workspace ${workspaceId}. Could not add emails to person view`, + ), + ); + continue; + } + + const personViewsIds = + await this.viewService.getViewsIdsForObjectMetadataId({ + workspaceId, + objectMetadataId: personObjectMetadaIdForWorkspace as string, + }); + + await this.viewService.addFieldToViews({ + workspaceId: workspaceId, + fieldId: migratedEmailFieldMetadata.id, + viewsIds: personViewsIds, + positions: personViewsIds.reduce((acc, personView) => { + if (!personView.id) { + return acc; + } + acc[personView.id] = 4; + + return acc; + }, []), + }); + this.logger.log(chalk.green(`Added emails to view ${workspaceId}.`)); + } catch (error) { + this.logger.log( + chalk.red( + `Running command on workspace ${workspaceId} failed with error: ${error}`, + ), + ); + continue; + } finally { + this.logger.log( + chalk.green(`Finished running command for workspace ${workspaceId}.`), + ); + } + + this.logger.log(chalk.green(`Command completed!`)); + } + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.command.ts index 4702e50fdc..7bf2a9ddd6 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.command.ts @@ -4,6 +4,7 @@ import { Command } from 'nest-commander'; import { Repository } from 'typeorm'; import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command'; +import { FixEmailFieldsToEmailsCommand } from 'src/database/commands/upgrade-version/0-30/0-30-fix-email-field-migration.command'; import { MigrateEmailFieldsToEmailsCommand } from 'src/database/commands/upgrade-version/0-30/0-30-migrate-email-fields-to-emails.command'; import { SetStaleMessageSyncBackToPendingCommand } from 'src/database/commands/upgrade-version/0-30/0-30-set-stale-message-sync-back-to-pending'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -24,6 +25,7 @@ export class UpgradeTo0_30Command extends ActiveWorkspacesCommandRunner { private readonly syncWorkspaceMetadataCommand: SyncWorkspaceMetadataCommand, private readonly migrateEmailFieldsToEmails: MigrateEmailFieldsToEmailsCommand, private readonly setStaleMessageSyncBackToPendingCommand: SetStaleMessageSyncBackToPendingCommand, + private readonly fixEmailFieldsToEmailsCommand: FixEmailFieldsToEmailsCommand, ) { super(workspaceRepository); } @@ -51,5 +53,10 @@ export class UpgradeTo0_30Command extends ActiveWorkspacesCommandRunner { options, workspaceIds, ); + await this.fixEmailFieldsToEmailsCommand.executeActiveWorkspacesCommand( + passedParam, + options, + workspaceIds, + ); } } diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.module.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.module.ts index ff4735ba27..7938ea4f90 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-30/0-30-upgrade-version.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { FixEmailFieldsToEmailsCommand } from 'src/database/commands/upgrade-version/0-30/0-30-fix-email-field-migration.command'; import { MigrateEmailFieldsToEmailsCommand } from 'src/database/commands/upgrade-version/0-30/0-30-migrate-email-fields-to-emails.command'; import { SetStaleMessageSyncBackToPendingCommand } from 'src/database/commands/upgrade-version/0-30/0-30-set-stale-message-sync-back-to-pending'; import { UpgradeTo0_30Command } from 'src/database/commands/upgrade-version/0-30/0-30-upgrade-version.command'; @@ -32,6 +33,7 @@ import { ViewModule } from 'src/modules/view/view.module'; UpgradeTo0_30Command, MigrateEmailFieldsToEmailsCommand, SetStaleMessageSyncBackToPendingCommand, + FixEmailFieldsToEmailsCommand, ], }) export class UpgradeTo0_30CommandModule {} diff --git a/packages/twenty-server/src/modules/view/services/view.service.ts b/packages/twenty-server/src/modules/view/services/view.service.ts index e889db41d1..92044d999c 100644 --- a/packages/twenty-server/src/modules/view/services/view.service.ts +++ b/packages/twenty-server/src/modules/view/services/view.service.ts @@ -98,4 +98,26 @@ export class ViewService { ); } } + + async getViewsIdsForObjectMetadataId({ + workspaceId, + objectMetadataId, + }: { + workspaceId: string; + objectMetadataId: string; + }) { + const viewRepository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + workspaceId, + 'view', + ); + + return viewRepository + .find({ + where: { + objectMetadataId: objectMetadataId, + }, + }) + .then((views) => views.map((view) => view.id)); + } }