From 3295f5ee0739fea6a1f3cbac28e2c89ae977eb2e Mon Sep 17 00:00:00 2001 From: neo773 <62795688+neo773@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:32:08 +0530 Subject: [PATCH] fix logo upload during workspace onboarding (#18905) Logo upload during onboarding failed because it required the Twenty Standard Application, which doesn't exist yet at that point We only need custom app's universalIdentifier (workspace.workspaceCustomApplicationId, available from sign up) so we can safely remove ApplicationService dependency https://github.com/user-attachments/assets/a18599ee-0b91-4629-ad77-2f708351449a /closes #18829 Co-authored-by: Charles Bochet --- .../file-core-picture.module.ts | 5 +- .../services/file-core-picture.service.ts | 52 +++++++++++-------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/file/file-core-picture/file-core-picture.module.ts b/packages/twenty-server/src/engine/core-modules/file/file-core-picture/file-core-picture.module.ts index fc545afac5..8235bb4e20 100644 --- a/packages/twenty-server/src/engine/core-modules/file/file-core-picture/file-core-picture.module.ts +++ b/packages/twenty-server/src/engine/core-modules/file/file-core-picture/file-core-picture.module.ts @@ -1,8 +1,6 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module'; import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity'; import { FileCorePictureResolver } from 'src/engine/core-modules/file/file-core-picture/resolvers/file-core-picture.resolver'; @@ -16,10 +14,9 @@ import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permi @Module({ imports: [ JwtModule, - TypeOrmModule.forFeature([FileEntity, WorkspaceEntity, ApplicationEntity]), + TypeOrmModule.forFeature([FileEntity, WorkspaceEntity]), PermissionsModule, FileStorageModule, - ApplicationModule, FileUrlModule, SecureHttpClientModule, ], diff --git a/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts b/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts index 808076ab82..a554e012fb 100644 --- a/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts +++ b/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts @@ -11,7 +11,10 @@ import { isDefined } from 'twenty-shared/utils'; import { Like, type QueryRunner, Repository } from 'typeorm'; import { v4 } from 'uuid'; -import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { + ApplicationException, + ApplicationExceptionCode, +} from 'src/engine/core-modules/application/application.exception'; import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { FileWithSignedUrlDTO } from 'src/engine/core-modules/file/dtos/file-with-sign-url.dto'; import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity'; @@ -29,7 +32,6 @@ export class FileCorePictureService { constructor( private readonly fileStorageService: FileStorageService, - private readonly applicationService: ApplicationService, @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, @InjectRepository(FileEntity) @@ -38,6 +40,25 @@ export class FileCorePictureService { private readonly secureHttpClientService: SecureHttpClientService, ) {} + private async findCustomApplicationUniversalIdentifier( + workspaceId: string, + ): Promise { + const workspace = await this.workspaceRepository.findOne({ + where: { id: workspaceId }, + select: ['workspaceCustomApplicationId'], + withDeleted: true, + }); + + if (!isDefined(workspace)) { + throw new ApplicationException( + `Could not find workspace ${workspaceId}`, + ApplicationExceptionCode.APPLICATION_NOT_FOUND, + ); + } + + return workspace.workspaceCustomApplicationId; + } + private async uploadCorePicture({ file, filename, @@ -59,11 +80,7 @@ export class FileCorePictureService { const universalIdentifier = applicationUniversalIdentifier ?? - ( - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ) - ).workspaceCustomFlatApplication.universalIdentifier; + (await this.findCustomApplicationUniversalIdentifier(workspaceId)); const savedFile = await this.fileStorageService.writeFile({ sourceFile: sanitizedFile, @@ -169,17 +186,12 @@ export class FileCorePictureService { }, }); - const { workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); + const customApplicationUniversalIdentifier = + await this.findCustomApplicationUniversalIdentifier(workspaceId); await this.fileStorageService.delete({ workspaceId, - applicationUniversalIdentifier: - workspaceCustomFlatApplication.universalIdentifier, + applicationUniversalIdentifier: customApplicationUniversalIdentifier, fileFolder: FileFolder.CorePicture, resourcePath: removeFileFolderFromFileEntityPath(file.path), }); @@ -286,16 +298,12 @@ export class FileCorePictureService { }, }); - const { workspaceCustomFlatApplication: sourceApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId: sourceWorkspaceId, - }, - ); + const sourceApplicationUniversalIdentifier = + await this.findCustomApplicationUniversalIdentifier(sourceWorkspaceId); const fileStream = await this.fileStorageService.readFile({ workspaceId: sourceWorkspaceId, - applicationUniversalIdentifier: sourceApplication.universalIdentifier, + applicationUniversalIdentifier: sourceApplicationUniversalIdentifier, fileFolder: FileFolder.CorePicture, resourcePath: removeFileFolderFromFileEntityPath(sourceFile.path), });