feat(auth): nuevo rol 'admin' (programador, modo Dios oculto)
JERARQUÍA DE ROLES
admin = programador. Modo Dios. Oculto de dropdowns y del Panel
de Control para non-admins. Acceso total.
socio = modo Dios visible. Acceso al Panel, ve y edita todo.
abogado = crea casos, ve los suyos + donde es involucrado.
usuario = solo ve/edita donde es involucrado.
* Migración 008: agrega 'admin' al ENUM users.role. Promueve a
ozerpa@aal-law.com como admin.
* Auth.php: isAdmin() nuevo. isSocio() y isAbogado() ahora incluyen
admin (admin hereda todos los poderes de socio). canCreate/canDelete
también heredan.
* Lookups.php:
- abogadoNames() ya filtraba a role IN (socio, abogado) → admins no
aparecen en el dropdown "Abogado Solicitante".
- involucrablesUsers() agrega filtro role != 'admin' → admins no
aparecen en el picker de Involucrados.
- allUsers($includeAdmins) parametrizada: socios reciben la lista
sin admins, admins reciben todo.
* Bootstrap.php: window.DONNA.isAdmin disponible al frontend.
* admin/api.php:
- list_users pasa Auth::isAdmin() para filtrar.
- create_user / update_user: rechazan role='admin' si quien llama no
es admin. Solo admins pueden editar a otros admins.
- delete_user: protege admins (extends al check existente de socio).
- Self-protection extendida: admin no puede demoverse por debajo de
socio (queda en god-mode tier).
* admin.html: opción 'admin' en role dropdown solo visible si el
usuario actual es admin. Role pill navy/blanca para admin.
This commit is contained in:
+27
-7
@@ -10,7 +10,7 @@ header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
|
||||
|
||||
const ROLES = ['socio','abogado','usuario'];
|
||||
const ROLES = ['admin','socio','abogado','usuario'];
|
||||
|
||||
function ok($data = null): void {
|
||||
echo json_encode(['ok' => true, 'data' => $data, 'user' => Auth::user()], JSON_UNESCAPED_UNICODE);
|
||||
@@ -32,7 +32,8 @@ $pdo = Db::pdo();
|
||||
|
||||
try {
|
||||
if ($method === 'GET' && $action === 'list_users') {
|
||||
ok(Lookups::allUsers());
|
||||
// Los socios no ven a los admins; los admins ven todo
|
||||
ok(Lookups::allUsers(Auth::isAdmin()));
|
||||
}
|
||||
|
||||
if ($method === 'POST' && $action === 'create_user') {
|
||||
@@ -46,6 +47,11 @@ try {
|
||||
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
|
||||
$orden = (int)($b['orden'] ?? 0);
|
||||
|
||||
// Solo admins pueden crear nuevos admins
|
||||
if ($role === 'admin' && !Auth::isAdmin()) {
|
||||
err('Solo los admins pueden crear nuevos admins', 403);
|
||||
}
|
||||
|
||||
$exists = $pdo->prepare('SELECT id FROM users WHERE email = :e');
|
||||
$exists->execute([':e' => $email]);
|
||||
if ($exists->fetch()) err('Ya existe un usuario con ese email', 409);
|
||||
@@ -82,10 +88,21 @@ try {
|
||||
$newRole = in_array(($b['role'] ?? $existing['role']), ROLES, true) ? $b['role'] : $existing['role'];
|
||||
$newActivo = isset($b['activo']) ? ((int)$b['activo'] === 1 ? 1 : 0) : (int)$existing['activo'];
|
||||
|
||||
// Salvaguardas: el socio no puede demoverse ni desactivarse a sí mismo
|
||||
// Solo admins pueden editar a otros admins
|
||||
if ($existing['role'] === 'admin' && !Auth::isAdmin()) {
|
||||
err('Solo los admins pueden editar a otros admins', 403);
|
||||
}
|
||||
// Solo admins pueden asignar el rol admin
|
||||
if ($newRole === 'admin' && !Auth::isAdmin()) {
|
||||
err('Solo los admins pueden asignar el rol admin', 403);
|
||||
}
|
||||
|
||||
// Salvaguardas: no puedes quitarte tu modo Dios ni desactivarte
|
||||
if ((int)$existing['id'] === $me) {
|
||||
if ($newRole !== 'socio') err('No puedes quitarte el rol de Socio a ti mismo', 400);
|
||||
if ($newActivo === 0) err('No puedes desactivarte a ti mismo', 400);
|
||||
if (!in_array($newRole, ['admin','socio'], true)) {
|
||||
err('No puedes quitarte el modo Dios a ti mismo (debe quedar Admin o Socio)', 400);
|
||||
}
|
||||
if ($newActivo === 0) err('No puedes desactivarte a ti mismo', 400);
|
||||
}
|
||||
|
||||
$newEmail = isset($b['email']) ? strtolower(trim((string)$b['email'])) : $existing['email'];
|
||||
@@ -128,8 +145,11 @@ try {
|
||||
$sel->execute([':id' => $id]);
|
||||
$u = $sel->fetch();
|
||||
if (!$u) err('Usuario no encontrado', 404);
|
||||
if ($u['role'] === 'socio') {
|
||||
err('No puedes eliminar a otro Socio. Cambia su rol a Abogado o Usuario primero.', 400);
|
||||
if ($u['role'] === 'admin' && !Auth::isAdmin()) {
|
||||
err('Solo los admins pueden eliminar a otros admins', 403);
|
||||
}
|
||||
if (in_array($u['role'], ['admin','socio'], true)) {
|
||||
err('No puedes eliminar a un Admin o Socio. Cambia su rol a Abogado o Usuario primero.', 400);
|
||||
}
|
||||
|
||||
// CASCADE de tramites_involucrados limpia los vínculos automáticamente.
|
||||
|
||||
Reference in New Issue
Block a user