Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 860d540773 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.
2026-03-22 12:47:12 +00:00
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,