Fix empty emails critical bug (#13465)
Fixes https://github.com/twentyhq/twenty/issues/13398 This bug was introduced by https://github.com/twentyhq/twenty/pull/13215 The emails were empty in scenarios where the user wasn't authenticated (reset passwords for instance) because in `hydrateGraphqlRequest` the information about the locale was added only if the user was authenticated `!this.isTokenPresent(request)`. So the locale was undefined making ` i18n.activate(undefined) ` fail silently resulting in an empty email.
This commit is contained in:
@ -478,4 +478,53 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
|||||||
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
|
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Undefined locale handling', () => {
|
||||||
|
it('should use SOURCE_LOCALE fallback when locale is undefined for standard object', () => {
|
||||||
|
const objectMetadata = {
|
||||||
|
labelSingular: 'Standard Label',
|
||||||
|
labelPlural: 'Standard Labels',
|
||||||
|
description: 'Standard Description',
|
||||||
|
icon: 'default-icon',
|
||||||
|
isCustom: false,
|
||||||
|
standardOverrides: {
|
||||||
|
labelSingular: 'Source Override',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveObjectMetadataStandardOverride(
|
||||||
|
objectMetadata,
|
||||||
|
'labelSingular',
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe('Source Override');
|
||||||
|
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||||
|
expect(mockI18n._).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fall back to auto translation when locale is undefined and no SOURCE_LOCALE override exists', () => {
|
||||||
|
mockI18n._.mockReturnValue('Auto Translated Label');
|
||||||
|
mockGenerateMessageId.mockReturnValue('auto.translation.id');
|
||||||
|
|
||||||
|
const objectMetadata = {
|
||||||
|
labelSingular: 'Standard Label',
|
||||||
|
labelPlural: 'Standard Labels',
|
||||||
|
description: 'Standard Description',
|
||||||
|
icon: 'default-icon',
|
||||||
|
isCustom: false,
|
||||||
|
standardOverrides: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveObjectMetadataStandardOverride(
|
||||||
|
objectMetadata,
|
||||||
|
'labelSingular',
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe('Auto Translated Label');
|
||||||
|
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
|
||||||
|
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,6 +19,8 @@ export const resolveObjectMetadataStandardOverride = (
|
|||||||
labelKey: 'labelPlural' | 'labelSingular' | 'description' | 'icon',
|
labelKey: 'labelPlural' | 'labelSingular' | 'description' | 'icon',
|
||||||
locale: keyof typeof APP_LOCALES | undefined,
|
locale: keyof typeof APP_LOCALES | undefined,
|
||||||
): string => {
|
): string => {
|
||||||
|
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||||
|
|
||||||
if (objectMetadata.isCustom) {
|
if (objectMetadata.isCustom) {
|
||||||
return objectMetadata[labelKey] ?? '';
|
return objectMetadata[labelKey] ?? '';
|
||||||
}
|
}
|
||||||
@ -32,11 +34,10 @@ export const resolveObjectMetadataStandardOverride = (
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
isDefined(objectMetadata.standardOverrides?.translations) &&
|
isDefined(objectMetadata.standardOverrides?.translations) &&
|
||||||
isDefined(locale) &&
|
|
||||||
labelKey !== 'icon'
|
labelKey !== 'icon'
|
||||||
) {
|
) {
|
||||||
const translationValue =
|
const translationValue =
|
||||||
objectMetadata.standardOverrides.translations[locale]?.[labelKey];
|
objectMetadata.standardOverrides.translations[safeLocale]?.[labelKey];
|
||||||
|
|
||||||
if (isDefined(translationValue)) {
|
if (isDefined(translationValue)) {
|
||||||
return translationValue;
|
return translationValue;
|
||||||
@ -44,7 +45,7 @@ export const resolveObjectMetadataStandardOverride = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
locale === SOURCE_LOCALE &&
|
safeLocale === SOURCE_LOCALE &&
|
||||||
isNonEmptyString(objectMetadata.standardOverrides?.[labelKey])
|
isNonEmptyString(objectMetadata.standardOverrides?.[labelKey])
|
||||||
) {
|
) {
|
||||||
return objectMetadata.standardOverrides[labelKey] ?? '';
|
return objectMetadata.standardOverrides[labelKey] ?? '';
|
||||||
|
|||||||
@ -128,6 +128,10 @@ export class MiddlewareService {
|
|||||||
|
|
||||||
public async hydrateGraphqlRequest(request: Request) {
|
public async hydrateGraphqlRequest(request: Request) {
|
||||||
if (!this.isTokenPresent(request)) {
|
if (!this.isTokenPresent(request)) {
|
||||||
|
request.locale =
|
||||||
|
(request.headers['x-locale'] as keyof typeof APP_LOCALES) ??
|
||||||
|
SOURCE_LOCALE;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user