refactor(users)!: merge users.edit and users.delete into users.manage permission
BREAKING CHANGE: permissions `users.edit` and `users.delete` have been replaced by a single `users.manage` permission; any role or code referencing the old keys must be updated - remove `USERS_EDIT` and `USERS_DELETE` from `PERMISSIONS` and `PERMISSION_DEFINITIONS` - add `USERS_MANAGE` permission covering create, edit and delete actions - update `db.js` to use `users.manage` in permission checks - update `auth/api.js` to reference the new permission key - update `UsersPage.client.js` to check `users.manage` instead of old keys - update `api/define.js` and all README examples to reflect the new key
This commit is contained in:
@@ -181,7 +181,7 @@ Champs optionnels :
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `skipRateLimit` | `boolean` | Exempte la route du rate limiting par IP (ex. health checks) |
|
||||
| `permission` | `string` | Sur une route `auth: 'admin'`, exige en plus cette clé de permission granulaire (ex. `'users.edit'`). Retourne 403 si l'utilisateur ne la possède pas. Voir `PERMISSIONS` dans `src/core/users/constants.js` |
|
||||
| `permission` | `string` | Sur une route `auth: 'admin'`, exige en plus cette clé de permission granulaire (ex. `'users.manage'`). Retourne 403 si l'utilisateur ne la possède pas. Voir `PERMISSIONS` dans `src/core/users/constants.js` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* (e.g. health checks from monitoring systems).
|
||||
* permission {string} When set on an 'admin' route, the router additionally
|
||||
* verifies that the authenticated user holds this granular
|
||||
* permission key (e.g. 'users.edit'). If the user lacks
|
||||
* permission key (e.g. 'users.manage'). If the user lacks
|
||||
* the permission, the request is rejected with 403 Forbidden.
|
||||
*
|
||||
* Auth levels:
|
||||
|
||||
@@ -204,7 +204,7 @@ const role = await createRole({ name: 'Modérateur', description: 'Peut gérer l
|
||||
|
||||
await updateRole(roleId, {
|
||||
name: 'Modérateur',
|
||||
permissionKeys: [PERMISSIONS.USERS_VIEW, PERMISSIONS.USERS_EDIT],
|
||||
permissionKeys: [PERMISSIONS.USERS_VIEW, PERMISSIONS.USERS_MANAGE],
|
||||
});
|
||||
|
||||
await deleteRole(roleId); // impossible sur les rôles système
|
||||
@@ -230,7 +230,7 @@ const keys = await getUserPermissions(userId);
|
||||
| Groupe | Clés |
|
||||
|--------|------|
|
||||
| Administration | `admin.access` |
|
||||
| Utilisateurs | `users.view`, `users.edit`, `users.delete` |
|
||||
| Utilisateurs | `users.view`, `users.manage` |
|
||||
| Rôles | `roles.view`, `roles.manage` |
|
||||
|
||||
---
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
export const PERMISSIONS = {
|
||||
ADMIN_ACCESS: 'admin.access',
|
||||
USERS_VIEW: 'users.view',
|
||||
USERS_EDIT: 'users.edit',
|
||||
USERS_DELETE: 'users.delete',
|
||||
USERS_MANAGE: 'users.manage',
|
||||
ROLES_VIEW: 'roles.view',
|
||||
ROLES_MANAGE: 'roles.manage',
|
||||
};
|
||||
@@ -15,8 +14,7 @@ export const PERMISSIONS = {
|
||||
export const PERMISSION_DEFINITIONS = [
|
||||
{ key: 'admin.access', name: 'Accès au panneau admin', description: "Permet d'accéder à l'interface d'administration.", group_name: 'Administration' },
|
||||
{ key: 'users.view', name: 'Voir les utilisateurs', description: 'Permet de consulter la liste des membres et leurs profils.', group_name: 'Utilisateurs' },
|
||||
{ key: 'users.edit', name: 'Modifier les utilisateurs', description: 'Permet de changer les informations et les rôles des membres.', group_name: 'Utilisateurs' },
|
||||
{ key: 'users.delete', name: 'Supprimer des utilisateurs', description: 'Permet de supprimer des comptes membres.', group_name: 'Utilisateurs' },
|
||||
{ key: 'users.manage', name: 'Gérer les utilisateurs', description: 'Permet de créer, modifier et supprimer des comptes membres.', group_name: 'Utilisateurs' },
|
||||
{ key: 'roles.view', name: 'Voir les rôles', description: 'Permet de consulter la liste des rôles et leurs permissions.', group_name: 'Rôles' },
|
||||
{ key: 'roles.manage', name: 'Gérer les rôles', description: 'Permet de créer, modifier et supprimer des rôles.', group_name: 'Rôles' },
|
||||
];
|
||||
|
||||
@@ -66,6 +66,20 @@ async function dropRoleCheckConstraint() {
|
||||
`);
|
||||
}
|
||||
|
||||
async function migratePermissions() {
|
||||
// Migrate users.edit / users.delete → users.manage
|
||||
await query(`
|
||||
INSERT INTO zen_auth_role_permissions (role_id, permission_key)
|
||||
SELECT DISTINCT role_id, 'users.manage'
|
||||
FROM zen_auth_role_permissions
|
||||
WHERE permission_key IN ('users.edit', 'users.delete')
|
||||
AND EXISTS (SELECT 1 FROM zen_auth_permissions WHERE key = 'users.manage')
|
||||
ON CONFLICT DO NOTHING
|
||||
`);
|
||||
await query(`DELETE FROM zen_auth_role_permissions WHERE permission_key IN ('users.edit', 'users.delete')`);
|
||||
await query(`DELETE FROM zen_auth_permissions WHERE key IN ('users.edit', 'users.delete')`);
|
||||
}
|
||||
|
||||
async function seedDefaultRolesAndPermissions() {
|
||||
// Permissions
|
||||
for (const perm of PERMISSION_DEFINITIONS) {
|
||||
@@ -75,6 +89,8 @@ async function seedDefaultRolesAndPermissions() {
|
||||
);
|
||||
}
|
||||
|
||||
await migratePermissions();
|
||||
|
||||
// Admin role
|
||||
const adminRoleId = generateId();
|
||||
await query(
|
||||
|
||||
@@ -174,7 +174,7 @@ const UsersPageClient = ({ currentUserId, refreshKey, canEdit }) => {
|
||||
const UsersPage = ({ user }) => {
|
||||
const [createModalOpen, setCreateModalOpen] = useState(false);
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
const canEdit = user?.permissions?.includes('users.edit');
|
||||
const canEdit = user?.permissions?.includes('users.manage');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 sm:gap-6 lg:gap-8">
|
||||
|
||||
@@ -897,7 +897,7 @@ async function handleAdminCreateUser(request) {
|
||||
|
||||
export const routes = defineApiRoutes([
|
||||
{ path: '/users', method: 'GET', handler: handleListUsers, auth: 'admin', permission: PERMISSIONS.USERS_VIEW },
|
||||
{ path: '/users', method: 'POST', handler: handleAdminCreateUser, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users', method: 'POST', handler: handleAdminCreateUser, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/users/profile', method: 'PUT', handler: handleUpdateProfile, auth: 'user' },
|
||||
{ path: '/users/profile/email', method: 'POST', handler: handleInitiateEmailChange, auth: 'user' },
|
||||
{ path: '/users/profile/password', method: 'POST', handler: handleChangeOwnPassword, auth: 'user' },
|
||||
@@ -908,13 +908,13 @@ export const routes = defineApiRoutes([
|
||||
{ path: '/users/profile/sessions/:sessionId', method: 'DELETE', handler: handleDeleteSession, auth: 'user' },
|
||||
{ path: '/users/email/confirm', method: 'GET', handler: handleConfirmEmailChange, auth: 'user' },
|
||||
{ path: '/users/:id/roles', method: 'GET', handler: handleGetUserRoles, auth: 'admin', permission: PERMISSIONS.USERS_VIEW },
|
||||
{ path: '/users/:id/roles', method: 'POST', handler: handleAssignUserRole, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/roles/:roleId', method: 'DELETE', handler: handleRevokeUserRole, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/roles', method: 'POST', handler: handleAssignUserRole, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/users/:id/roles/:roleId', method: 'DELETE', handler: handleRevokeUserRole, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/users/:id', method: 'GET', handler: handleGetUserById, auth: 'admin', permission: PERMISSIONS.USERS_VIEW },
|
||||
{ path: '/users/:id', method: 'PUT', handler: handleUpdateUserById, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/email', method: 'PUT', handler: handleAdminUpdateUserEmail, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/password', method: 'PUT', handler: handleAdminSetUserPassword, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id/send-password-reset', method: 'POST', handler: handleAdminSendPasswordReset, auth: 'admin', permission: PERMISSIONS.USERS_EDIT },
|
||||
{ path: '/users/:id', method: 'PUT', handler: handleUpdateUserById, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/users/:id/email', method: 'PUT', handler: handleAdminUpdateUserEmail, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/users/:id/password', method: 'PUT', handler: handleAdminSetUserPassword, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/users/:id/send-password-reset', method: 'POST', handler: handleAdminSendPasswordReset, auth: 'admin', permission: PERMISSIONS.USERS_MANAGE },
|
||||
{ path: '/roles', method: 'GET', handler: handleListRoles, auth: 'admin', permission: PERMISSIONS.ROLES_VIEW },
|
||||
{ path: '/roles', method: 'POST', handler: handleCreateRole, auth: 'admin', permission: PERMISSIONS.ROLES_MANAGE },
|
||||
{ path: '/roles/:id', method: 'GET', handler: handleGetRole, auth: 'admin', permission: PERMISSIONS.ROLES_VIEW },
|
||||
|
||||
Reference in New Issue
Block a user