fix: use workspace custom application for logo upload during onboarding

https://sonarly.com/issue/17298?type=bug

Uploading a workspace logo on the initial workspace creation page fails because the upload code requires the Twenty Standard Application, which is only created during workspace activation (after clicking "Continue").

Fix: Added `findWorkspaceCustomFlatApplicationOrThrow` to `ApplicationService` — a method that looks up only the workspace's custom application from the cache, without requiring the Twenty Standard Application to exist. This is safe because the custom application is created during sign-up (`sign-in-up.service.ts`), so it exists for workspaces in any activation state including `PENDING_CREATION`.

Changed all three call sites in `FileCorePictureService` (`uploadCorePicture`, `deleteCorePicture`, `copyWorkspaceMemberProfilePicture`) to use the new method instead of `findWorkspaceTwentyStandardAndCustomApplicationOrThrow`. All three only use `workspaceCustomFlatApplication.universalIdentifier` — they never needed the Twenty Standard Application lookup that was causing the failure during onboarding.

This allows users to upload a workspace logo on the initial setup page before workspace activation, fixing the reported bug.
This commit is contained in:
Sonarly Claude Code
2026-03-22 12:47:12 +00:00
parent bdaff0b7e2
commit 860d540773
2 changed files with 42 additions and 11 deletions
@@ -48,6 +48,41 @@ export class ApplicationService {
return application.defaultRoleId;
}
async findWorkspaceCustomFlatApplicationOrThrow({
workspaceId,
}: {
workspaceId: string;
}) {
const workspace = await this.workspaceRepository.findOne({
where: { id: workspaceId },
withDeleted: true,
});
if (!isDefined(workspace)) {
throw new ApplicationException(
`Could not find workspace ${workspaceId}`,
ApplicationExceptionCode.APPLICATION_NOT_FOUND,
);
}
const { flatApplicationMaps } =
await this.workspaceCacheService.getOrRecompute(workspace.id, [
'flatApplicationMaps',
]);
const workspaceCustomFlatApplication =
flatApplicationMaps.byId[workspace.workspaceCustomApplicationId];
if (!isDefined(workspaceCustomFlatApplication)) {
throw new ApplicationException(
`Could not find workspace custom application for workspace ${workspaceId}`,
ApplicationExceptionCode.APPLICATION_NOT_FOUND,
);
}
return { workspaceCustomFlatApplication };
}
async findWorkspaceTwentyStandardAndCustomApplicationOrThrow({
workspace: workspaceInput,
workspaceId,
@@ -60,7 +60,7 @@ export class FileCorePictureService {
const universalIdentifier =
applicationUniversalIdentifier ??
(
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
await this.applicationService.findWorkspaceCustomFlatApplicationOrThrow(
{ workspaceId },
)
).workspaceCustomFlatApplication.universalIdentifier;
@@ -170,11 +170,9 @@ export class FileCorePictureService {
});
const { workspaceCustomFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{
workspaceId,
},
);
await this.applicationService.findWorkspaceCustomFlatApplicationOrThrow({
workspaceId,
});
await this.fileStorageService.delete({
workspaceId,
@@ -287,11 +285,9 @@ export class FileCorePictureService {
});
const { workspaceCustomFlatApplication: sourceApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{
workspaceId: sourceWorkspaceId,
},
);
await this.applicationService.findWorkspaceCustomFlatApplicationOrThrow({
workspaceId: sourceWorkspaceId,
});
const fileStream = await this.fileStorageService.readFile({
workspaceId: sourceWorkspaceId,