mirror of
				https://github.com/lingble/twenty.git
				synced 2025-10-30 20:27:55 +00:00 
			
		
		
		
	[Emails migration] Fix email field migration (#7065)
Fix email field migration - Remove deprecated field of type Email - Add standard emails field on person to person views in position 4
This commit is contained in:
		| @@ -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<Workspace>, | ||||||
|  |     @InjectRepository(FieldMetadataEntity, 'metadata') | ||||||
|  |     private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>, | ||||||
|  |     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<void> { | ||||||
|  |     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!`)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -4,6 +4,7 @@ import { Command } from 'nest-commander'; | |||||||
| import { Repository } from 'typeorm'; | import { Repository } from 'typeorm'; | ||||||
|  |  | ||||||
| import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command'; | 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 { 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 { 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'; | 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 syncWorkspaceMetadataCommand: SyncWorkspaceMetadataCommand, | ||||||
|     private readonly migrateEmailFieldsToEmails: MigrateEmailFieldsToEmailsCommand, |     private readonly migrateEmailFieldsToEmails: MigrateEmailFieldsToEmailsCommand, | ||||||
|     private readonly setStaleMessageSyncBackToPendingCommand: SetStaleMessageSyncBackToPendingCommand, |     private readonly setStaleMessageSyncBackToPendingCommand: SetStaleMessageSyncBackToPendingCommand, | ||||||
|  |     private readonly fixEmailFieldsToEmailsCommand: FixEmailFieldsToEmailsCommand, | ||||||
|   ) { |   ) { | ||||||
|     super(workspaceRepository); |     super(workspaceRepository); | ||||||
|   } |   } | ||||||
| @@ -51,5 +53,10 @@ export class UpgradeTo0_30Command extends ActiveWorkspacesCommandRunner { | |||||||
|       options, |       options, | ||||||
|       workspaceIds, |       workspaceIds, | ||||||
|     ); |     ); | ||||||
|  |     await this.fixEmailFieldsToEmailsCommand.executeActiveWorkspacesCommand( | ||||||
|  |       passedParam, | ||||||
|  |       options, | ||||||
|  |       workspaceIds, | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| import { Module } from '@nestjs/common'; | import { Module } from '@nestjs/common'; | ||||||
| import { TypeOrmModule } from '@nestjs/typeorm'; | 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 { 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 { 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'; | 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, |     UpgradeTo0_30Command, | ||||||
|     MigrateEmailFieldsToEmailsCommand, |     MigrateEmailFieldsToEmailsCommand, | ||||||
|     SetStaleMessageSyncBackToPendingCommand, |     SetStaleMessageSyncBackToPendingCommand, | ||||||
|  |     FixEmailFieldsToEmailsCommand, | ||||||
|   ], |   ], | ||||||
| }) | }) | ||||||
| export class UpgradeTo0_30CommandModule {} | export class UpgradeTo0_30CommandModule {} | ||||||
|   | |||||||
| @@ -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)); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Marie
					Marie