From a1aef26905f624569ee47e43bb3a9c9cf05b997b Mon Sep 17 00:00:00 2001 From: IceHe Date: Mon, 19 Sep 2022 18:18:03 +0800 Subject: [PATCH] feat(core): cannot delete custom phrase used as default language in sign-in exp (#1951) --- packages/core/src/routes/custom-phrase.test.ts | 14 +++++++++++++- packages/core/src/routes/custom-phrase.ts | 13 +++++++++++++ packages/phrases/src/locales/en/errors.ts | 4 ++++ packages/phrases/src/locales/fr/errors.ts | 4 ++++ packages/phrases/src/locales/ko-kr/errors.ts | 4 ++++ packages/phrases/src/locales/pt-pt/errors.ts | 4 ++++ packages/phrases/src/locales/tr-tr/errors.ts | 4 ++++ packages/phrases/src/locales/zh-cn/errors.ts | 3 +++ 8 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/core/src/routes/custom-phrase.test.ts b/packages/core/src/routes/custom-phrase.test.ts index cd1020d95..70e7b035e 100644 --- a/packages/core/src/routes/custom-phrase.test.ts +++ b/packages/core/src/routes/custom-phrase.test.ts @@ -1,5 +1,6 @@ import { CustomPhrase } from '@logto/schemas'; +import { mockSignInExperience } from '@/__mocks__'; import RequestError from '@/errors/RequestError'; import customPhraseRoutes from '@/routes/custom-phrase'; import { createRequester } from '@/utils/test-utils'; @@ -48,6 +49,12 @@ jest.mock('@/queries/custom-phrase', () => ({ upsertCustomPhrase: async (customPhrase: CustomPhrase) => upsertCustomPhrase(customPhrase), })); +const findDefaultSignInExperience = jest.fn(async () => mockSignInExperience); + +jest.mock('@/queries/sign-in-experience', () => ({ + findDefaultSignInExperience: async () => findDefaultSignInExperience(), +})); + describe('customPhraseRoutes', () => { const customPhraseRequest = createRequester({ authedRoutes: customPhraseRoutes }); @@ -122,8 +129,13 @@ describe('customPhraseRoutes', () => { }); it('should return 404 status code when the specified custom phrase does not exist before deleting', async () => { - const response = await customPhraseRequest.delete(`/custom-phrases/en-UK`); + const response = await customPhraseRequest.delete('/custom-phrases/en-UK'); expect(response.status).toEqual(404); }); + + it('should return 400 status code when the specified custom phrase is used as default language in sign-in experience', async () => { + const response = await customPhraseRequest.delete('/custom-phrases/en'); + expect(response.status).toEqual(400); + }); }); }); diff --git a/packages/core/src/routes/custom-phrase.ts b/packages/core/src/routes/custom-phrase.ts index ceb9190a6..81a39c4a2 100644 --- a/packages/core/src/routes/custom-phrase.ts +++ b/packages/core/src/routes/custom-phrase.ts @@ -1,5 +1,6 @@ import { CustomPhrases, translationGuard } from '@logto/schemas'; +import RequestError from '@/errors/RequestError'; import koaGuard from '@/middleware/koa-guard'; import { deleteCustomPhraseByLanguageKey, @@ -7,6 +8,7 @@ import { findCustomPhraseByLanguageKey, upsertCustomPhrase, } from '@/queries/custom-phrase'; +import { findDefaultSignInExperience } from '@/queries/sign-in-experience'; import { AuthedRouter } from './types'; @@ -70,6 +72,17 @@ export default function customPhraseRoutes(router: T) { params: { languageKey }, } = ctx.guard; + const { + languageInfo: { fallbackLanguage }, + } = await findDefaultSignInExperience(); + + if (fallbackLanguage === languageKey) { + throw new RequestError({ + code: 'localization.cannot_delete_default_language', + languageKey, + }); + } + await deleteCustomPhraseByLanguageKey(languageKey); ctx.status = 204; diff --git a/packages/phrases/src/locales/en/errors.ts b/packages/phrases/src/locales/en/errors.ts index 7e389d60f..661d8806e 100644 --- a/packages/phrases/src/locales/en/errors.ts +++ b/packages/phrases/src/locales/en/errors.ts @@ -101,6 +101,10 @@ const errors = { not_one_and_only_one_primary_sign_in_method: 'There must be one and only one primary sign-in method. Please check your input.', }, + localization: { + cannot_delete_default_language: + 'You cannot delete {{languageKey}} language since it is used as default language in sign-in experience.', // UNTRANSLATED + }, swagger: { invalid_zod_type: 'Invalid Zod type. Please check route guard config.', not_supported_zod_type_for_params: diff --git a/packages/phrases/src/locales/fr/errors.ts b/packages/phrases/src/locales/fr/errors.ts index 44e23847d..44f577238 100644 --- a/packages/phrases/src/locales/fr/errors.ts +++ b/packages/phrases/src/locales/fr/errors.ts @@ -109,6 +109,10 @@ const errors = { not_one_and_only_one_primary_sign_in_method: 'Il doit y avoir une et une seule méthode de connexion primaire. Veuillez vérifier votre saisie.', }, + localization: { + cannot_delete_default_language: + 'You cannot delete {{languageKey}} language since it is used as default language in sign-in experience.', // UNTRANSLATED + }, swagger: { invalid_zod_type: 'Type Zod non valide. Veuillez vérifier la configuration du garde-route.', not_supported_zod_type_for_params: diff --git a/packages/phrases/src/locales/ko-kr/errors.ts b/packages/phrases/src/locales/ko-kr/errors.ts index 72f6153c7..14569b011 100644 --- a/packages/phrases/src/locales/ko-kr/errors.ts +++ b/packages/phrases/src/locales/ko-kr/errors.ts @@ -98,6 +98,10 @@ const errors = { not_one_and_only_one_primary_sign_in_method: '반드시 하나의 메인 로그인 방법이 설정되어야 해요. 입력된 값을 확인해주세요.', }, + localization: { + cannot_delete_default_language: + 'You cannot delete {{languageKey}} language since it is used as default language in sign-in experience.', // UNTRANSLATED + }, swagger: { invalid_zod_type: '유요하지 않은 Zod 종류에요. Route Guard 설정을 확인해주세요.', not_supported_zod_type_for_params: diff --git a/packages/phrases/src/locales/pt-pt/errors.ts b/packages/phrases/src/locales/pt-pt/errors.ts index e884dff56..462b49b16 100644 --- a/packages/phrases/src/locales/pt-pt/errors.ts +++ b/packages/phrases/src/locales/pt-pt/errors.ts @@ -104,6 +104,10 @@ const errors = { not_one_and_only_one_primary_sign_in_method: 'Deve haver um e apenas um método de login principal. Por favor, verifique sua entrada.', }, + localization: { + cannot_delete_default_language: + 'You cannot delete {{languageKey}} language since it is used as default language in sign-in experience.', // UNTRANSLATED + }, swagger: { invalid_zod_type: 'Tipo de Zod inválido. Verifique a configuração do protetor de rota.', not_supported_zod_type_for_params: diff --git a/packages/phrases/src/locales/tr-tr/errors.ts b/packages/phrases/src/locales/tr-tr/errors.ts index 777bd05fc..18a760aff 100644 --- a/packages/phrases/src/locales/tr-tr/errors.ts +++ b/packages/phrases/src/locales/tr-tr/errors.ts @@ -102,6 +102,10 @@ const errors = { not_one_and_only_one_primary_sign_in_method: 'Yalnızca bir tane birincil oturum açma yöntemi olmalıdır. Lütfen inputu kontrol ediniz.', }, + localization: { + cannot_delete_default_language: + 'You cannot delete {{languageKey}} language since it is used as default language in sign-in experience.', // UNTRANSLATED + }, swagger: { invalid_zod_type: 'Geçersiz Zod tipi. Lütfen yönlendirici koruma yapılandırmasını kontrol ediniz.', diff --git a/packages/phrases/src/locales/zh-cn/errors.ts b/packages/phrases/src/locales/zh-cn/errors.ts index 5a461d4a3..2b686cbbd 100644 --- a/packages/phrases/src/locales/zh-cn/errors.ts +++ b/packages/phrases/src/locales/zh-cn/errors.ts @@ -96,6 +96,9 @@ const errors = { enabled_connector_not_found: '未找到已启用的 {{type}} 连接器', not_one_and_only_one_primary_sign_in_method: '主要的登录方式必须有且仅有一个,请检查你的输入。', }, + localization: { + cannot_delete_default_language: '不能删除「登录体验」正在使用的默认语言 {{languageKey}}。', // UNTRANSLATED + }, swagger: { invalid_zod_type: '无效的 Zod 类型,请检查路由 guard 配置。', not_supported_zod_type_for_params: '请求参数不支持的 Zod 类型,请检查路由 guard 配置。',