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:
+14
-2
@@ -81,6 +81,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
|
||||
.role-pill { display:inline-block; padding:2px 9px; border-radius:14px; font-size:10.5px; font-weight:700;
|
||||
letter-spacing:.04em; text-transform:uppercase; }
|
||||
.role-admin { background:#1B3A6B; color:#fff; }
|
||||
.role-socio { background:#FCE4EC; color:#880E4F; }
|
||||
.role-abogado { background:#E1F5EE; color:#085041; }
|
||||
.role-usuario { background:#EEEDE9; color:#5F5E5A; }
|
||||
@@ -167,6 +168,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
<input type="search" id="search" placeholder="Buscar por email o nombre…">
|
||||
<select id="f-role">
|
||||
<option value="">— Todos los roles —</option>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="socio">Socio</option>
|
||||
<option value="abogado">Abogado</option>
|
||||
<option value="usuario">Usuario</option>
|
||||
@@ -223,6 +225,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
<option value="usuario">Usuario (pasante / asistente)</option>
|
||||
<option value="abogado">Abogado</option>
|
||||
<option value="socio">Socio (modo Dios)</option>
|
||||
<option value="admin" id="opt-admin" style="display:none;">Admin (programador, modo Dios oculto)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -251,9 +254,18 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
const ROLES = ['socio','abogado','usuario'];
|
||||
const ROLE_LABEL = { socio:'Socio', abogado:'Abogado', usuario:'Usuario' };
|
||||
const ROLES = ['admin','socio','abogado','usuario'];
|
||||
const ROLE_LABEL = { admin:'Admin', socio:'Socio', abogado:'Abogado', usuario:'Usuario' };
|
||||
const MY_EMAIL = (window.DONNA && window.DONNA.me) || '';
|
||||
const I_AM_ADMIN = !!(window.DONNA && window.DONNA.isAdmin);
|
||||
|
||||
// Mostrar la opción "admin" en el dropdown solo si el usuario actual es admin
|
||||
if (I_AM_ADMIN) {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const opt = document.getElementById('opt-admin');
|
||||
if (opt) opt.style.display = '';
|
||||
});
|
||||
}
|
||||
|
||||
let users = [];
|
||||
let editingId = null;
|
||||
|
||||
Reference in New Issue
Block a user