diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 146b0daf51..dbac2ed5d2 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -4397,6 +4397,7 @@ export type WorkspaceInfo = { name: Scalars['String']; totalUsers: Scalars['Float']; users: Array; + workspaceUrls: WorkspaceUrls; }; export type WorkspaceInvitation = { @@ -5079,7 +5080,7 @@ export type UserLookupAdminPanelMutationVariables = Exact<{ }>; -export type UserLookupAdminPanelMutation = { __typename?: 'Mutation', userLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, logo?: string | null, totalUsers: number, allowImpersonation: boolean, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: FeatureFlagKey, value: boolean }> }> } }; +export type UserLookupAdminPanelMutation = { __typename?: 'Mutation', userLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, logo?: string | null, totalUsers: number, allowImpersonation: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', customUrl?: string | null, subdomainUrl: string }, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: FeatureFlagKey, value: boolean }> }> } }; export type GetVersionInfoQueryVariables = Exact<{ [key: string]: never; }>; @@ -9640,6 +9641,10 @@ export const UserLookupAdminPanelDocument = gql` logo totalUsers allowImpersonation + workspaceUrls { + customUrl + subdomainUrl + } users { id email diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 2df2f4e39a..f4b7e4aca6 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -4225,6 +4225,7 @@ export type WorkspaceInfo = { name: Scalars['String']; totalUsers: Scalars['Float']; users: Array; + workspaceUrls: WorkspaceUrls; }; export type WorkspaceInvitation = { diff --git a/packages/twenty-front/src/modules/apollo/components/ApolloProvider.tsx b/packages/twenty-front/src/modules/apollo/components/ApolloProvider.tsx index a14a5e9f61..df99aadd86 100644 --- a/packages/twenty-front/src/modules/apollo/components/ApolloProvider.tsx +++ b/packages/twenty-front/src/modules/apollo/components/ApolloProvider.tsx @@ -16,8 +16,10 @@ export const ApolloProvider = ({ children }: React.PropsWithChildren) => { extraLinks: [captchaRefreshLink], }); - // This will attach the right apollo client to Apollo Dev Tools - window.__APOLLO_CLIENT__ = apolloClient; + // Expose Apollo client in development to Apollo Dev Tools + if (process.env.NODE_ENV === 'development') { + window.__APOLLO_CLIENT__ = apolloClient; + } return ( {children} diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx index 7f90cfe3a8..c8198ef199 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx @@ -26,6 +26,7 @@ import { IconEyeShare, IconHome, IconId, + IconLink, IconUser, } from 'twenty-ui/display'; import { Button, Toggle } from 'twenty-ui/input'; @@ -133,6 +134,10 @@ export const SettingsAdminWorkspaceContent = ({ }); }; + const getWorkspaceUrl = (workspaceUrls: WorkspaceInfo['workspaceUrls']) => { + return workspaceUrls.customUrl ?? workspaceUrls.subdomainUrl; + }; + const workspaceInfoItems = [ { Icon: IconHome, @@ -160,6 +165,13 @@ export const SettingsAdminWorkspaceContent = ({ label: t`ID`, value: activeWorkspace?.id, }, + { + Icon: IconLink, + label: t`URL`, + value: activeWorkspace?.workspaceUrls + ? getWorkspaceUrl(activeWorkspace.workspaceUrls) + : '', + }, { Icon: IconUser, label: t`Members`, @@ -186,7 +198,11 @@ export const SettingsAdminWorkspaceContent = ({ Icon={IconEyeShare} variant="primary" accent="default" - title={t`Impersonate`} + title={ + activeWorkspace.allowImpersonation === false + ? t`Impersonation is disabled for this workspace` + : t`Impersonate` + } onClick={() => handleImpersonate(activeWorkspace.id)} disabled={ isImpersonateLoading || diff --git a/packages/twenty-front/src/modules/settings/admin-panel/graphql/mutations/userLookupAdminPanel.ts b/packages/twenty-front/src/modules/settings/admin-panel/graphql/mutations/userLookupAdminPanel.ts index 3d2ecaae8f..37824e3512 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/graphql/mutations/userLookupAdminPanel.ts +++ b/packages/twenty-front/src/modules/settings/admin-panel/graphql/mutations/userLookupAdminPanel.ts @@ -15,6 +15,10 @@ export const USER_LOOKUP_ADMIN_PANEL = gql` logo totalUsers allowImpersonation + workspaceUrls { + customUrl + subdomainUrl + } users { id email diff --git a/packages/twenty-front/src/modules/settings/admin-panel/types/WorkspaceInfo.ts b/packages/twenty-front/src/modules/settings/admin-panel/types/WorkspaceInfo.ts index 0b3cfa0da2..04bbe403e1 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/types/WorkspaceInfo.ts +++ b/packages/twenty-front/src/modules/settings/admin-panel/types/WorkspaceInfo.ts @@ -1,10 +1,12 @@ import { type FeatureFlag } from '@/settings/admin-panel/types/FeatureFlag'; +import { type WorkspaceUrls } from '~/generated-metadata/graphql'; export type WorkspaceInfo = { id: string; name: string; logo?: string | null; totalUsers: number; + workspaceUrls: WorkspaceUrls; users: { id: string; email: string; diff --git a/packages/twenty-front/src/utils/cookie-storage.ts b/packages/twenty-front/src/utils/cookie-storage.ts index 183d0da52f..51438dc15b 100644 --- a/packages/twenty-front/src/utils/cookie-storage.ts +++ b/packages/twenty-front/src/utils/cookie-storage.ts @@ -13,7 +13,14 @@ class CookieStorage { attributes?: Cookies.CookieAttributes, ): void { this.keys.add(key); - Cookies.set(key, value, attributes); + + const secureAttributes = { + secure: window.location.protocol === 'https:', + sameSite: 'lax' as const, + ...attributes, + }; + + Cookies.set(key, value, secureAttributes); } removeItem(key: string, attributes?: Cookies.CookieAttributes): void { diff --git a/packages/twenty-server/src/engine/core-modules/admin-panel/__tests__/admin-panel.service.spec.ts b/packages/twenty-server/src/engine/core-modules/admin-panel/__tests__/admin-panel.service.spec.ts index 25b00408ec..ee5bb9cf00 100644 --- a/packages/twenty-server/src/engine/core-modules/admin-panel/__tests__/admin-panel.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/admin-panel/__tests__/admin-panel.service.spec.ts @@ -7,6 +7,7 @@ import { AdminPanelService } from 'src/engine/core-modules/admin-panel/admin-pan import { AuditService } from 'src/engine/core-modules/audit/services/audit.service'; import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; +import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { User } from 'src/engine/core-modules/user/user.entity'; @@ -82,6 +83,10 @@ describe('AdminPanelService', () => { }), }, }, + { + provide: FileService, + useValue: {}, + }, ], }).compile(); diff --git a/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.module.ts b/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.module.ts index 2ffbf7129f..1cb8e38a00 100644 --- a/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.module.ts +++ b/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.module.ts @@ -9,6 +9,7 @@ import { AuditModule } from 'src/engine/core-modules/audit/audit.module'; import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; +import { FileModule } from 'src/engine/core-modules/file/file.module'; import { HealthModule } from 'src/engine/core-modules/health/health.module'; import { ImpersonationModule } from 'src/engine/core-modules/impersonation/impersonation.module'; import { RedisClientModule } from 'src/engine/core-modules/redis-client/redis-client.module'; @@ -21,6 +22,7 @@ import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permi TypeOrmModule.forFeature([User]), AuthModule, DomainManagerModule, + FileModule, HealthModule, RedisClientModule, TerminusModule, diff --git a/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts b/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts index 059c9606c3..a6a64ff093 100644 --- a/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts +++ b/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts @@ -20,6 +20,7 @@ import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/l import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { type FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { type ConfigVariables } from 'src/engine/core-modules/twenty-config/config-variables'; import { CONFIG_VARIABLES_GROUP_METADATA } from 'src/engine/core-modules/twenty-config/constants/config-variables-group-metadata'; import { type ConfigVariablesGroup } from 'src/engine/core-modules/twenty-config/enums/config-variables-group.enum'; @@ -34,15 +35,21 @@ export class AdminPanelService { private readonly twentyConfigService: TwentyConfigService, private readonly domainManagerService: DomainManagerService, private readonly auditService: AuditService, + private readonly fileService: FileService, @InjectRepository(User) private readonly userRepository: Repository, ) {} async userLookup(userIdentifier: string): Promise { const isEmail = userIdentifier.includes('@'); + const normalizedIdentifier = isEmail + ? userIdentifier.toLowerCase() + : userIdentifier; const targetUser = await this.userRepository.findOne({ - where: isEmail ? { email: userIdentifier } : { id: userIdentifier }, + where: isEmail + ? { email: normalizedIdentifier } + : { id: normalizedIdentifier }, relations: { userWorkspaces: { workspace: { @@ -57,7 +64,9 @@ export class AdminPanelService { userValidator.assertIsDefinedOrThrow( targetUser, - new AuthException('User not found', AuthExceptionCode.INVALID_INPUT), + new AuthException('User not found', AuthExceptionCode.INVALID_INPUT, { + userFriendlyMessage: 'User not found. Please check the email or ID.', + }), ); const allFeatureFlagKeys = Object.values(FeatureFlagKey); @@ -73,8 +82,18 @@ export class AdminPanelService { id: userWorkspace.workspace.id, name: userWorkspace.workspace.displayName ?? '', totalUsers: userWorkspace.workspace.workspaceUsers.length, - logo: userWorkspace.workspace.logo, + logo: userWorkspace.workspace.logo + ? this.fileService.signFileUrl({ + url: userWorkspace.workspace.logo, + workspaceId: userWorkspace.workspace.id, + }) + : userWorkspace.workspace.logo, allowImpersonation: userWorkspace.workspace.allowImpersonation, + workspaceUrls: this.domainManagerService.getWorkspaceUrls({ + subdomain: userWorkspace.workspace.subdomain, + customDomain: userWorkspace.workspace.customDomain, + isCustomDomainEnabled: userWorkspace.workspace.isCustomDomainEnabled, + }), users: userWorkspace.workspace.workspaceUsers.map((workspaceUser) => ({ id: workspaceUser.user.id, email: workspaceUser.user.email, diff --git a/packages/twenty-server/src/engine/core-modules/admin-panel/dtos/user-lookup.entity.ts b/packages/twenty-server/src/engine/core-modules/admin-panel/dtos/user-lookup.entity.ts index c2c01451b0..a6f09949e6 100644 --- a/packages/twenty-server/src/engine/core-modules/admin-panel/dtos/user-lookup.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/admin-panel/dtos/user-lookup.entity.ts @@ -2,6 +2,7 @@ import { Field, ObjectType } from '@nestjs/graphql'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; +import { WorkspaceUrls } from 'src/engine/core-modules/workspace/dtos/workspace-urls.dto'; @ObjectType() class UserInfo { @@ -35,6 +36,9 @@ class WorkspaceInfo { @Field(() => Number) totalUsers: number; + @Field(() => WorkspaceUrls) + workspaceUrls: WorkspaceUrls; + @Field(() => [UserInfo]) users: UserInfo[]; diff --git a/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.module.ts b/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.module.ts index 0803d30ebc..bd1ef25142 100644 --- a/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.module.ts +++ b/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.module.ts @@ -2,14 +2,16 @@ import { Module } from '@nestjs/common'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; -import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module'; +import { ApprovedAccessDomain } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.entity'; import { ApprovedAccessDomainResolver } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.resolver'; import { ApprovedAccessDomainService } from 'src/engine/core-modules/approved-access-domain/services/approved-access-domain.service'; -import { ApprovedAccessDomain } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.entity'; +import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module'; +import { FileModule } from 'src/engine/core-modules/file/file.module'; @Module({ imports: [ DomainManagerModule, + FileModule, NestjsQueryTypeOrmModule.forFeature([ApprovedAccessDomain]), ], exports: [ApprovedAccessDomainService], diff --git a/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.service.ts b/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.service.ts index d90c5cf99b..640d072c8f 100644 --- a/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.service.ts +++ b/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.service.ts @@ -18,6 +18,7 @@ import { import { approvedAccessDomainValidator } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.validate'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { EmailService } from 'src/engine/core-modules/email/email.service'; +import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @@ -31,6 +32,7 @@ export class ApprovedAccessDomainService { private readonly emailService: EmailService, private readonly twentyConfigService: TwentyConfigService, private readonly domainManagerService: DomainManagerService, + private readonly fileService: FileService, ) {} async sendApprovedAccessDomainValidationEmail( @@ -70,7 +72,15 @@ export class ApprovedAccessDomainService { const emailTemplate = SendApprovedAccessDomainValidation({ link: link.toString(), - workspace: { name: workspace.displayName, logo: workspace.logo }, + workspace: { + name: workspace.displayName, + logo: workspace.logo + ? this.fileService.signFileUrl({ + url: workspace.logo, + workspaceId: workspace.id, + }) + : workspace.logo, + }, domain: approvedAccessDomain.domain, sender: { email: sender.userEmail, diff --git a/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.spec.ts b/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.spec.ts index fda3d1fdf0..90c45d2445 100644 --- a/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/approved-access-domain/services/approved-access-domain.spec.ts @@ -12,6 +12,7 @@ import { } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.exception'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { EmailService } from 'src/engine/core-modules/email/email.service'; +import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @@ -67,6 +68,14 @@ describe('ApprovedAccessDomainService', () => { buildWorkspaceURL: jest.fn(), }, }, + { + provide: FileService, + useValue: { + signFileUrl: jest + .fn() + .mockReturnValue('https://signed-url.com/logo.png'), + }, + }, ], }).compile(); diff --git a/packages/twenty-server/src/engine/core-modules/session-storage/session-storage.module-factory.ts b/packages/twenty-server/src/engine/core-modules/session-storage/session-storage.module-factory.ts index cdcf1272f5..c8aab18e95 100644 --- a/packages/twenty-server/src/engine/core-modules/session-storage/session-storage.module-factory.ts +++ b/packages/twenty-server/src/engine/core-modules/session-storage/session-storage.module-factory.ts @@ -32,6 +32,8 @@ export const getSessionStorageOptions = ( proxy: true, cookie: { secure: !!(SERVER_URL && SERVER_URL.startsWith('https')), + httpOnly: true, + sameSite: 'lax', maxAge: 1000 * 60 * 30, // 30 minutes }, }; diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts index 0c9b12a7eb..9a47aa11c3 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts @@ -381,7 +381,12 @@ export class UserWorkspaceService extends TypeOrmQueryService { id: workspace.id, displayName: workspace.displayName, workspaceUrls: this.domainManagerService.getWorkspaceUrls(workspace), - logo: workspace.logo, + logo: workspace.logo + ? this.fileService.signFileUrl({ + url: workspace.logo, + workspaceId: workspace.id, + }) + : workspace.logo, sso: workspace.workspaceSSOIdentityProviders?.reduce( (acc, identityProvider) => diff --git a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts index eba44e6de9..4210b9343f 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts @@ -9,6 +9,8 @@ import { } from 'src/engine/core-modules/app-token/app-token.entity'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { EmailService } from 'src/engine/core-modules/email/email.service'; +import { FileService } from 'src/engine/core-modules/file/services/file.service'; +import { I18nService } from 'src/engine/core-modules/i18n/i18n.service'; import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; @@ -16,7 +18,6 @@ import { WorkspaceInvitationException } from 'src/engine/core-modules/workspace- import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { I18nService } from 'src/engine/core-modules/i18n/i18n.service'; import { WorkspaceInvitationService } from './workspace-invitation.service'; @@ -103,6 +104,14 @@ describe('WorkspaceInvitationService', () => { }), }, }, + { + provide: FileService, + useValue: { + signFileUrl: jest + .fn() + .mockReturnValue('https://signed-url.com/logo.png'), + }, + }, ], }).compile(); diff --git a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts index 7016986888..3ae94aa238 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts @@ -22,6 +22,7 @@ import { } from 'src/engine/core-modules/auth/auth.exception'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { EmailService } from 'src/engine/core-modules/email/email.service'; +import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { I18nService } from 'src/engine/core-modules/i18n/i18n.service'; import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; @@ -47,6 +48,7 @@ export class WorkspaceInvitationService { private readonly onboardingService: OnboardingService, private readonly domainManagerService: DomainManagerService, private readonly i18nService: I18nService, + private readonly fileService: FileService, ) {} async validatePersonalInvitation({ @@ -294,7 +296,15 @@ export class WorkspaceInvitationService { const emailData = { link: link.toString(), - workspace: { name: workspace.displayName, logo: workspace.logo }, + workspace: { + name: workspace.displayName, + logo: workspace.logo + ? this.fileService.signFileUrl({ + url: workspace.logo, + workspaceId: workspace.id, + }) + : workspace.logo, + }, sender: { email: sender.userEmail, firstName: sender.name.firstName,