Files
twenty/packages/twenty-server/test/integration/graphql/utils/get-current-user.util.ts
T
e6399b180e Fix/workspace member avatars 20193 (#20200)
Fixes #20193

**Bug Description:**
Previously, workspace member avatars failed to render correctly in table
views and relation chips (such as the Account Owner field). While the
avatar picker dropdown correctly fetched fresh GraphQL data, table views
and chips relied on the cached defaultAvatarUrl or avatarUrl fields,
which were frequently resolving to empty strings or failing to parse
external OAuth URLs correctly.

**Root Cause:**

- Empty String Defaults: Deleting an avatar or failing to retrieve one
defaulted the database state to an empty string ("") instead of null,
which caused frontend image components to break rather than render their
fallback states.

- Missing Permanent URLs: The WorkspaceMemberTranspiler was strictly
expecting internal signed URLs. If an avatar was an external OAuth URL,
it incorrectly returned an empty string, breaking SSO profile pictures.

- Missing Fallbacks: New users lacked a proper Gravatar fallback
assignment upon workspace creation.

**Changes Made:**

- user-workspace.service.ts: Updated the avatar computation logic during
user creation to implement a reliable Gravatar fallback and correctly
set missing avatars to null instead of empty strings. Updated the
storage to use permanent file URLs.
- file-url.service.ts: Implemented a getRawFileUrl method to support
rendering permanent, non-expiring file URLs for avatars.
- workspace-member-transpiler.service.ts: Refactored the URL
transpilation logic to gracefully pass through external OAuth URLs
(e.g., Google/Microsoft profile pictures) instead of stripping them.
- WorkspaceMemberPictureUploader.tsx: Fixed the frontend removal logic
so that deleting a profile picture sets the avatarUrl to null
(consistent with the backend) rather than an empty string.

**Testing:**

- Verified that avatars correctly display in relation chips and table
views.
- Verified that external OAuth avatars load properly.
- Verified that deleting an avatar correctly resets the UI to the
fallback initials component.

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 19:42:12 +00:00

75 lines
1.8 KiB
TypeScript

import gql from 'graphql-tag';
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
import { type UserEntity } from 'src/engine/core-modules/user/user.entity';
type CurrentUserUtilArgs = {
accessToken: string;
expectToFail?: boolean;
};
export const getCurrentUser = async ({
accessToken,
expectToFail,
}: CurrentUserUtilArgs): CommonResponseBody<{
currentUser: UserEntity;
}> => {
const query = gql`
query CurrentUser {
currentUser {
id
email
firstName
lastName
isEmailVerified
disabled
canImpersonate
canAccessFullAdminPanel
locale
createdAt
updatedAt
deletedAt
currentWorkspace {
id
displayName
subdomain
activationStatus
logo
workspaceCustomApplicationId
}
currentUserWorkspace {
id
userId
}
}
}
`;
const response = await makeMetadataAPIRequest(
{
query,
variables: {},
},
accessToken,
);
if (expectToFail === true) {
warnIfNoErrorButExpectedToFail({
response,
errorMessage: 'Get current user should have failed but did not',
});
}
if (expectToFail === false) {
warnIfErrorButNotExpectedToFail({
response,
errorMessage: 'Get current user has failed but should not',
});
}
return { data: response.body.data, errors: response.body.errors };
};