feat: roles SPA foundations
This commit is contained in:
1 parent
80f7037d3a
commit
907949aa12
180 files changed
+4308
-835
No files matched your search
@@ -23,7 +23,6 @@ const SOURCES = [
|
||||
'components/PublishingLinksCard.vue',
|
||||
'components/ReassignDialog.vue',
|
||||
'components/SiteFormPanel.vue',
|
||||
'components/SitesForbidden.vue',
|
||||
'components/SlugField.vue',
|
||||
'components/SocialLinksRepeater.vue',
|
||||
'components/UserSelect.vue',
|
||||
|
||||
@@ -2831,6 +2831,92 @@ export const messages = {
|
||||
'Value in an entry': 'Valeur dans une entrée',
|
||||
'1 or higher. Default 1.': '1 ou plus. 1 par défaut.',
|
||||
'One of 5, 25, 50 or 100. Default 25.': '5, 25, 50 ou 100. 25 par défaut.',
|
||||
'Read entries': 'Lire les entrées',
|
||||
'Create entries': 'Créer des entrées',
|
||||
'Update entries': 'Modifier des entrées',
|
||||
'Delete entries': 'Supprimer des entrées',
|
||||
'Publish entries': 'Publier des entrées',
|
||||
'View content types': 'Voir les types de contenu',
|
||||
'Create and edit content types': 'Créer et modifier des types de contenu',
|
||||
'Delete content types': 'Supprimer des types de contenu',
|
||||
'View the media library': 'Voir la médiathèque',
|
||||
'Upload files': 'Téléverser des fichiers',
|
||||
'Delete files': 'Supprimer des fichiers',
|
||||
'View authors': 'Voir les auteurs',
|
||||
'Create authors': 'Créer des auteurs',
|
||||
'Edit authors': 'Modifier des auteurs',
|
||||
'Delete authors': 'Supprimer des auteurs',
|
||||
'See activity': 'Voir l’activité',
|
||||
'Export activity': 'Exporter l’activité',
|
||||
'View users': 'Voir les utilisateurs',
|
||||
'Invite users': 'Inviter des utilisateurs',
|
||||
"Change a user's role": 'Changer le rôle d’un utilisateur',
|
||||
'Remove users': 'Retirer des utilisateurs',
|
||||
'View settings': 'Voir les paramètres',
|
||||
'Edit general settings': 'Modifier les paramètres généraux',
|
||||
'Delete a site': 'Supprimer un site',
|
||||
'See API keys': 'Voir les clés d’API',
|
||||
'Create API keys': 'Créer des clés d’API',
|
||||
'Revoke API keys': 'Révoquer des clés d’API',
|
||||
'View roles': 'Voir les rôles',
|
||||
'Manage roles': 'Gérer les rôles',
|
||||
'Edit roles with owner-only power': 'Modifier les rôles à pouvoir réservé au propriétaire',
|
||||
'Apply software updates': 'Appliquer les mises à jour du logiciel',
|
||||
'Edit activity retention': 'Modifier la durée de conservation de l’activité',
|
||||
'Transfer ownership': 'Transférer la propriété',
|
||||
"You don't have permission to do that": 'Vous n’avez pas la permission de faire cela',
|
||||
"Your role doesn't include {0}. Ask an owner or admin.":
|
||||
'Votre rôle n’inclut pas « {0} ». Demandez à un propriétaire ou à un administrateur.',
|
||||
"Your role doesn't include this action. Ask an owner or admin.":
|
||||
'Votre rôle n’inclut pas cette action. Demandez à un propriétaire ou à un administrateur.',
|
||||
"You can't grant that": 'Vous ne pouvez pas accorder cela',
|
||||
'You can only grant what your role has.':
|
||||
'Vous ne pouvez accorder que ce que votre rôle possède.',
|
||||
'This role is locked': 'Ce rôle est verrouillé',
|
||||
"The Owner role can't be changed or deleted. Transfer ownership from Users instead.":
|
||||
'Le rôle Propriétaire ne peut être ni modifié ni supprimé. Transférez plutôt la propriété depuis Utilisateurs.',
|
||||
"You can't change your own role": 'Vous ne pouvez pas changer votre propre rôle',
|
||||
'Ask another owner or admin.': 'Demandez à un autre propriétaire ou administrateur.',
|
||||
"Built-in roles can't be deleted": 'Les rôles intégrés ne peuvent pas être supprimés',
|
||||
'Duplicate it to make a custom role.': 'Dupliquez-le pour créer un rôle personnalisé.',
|
||||
'Built-in roles keep their name.': 'Les rôles intégrés gardent leur nom.',
|
||||
'This changed somewhere else. Reload and try again.':
|
||||
'Cela a changé ailleurs. Rechargez la page et réessayez.',
|
||||
'View only': 'Lecture seule',
|
||||
'You can only edit content you created.':
|
||||
'Vous ne pouvez modifier que le contenu que vous avez créé.',
|
||||
"You don't have access to this page": 'Vous n’avez pas accès à cette page',
|
||||
"Your role, {0}, doesn't include it. Ask an owner or admin if you need it.":
|
||||
'Votre rôle, {0}, ne l’inclut pas. Demandez à un propriétaire ou à un administrateur si vous en avez besoin.',
|
||||
'Go to Articles': 'Aller aux articles',
|
||||
writer: 'rédacteur',
|
||||
'Only the owner can delete a site.': 'Seul le propriétaire peut supprimer un site.',
|
||||
'Only the owner can apply updates.': 'Seul le propriétaire peut appliquer les mises à jour.',
|
||||
'Apply update': 'Appliquer la mise à jour',
|
||||
'Admins can read the log. Only the owner can change how long it is kept.':
|
||||
'Les administrateurs peuvent lire le journal. Seul le propriétaire peut changer sa durée de conservation.',
|
||||
'How long activity is kept, and how much log data to keep. Whichever limit is reached first removes the oldest events.':
|
||||
'Durée de conservation de l’activité et volume de journal à garder. La première limite atteinte supprime les événements les plus anciens.',
|
||||
'You can read these settings but not change them':
|
||||
'Vous pouvez lire ces paramètres mais pas les modifier',
|
||||
'Ask the owner to change them, or ask for a role that can edit settings.':
|
||||
'Demandez au propriétaire de les modifier, ou demandez un rôle qui peut modifier les paramètres.',
|
||||
'You can create entries and edit your own.':
|
||||
'Vous pouvez créer des entrées et modifier les vôtres.',
|
||||
'Entries by others are view only': 'Les entrées des autres sont en lecture seule',
|
||||
'Your role lets you edit entries you created.':
|
||||
'Votre rôle vous permet de modifier les entrées que vous avez créées.',
|
||||
"Your role can't edit entries.": 'Votre rôle ne permet pas de modifier des entrées.',
|
||||
"Your role can't delete entries.": 'Votre rôle ne permet pas de supprimer des entrées.',
|
||||
"Your role can't edit articles.": 'Votre rôle ne permet pas de modifier des articles.',
|
||||
"Your role can't delete articles.": 'Votre rôle ne permet pas de supprimer des articles.',
|
||||
'Ask an editor to publish.': 'Demandez à un éditeur de publier.',
|
||||
'You can write and edit all articles. Publishing is done by an editor.':
|
||||
'Vous pouvez rédiger et modifier tous les articles. La publication est faite par un éditeur.',
|
||||
"Your role can't delete files.": 'Votre rôle ne permet pas de supprimer des fichiers.',
|
||||
'Save draft': 'Enregistrer le brouillon',
|
||||
'The id of the role to give. Absent or 0 means the Writer role. The Owner role is refused.':
|
||||
'L’identifiant du rôle à donner. Absent ou 0, c’est le rôle Rédacteur. Le rôle Propriétaire est refusé.',
|
||||
} as const
|
||||
|
||||
export type MessageKey = keyof typeof messages
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { API_GROUPS, SESSION_GROUPS } from '@/data/apiCatalogue'
|
||||
@@ -108,32 +108,16 @@ describe('Catalogue groups of Sites and Authors in French', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('The owner_only copy of the design board', () => {
|
||||
it.each([
|
||||
"You don't have access to Sites",
|
||||
'Only the owner can manage sites. Ask the owner of this site if you need a change.',
|
||||
'Only the owner can manage sites',
|
||||
'Ask the owner of this site.',
|
||||
])('"%s" has a French entry', (text) => {
|
||||
expect(frenchOf(text)).toMatch(/\S/)
|
||||
expect(frenchOf(text)).not.toBe(text)
|
||||
})
|
||||
|
||||
it('is used by the 403 page and by the action toast', () => {
|
||||
const page = readFileSync(
|
||||
join(import.meta.dirname, '..', 'components/SitesForbidden.vue'),
|
||||
'utf8',
|
||||
)
|
||||
const toast = readFileSync(
|
||||
describe('The retired owner-only sites copy', () => {
|
||||
it('shows nowhere any more: the page-level state and the generic toast replace it', () => {
|
||||
const toasts = readFileSync(
|
||||
join(import.meta.dirname, '..', 'composables/useDirectoryToasts.ts'),
|
||||
'utf8',
|
||||
)
|
||||
|
||||
expect(page).toContain("You don\\'t have access to Sites")
|
||||
expect(page).toContain(
|
||||
'Only the owner can manage sites. Ask the owner of this site if you need a change.',
|
||||
expect(toasts).not.toContain('Only the owner can manage sites')
|
||||
expect(existsSync(join(import.meta.dirname, '..', 'components/SitesForbidden.vue'))).toBe(
|
||||
false,
|
||||
)
|
||||
expect(toast).toContain('Only the owner can manage sites')
|
||||
expect(toast).toContain('Ask the owner of this site.')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { messages } from './messages'
|
||||
|
||||
const KEYS = [
|
||||
"You don't have permission to do that",
|
||||
"Your role doesn't include {0}. Ask an owner or admin.",
|
||||
"Your role doesn't include this action. Ask an owner or admin.",
|
||||
"You can't grant that",
|
||||
'This role is locked',
|
||||
"You can't change your own role",
|
||||
"Built-in roles can't be deleted",
|
||||
'Built-in roles keep their name.',
|
||||
'This changed somewhere else. Reload and try again.',
|
||||
"You don't have access to this page",
|
||||
"Your role, {0}, doesn't include it. Ask an owner or admin if you need it.",
|
||||
'Go to Articles',
|
||||
'View only',
|
||||
'Owner only',
|
||||
'Only the owner can apply updates.',
|
||||
'Admins can read the log. Only the owner can change how long it is kept.',
|
||||
'You can read these settings but not change them',
|
||||
'Ask the owner to change them, or ask for a role that can edit settings.',
|
||||
'You can create entries and edit your own.',
|
||||
'Entries by others are view only',
|
||||
"Your role can't delete articles.",
|
||||
'Ask an editor to publish.',
|
||||
'You can write and edit all articles. Publishing is done by an editor.',
|
||||
'Save draft',
|
||||
] as const
|
||||
|
||||
describe('Permission copy', () => {
|
||||
it.each(KEYS)('"%s" has a French entry', (key) => {
|
||||
const french = (messages as Record<string, string>)[key]
|
||||
expect(french).toMatch(/\S/)
|
||||
})
|
||||
})
|
||||
@@ -14,6 +14,7 @@ import { messages } from './messages'
|
||||
import { formatAbsoluteDateFromIso } from '@/lib/relativeDate'
|
||||
import { formatSize, pluralArticles } from '@/lib/mediaFormat'
|
||||
import { articleEnvelope, articleListUrl } from '@/views/__tests__/articleEnvelope'
|
||||
import { accessFor, ownerAccess } from '@/test/access'
|
||||
|
||||
vi.mock('@/composables/useApi', async () => {
|
||||
const { ref } = await import('vue')
|
||||
@@ -70,7 +71,7 @@ async function mountRoute(path: string) {
|
||||
username: 'marta',
|
||||
displayName: 'Marta',
|
||||
email: 'marta@example.com',
|
||||
role: 'owner',
|
||||
access: accessFor('owner'),
|
||||
}
|
||||
session.status = 'ready'
|
||||
await router.push(path)
|
||||
@@ -315,7 +316,7 @@ describe('Hardener localization outcomes', () => {
|
||||
async (authenticated) => {
|
||||
const { default: NotFoundView } = await import('@/views/NotFoundView.vue')
|
||||
useSessionStore().session = authenticated
|
||||
? { verified: true, username: 'marta', displayName: '' }
|
||||
? { verified: true, access: ownerAccess(), username: 'marta', displayName: '' }
|
||||
: null
|
||||
wrapper = mount(NotFoundView, {
|
||||
attachTo: document.body,
|
||||
@@ -389,6 +390,7 @@ describe('Hardener localization outcomes', () => {
|
||||
setLocale('fr')
|
||||
useSessionStore().session = {
|
||||
verified: true,
|
||||
access: ownerAccess(),
|
||||
username: 'marta',
|
||||
displayName: '',
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user