Move defaultAvatarUrl on userWorkspace + migration command (#12100)

closes https://github.com/twentyhq/core-team-issues/issues/883
This commit is contained in:
Etienne
2025-05-21 12:07:02 +02:00
committed by GitHub
parent 8e2d0139ed
commit 3702fefc89
13 changed files with 500 additions and 78 deletions

View File

@ -0,0 +1,87 @@
import { InjectRepository } from '@nestjs/typeorm';
import { isNonEmptyString } from '@sniptt/guards';
import { Command } from 'nest-commander';
import { Repository } from 'typeorm';
import {
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
RunOnWorkspaceArgs,
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
@Command({
name: 'upgrade:0-54:migrate-default-avatar-url-to-user-workspace',
description: 'Migrate default avatar url to user workspace',
})
export class MigrateDefaultAvatarUrlToUserWorkspaceCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@InjectRepository(UserWorkspace, 'core')
protected readonly userWorkspaceRepository: Repository<UserWorkspace>,
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {
super(workspaceRepository, twentyORMGlobalManager);
}
override async runOnWorkspace({
index,
total,
workspaceId,
options,
}: RunOnWorkspaceArgs): Promise<void> {
this.logger.log(
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
);
await this.migrateDefaultAvatarUrlToUserWorkspace({
workspaceId,
dryRun: !!options.dryRun,
});
}
private async migrateDefaultAvatarUrlToUserWorkspace({
workspaceId,
dryRun,
}: {
workspaceId: string;
dryRun: boolean;
}) {
const workspace = await this.workspaceRepository.findOneOrFail({
where: {
id: workspaceId,
},
relations: ['workspaceUsers', 'workspaceUsers.user'],
});
for (const workspaceUser of workspace.workspaceUsers) {
if (isNonEmptyString(workspaceUser.user.defaultAvatarUrl)) {
const userWorkspacesCount = await this.userWorkspaceRepository.count({
where: {
userId: workspaceUser.user.id,
},
});
if (userWorkspacesCount === 1) {
if (!dryRun)
await this.userWorkspaceRepository.update(
{
userId: workspaceUser.user.id,
workspaceId: workspace.id,
},
{
defaultAvatarUrl: workspaceUser.user.defaultAvatarUrl,
},
);
this.logger.log(
`Updated default avatar url for user ${workspaceUser.user.id} on user workspace ${workspaceUser.id}`,
);
}
}
}
}
}

View File

@ -5,8 +5,10 @@ import { CleanNotFoundFilesCommand } from 'src/database/commands/upgrade-version
import { FixCreatedByDefaultValueCommand } from 'src/database/commands/upgrade-version-command/0-54/0-54-created-by-default-value.command';
import { FixStandardSelectFieldsPositionCommand } from 'src/database/commands/upgrade-version-command/0-54/0-54-fix-standard-select-fields-position.command';
import { LowercaseUserAndInvitationEmailsCommand } from 'src/database/commands/upgrade-version-command/0-54/0-54-lowercase-user-and-invitation-emails.command';
import { MigrateDefaultAvatarUrlToUserWorkspaceCommand } from 'src/database/commands/upgrade-version-command/0-54/0-54-migrate-default-avatar-url-to-user-workspace.command';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { FileModule } from 'src/engine/core-modules/file/file.module';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@ -17,7 +19,10 @@ import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/wor
@Module({
imports: [
TypeOrmModule.forFeature([Workspace, AppToken, User], 'core'),
TypeOrmModule.forFeature(
[Workspace, AppToken, User, UserWorkspace],
'core',
),
TypeOrmModule.forFeature(
[FieldMetadataEntity, ObjectMetadataEntity],
'metadata',
@ -32,12 +37,14 @@ import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/wor
FixCreatedByDefaultValueCommand,
CleanNotFoundFilesCommand,
LowercaseUserAndInvitationEmailsCommand,
MigrateDefaultAvatarUrlToUserWorkspaceCommand,
],
exports: [
FixStandardSelectFieldsPositionCommand,
FixCreatedByDefaultValueCommand,
CleanNotFoundFilesCommand,
LowercaseUserAndInvitationEmailsCommand,
MigrateDefaultAvatarUrlToUserWorkspaceCommand,
],
})
export class V0_54_UpgradeVersionCommandModule {}

View File

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddDefaultAvatarUrlColumnInUserWorkspaceTable1747401483135
implements MigrationInterface
{
name = 'AddDefaultAvatarUrlColumnInUserWorkspaceTable1747401483135';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."userWorkspace" ADD "defaultAvatarUrl" character varying`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."userWorkspace" DROP COLUMN "defaultAvatarUrl"`,
);
}
}