refac: DELETE /v1/user/{id}?expected_role_id=N, user.remove audit event, 409 target_role_not_found, GetAll returns its error, Own-scope visibility filter moved into repos, JSON tags removed from use-case types

This commit is contained in:
Florian Sylvain committed 2026-10-29 16:28:25 +01:00
1 parent 5d6f378fce
commit b39a41be88
124 files changed
+8816 -523

No files matched your search

+133 -4
View File
@@ -63,7 +63,6 @@ describe('Roles screens copy', () => {
})
const USERS_ROLES_KEYS = [
'Assigned by {0}',
'Your role',
'See what I can do',
'What you can do',
@@ -90,10 +89,140 @@ describe('Users, Profile, API keys and Activity copy for roles', () => {
it.each(USERS_ROLES_KEYS)('"%s" has a French entry', (key) => {
expect((messages as Record<string, string>)[key]).toMatch(/\S/)
})
})
it('renders "Assigned by {0}" in both languages', () => {
expect(t('Assigned by {0}', ['Marta Alves'])).toBe('Assigned by Marta Alves')
const FINAL_COPY: [string, (string | number)[], string][] = [
[
'{0} is now {1}, and their API keys follow the new role.',
['Ines Duarte', 'Content lead'],
'Ines Duarte a maintenant le rôle Content lead, et ses clés API suivent le nouveau rôle.',
],
["Couldn't save the role", [], "Impossible d'enregistrer le rôle"],
[
'Your changes are still here. Try again in a moment.',
[],
'Vos modifications sont toujours là. Réessayez dans un instant.',
],
['Try again', [], 'Réessayer'],
["Couldn't change the role", [], 'Impossible de modifier le rôle'],
[
'Nothing was changed. Try again in a moment.',
[],
"Rien n'a été modifié. Réessayez dans un instant.",
],
[
"Your role can't assign a role with more power than yours.",
[],
'Votre rôle ne peut pas attribuer un rôle plus puissant que le vôtre.',
],
['{0} no longer exists', ['Writer'], "Writer n'existe plus"],
[
'It was deleted somewhere else. Choose another role to move the members to.',
[],
'Il a été supprimé ailleurs. Choisissez un autre rôle pour y déplacer les membres.',
],
['Role still has members', [], 'Le rôle a encore des membres'],
[
'{0} now has 1 member. Move them to another role first.',
['Intern'],
"Intern a maintenant 1 membre. Déplacez-le d'abord vers un autre rôle.",
],
[
'{0} now has {1} members. Move them to another role first.',
['Intern', 3],
"Intern a maintenant 3 membres. Déplacez-les d'abord vers un autre rôle.",
],
["Couldn't move the members", [], 'Impossible de déplacer les membres'],
['Enter a valid email address.', [], 'Saisissez une adresse e-mail valide.'],
['This address already has an account.', [], 'Cette adresse a déjà un compte.'],
["Couldn't send the invite", [], "Impossible d'envoyer l'invitation"],
['Try again in a moment.', [], 'Réessayez dans un instant.'],
['Role changed elsewhere', [], 'Rôle modifié ailleurs'],
[
'{0} edited {1}, so nothing was saved. Reload and try again.',
['Jonas Weber', 'Contributor'],
"Jonas Weber a modifié Contributor, donc rien n'a été enregistré. Rechargez et réessayez.",
],
['Reload', [], 'Recharger'],
['That role no longer exists', [], "Ce rôle n'existe plus"],
['Role not changed', [], 'Rôle non modifié'],
[
"{0}'s role changed in the meantime, so nothing was saved. Reload and try again.",
['Ines Duarte'],
"Le rôle de Ines Duarte a changé entre-temps, donc rien n'a été enregistré. Rechargez et réessayez.",
],
['Ownership not transferred', [], 'Propriété non transférée'],
[
"{0}'s role changed in the meantime, so nothing was transferred. Check it and try again.",
['Jonas Weber'],
"Le rôle de Jonas Weber a changé entre-temps, donc rien n'a été transféré. Vérifiez-le et réessayez.",
],
['User not removed', [], 'Utilisateur non retiré'],
[
"{0}'s role changed in the meantime, so nothing was removed. Check it and try again.",
['Ines Duarte'],
"Le rôle de Ines Duarte a changé entre-temps, donc rien n'a été retiré. Vérifiez-le et réessayez.",
],
['Role changed in the meantime', [], 'Rôle modifié entre-temps'],
[
'{0} is now {1}. Your choice is kept. Check it and try again.',
['Ines Duarte', 'Admin'],
'Ines Duarte a maintenant le rôle Admin. Votre choix est conservé. Vérifiez-le et réessayez.',
],
[
'{0} is now {1}. What you typed is kept. Check the change, then try again.',
['Jonas Weber', 'Writer'],
'Jonas Weber a maintenant le rôle Writer. Ce que vous avez saisi est conservé. Vérifiez le changement, puis réessayez.',
],
['Reload member', [], 'Recharger le membre'],
['Role reloaded', [], 'Rôle rechargé'],
[
'Your {0} changes are still here. Review them, then save.',
[2],
'Vos 2 modifications sont toujours là. Relisez-les, puis enregistrez.',
],
['Use the saved role', [], 'Utiliser le rôle enregistré'],
['Keep my edits', [], 'Garder mes modifications'],
['Loading…', [], 'Chargement…'],
['Locked', [], 'Verrouillé'],
]
describe('Final copy: toasts and errors, EN and FR', () => {
it.each(FINAL_COPY)('"%s" reads in English and in French', (key, values, french) => {
expect(t(key as keyof typeof messages, values)).toContain(
key.replace(/\{(\d+)\}/g, (_, index) => String(values[Number(index)])),
)
setLocale('fr')
expect(t('Assigned by {0}', ['Marta Alves'])).toBe('Attribué par Marta Alves')
expect(t(key as keyof typeof messages, values).replace(/\u2019/g, "'")).toBe(french)
})
})
const PROPOSED_COPY = [
'Remove user',
'Remove {0}?',
'They lose access straight away, and the API keys they created stop working. Their articles, entries and media stay.',
"Couldn't remove the user",
'User removed',
'{0} no longer has access.',
"You can't remove yourself. Ask another owner or admin.",
'Online articles and the drafts you created.',
'Drafts by others are hidden',
'Your role reads online articles and the drafts you created. The counts follow the same rule.',
'You have no drafts',
"Drafts you create appear here. Your role can't see drafts by other people.",
'Your role shows only entries you created.',
"Entries by others aren't shown",
'Your role reads only entries you created. Ask an owner or admin if you need to see more.',
"You haven't created {0} yet",
"Your role shows only entries you created, so other people's {0} aren't listed here. Use New entry to add one.",
'{0} saved changes to {1} at {2}.',
'Your 1 change is still here. Review it, then save.',
'read online articles and their own drafts',
'read only entries they created',
] as const
describe('Proposed copy that the design does not give', () => {
it.each(PROPOSED_COPY)('"%s" has a French entry', (key) => {
expect((messages as Record<string, string>)[key]).toMatch(/\S/)
})
})