-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(registry): templates/localized API (#610)
* refactor(registry): move updateTemplate logic into the repo * feat(registry): add routes to manage localized templates - `PUT /api/v1/templates/{name}/localizedVersions/{locale}` body: `{ content: string }` - `DELETE /api/v1/templates/{name}/localizedVersions/{locale}` * fix(regitsry/tests): remove `.only` * refactor(registry): move createTemplate logic to the repository * fix(registry): CR * fix(registry): CR - remove ts-exhaustive-check * fix(registry): CR - do an explicit assert on `req.user` instead of TS non-null assertion operator (`!`) * fix(registry): CR - remove the assert over req.user, because it is allowed to be undefined (in the tests); add missing expects in the tests * fix: remove .only * fix(registry): CR - implement unsupported locales validation MW as discussed * fix: increase tests coverage; ignore by-design unreachable code * chore: formatting * fix(registry): CR - throw custom error --------- Co-authored-by: Mark Harnyk <[email protected]>
- Loading branch information
Showing
14 changed files
with
523 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,4 +102,4 @@ | |
"node": "^20.8.0" | ||
}, | ||
"engineStrict": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { Request, Response } from 'express'; | ||
import Joi from 'joi'; | ||
|
||
import { SettingKeys } from '../settings/interfaces'; | ||
import settingsService from '../settings/services/SettingsService'; | ||
import { getJoiErr, joiErrorToResponse } from '../util/helpers'; | ||
|
||
export const validateLocalesMiddleware = | ||
( | ||
localesFromRequest: (req: Request) => string[], | ||
unsupportedLocalesToFieldName: (unsupportedLocales: string[]) => string, | ||
) => | ||
async (req: Request, res: Response, next: () => void) => { | ||
const locales = localesFromRequest(req); | ||
|
||
if (locales.length === 0) { | ||
next(); | ||
return; | ||
} | ||
|
||
const unsupportedLocales = await getUnsupportedLocales(locales); | ||
if (unsupportedLocales.length > 0) { | ||
res.status(422).send( | ||
joiErrorToResponse( | ||
unsupportedLocalesToJoiError(unsupportedLocales, unsupportedLocalesToFieldName(unsupportedLocales)), | ||
), | ||
); | ||
return; | ||
} | ||
|
||
next(); | ||
}; | ||
|
||
async function getUnsupportedLocales(locales: string[]): Promise<string[]> { | ||
const supportedLocales = await settingsService.get(SettingKeys.I18nSupportedLocales); | ||
return locales.filter((l) => !supportedLocales.includes(l)); | ||
} | ||
|
||
function unsupportedLocalesToJoiError(unsupportedLocales: string[], field: string): Joi.ValidationError { | ||
return getJoiErr( | ||
`localizedVersions.${unsupportedLocales[0]}`, | ||
`Next locales are not supported ${unsupportedLocales.join(',')}. Either change request or change ${ | ||
SettingKeys.I18nSupportedLocales | ||
} setting.`, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
registry/server/templates/routes/deleteTemplateLocalizedVersion.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Request, Response } from 'express'; | ||
import Joi from 'joi'; | ||
|
||
import validateRequestFactory from '../../common/services/validateRequest'; | ||
import { exhaustiveCheck } from '../../util/exhaustiveCheck'; | ||
import { templatesRepository } from '../services/templatesRepository'; | ||
import { localeNameSchema, templateNameSchema } from './validation'; | ||
|
||
const validateRequestBeforeDeleteTemplateLocalizedVersion = validateRequestFactory([ | ||
{ | ||
schema: Joi.object({ | ||
name: templateNameSchema.required(), | ||
locale: localeNameSchema.required(), | ||
}), | ||
selector: 'params', | ||
}, | ||
]); | ||
|
||
type Params = { | ||
name: string; | ||
locale: string; | ||
}; | ||
|
||
const deleteTemplateLocalizedVersion = async (req: Request<Params>, res: Response): Promise<void> => { | ||
const { name: templateName, locale } = req.params; | ||
|
||
const result = await templatesRepository.deleteLocalizedVersion(templateName, locale); | ||
switch (result.type) { | ||
case 'notFound': { | ||
res.status(404).send('Not found'); | ||
return; | ||
} | ||
case 'ok': { | ||
res.status(204).send(); | ||
return; | ||
} | ||
default: { | ||
/* istanbul ignore next */ | ||
exhaustiveCheck(result); | ||
} | ||
} | ||
}; | ||
|
||
export default [validateRequestBeforeDeleteTemplateLocalizedVersion, deleteTemplateLocalizedVersion]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
registry/server/templates/routes/upsertTemplateLocalizedVersion.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { Request, Response } from 'express'; | ||
import Joi from 'joi'; | ||
|
||
import validateRequestFactory from '../../common/services/validateRequest'; | ||
import { validateLocalesMiddleware } from '../../middleware/validatelocales'; | ||
import { exhaustiveCheck } from '../../util/exhaustiveCheck'; | ||
import { LocalizedVersion } from '../interfaces'; | ||
import { templatesRepository } from '../services/templatesRepository'; | ||
import { localeNameSchema, localizedVersionSchema, templateNameSchema } from './validation'; | ||
|
||
const validateRequestBeforeUpsertLocalizedVersion = validateRequestFactory([ | ||
{ | ||
schema: Joi.object({ | ||
name: templateNameSchema.required(), | ||
locale: localeNameSchema.required(), | ||
}), | ||
selector: 'params', | ||
}, | ||
{ | ||
schema: localizedVersionSchema.required(), | ||
selector: 'body', | ||
}, | ||
]); | ||
|
||
const validateLocale = validateLocalesMiddleware( | ||
(req) => [req.params.locale], | ||
() => 'params.locale', | ||
); | ||
|
||
type Params = { | ||
name: string; | ||
locale: string; | ||
}; | ||
|
||
const upsertTemplateLocalizedVersion = async ( | ||
req: Request<Params, any, LocalizedVersion>, | ||
res: Response, | ||
): Promise<void> => { | ||
const { name: templateName, locale } = req.params; | ||
const localizedVersion = req.body; | ||
|
||
const result = await templatesRepository.upsertLocalizedVersion(templateName, locale, localizedVersion); | ||
switch (result.type) { | ||
case 'notFound': { | ||
res.status(404).send('Not found'); | ||
return; | ||
} | ||
case 'ok': { | ||
res.status(200).send(result.localizedVersion); | ||
return; | ||
} | ||
default: { | ||
/* istanbul ignore next */ | ||
exhaustiveCheck(result); | ||
} | ||
} | ||
}; | ||
|
||
export default [validateRequestBeforeUpsertLocalizedVersion, validateLocale, upsertTemplateLocalizedVersion]; |
Oops, something went wrong.