Files
donna/sql/005_users_roles.sql
T
Soporte ZH Consultores 2db8f23ba5 feat(perms): permisología completa con 3 roles (Socio/Abogado/Usuario) + Panel de Control
ESQUEMA (migraciones 005 + 006)
* users: agrega role ENUM('socio','abogado','usuario'), apellido, activo, orden
* Seed: cabrego@aal-law.com como socio + 15 placeholders por apellido para
  poblar el dropdown "Abogado Solicitante" hasta que los reales se logueen.
* tramites_involucrados: tabla N:M (tramite_id, user_id) con CASCADE delete.

AUTH (src/Auth.php)
* userRow() cachea el row del usuario actual por request.
* role(), isSocio(), isAbogado(), canCreate(), canDelete(), requireSocio().
* completeLogin() retorna bool: false si user.activo=0 → callback muestra
  pantalla "cuenta deshabilitada" en lugar de loguear.

BOOTSTRAP (src/Bootstrap.php + src/Lookups.php)
* Bootstrap::inject(view) reemplaza readfile en los wrappers; inyecta
  <script>window.DONNA={me,name,role,isSocio,isAbogado,canCreate,canDelete,
  abogados,users}</script> antes de </head> para que el frontend tenga
  contexto sin requests extra.

TRAMITES — visibilidad + involucrados
* api.php: list filtra por (socio | creador | abogado solicitante mapped via
  users.apellido | involucrado) excepto socios que ven todo. Todas las
  mutaciones validan canView(). create/delete validan rol. Persiste
  involucrados vía syncInvolucrados().
* tramites.html: nueva columna "Involucrados" después de "Abogado", chip
  picker multi-select en el modal, gear icon (oculto a non-socios), oculta
  botones "+ Nuevo" y ✕ para usuarios sin permisos. Auto-incluye al
  creador como involucrado por defecto.
* Calendario y demás apps consumen el API filtrado → heredan la
  visibilidad sin código nuevo.

PANEL DE CONTROL (/admin/)
* index.php: requireSocio() + Bootstrap injection.
* api.php: list_users, create_user, update_user. Salvaguardas: el socio
  no puede demoverse ni desactivarse a sí mismo.
* admin.html: tabla unificada de usuarios con filtros, modal CRUD,
  resaltado de fila propia, placeholders identificados visualmente.

GEAR ICON
* Agregado en escrituras.html, tramites.html, calendario.html con
  display:none por defecto; JS lo revela si window.DONNA.isSocio.
* Link a /admin/.
2026-06-04 23:14:07 +00:00

53 lines
3.5 KiB
SQL

-- ============================================================
-- Donna — Schema 005: Roles + apellido en tabla users
-- ============================================================
-- Modelo de permisos:
-- socio = modo Dios, ve y edita todo, acceso al Panel de Control
-- abogado = crea casos. Ve/edita los que creó, los donde es abogado
-- solicitante (matching users.apellido = tramite.abogado),
-- y los donde fue involucrado. Puede eliminar lo suyo.
-- usuario = pasante/asistente. No crea ni elimina. Solo ve/edita
-- donde fue marcado como involucrado.
ALTER TABLE users
ADD COLUMN IF NOT EXISTS role ENUM('socio','abogado','usuario')
NOT NULL DEFAULT 'usuario' AFTER name,
ADD COLUMN IF NOT EXISTS apellido VARCHAR(100) NOT NULL DEFAULT '' AFTER role,
ADD COLUMN IF NOT EXISTS activo TINYINT(1) NOT NULL DEFAULT 1 AFTER apellido,
ADD COLUMN IF NOT EXISTS orden INT NOT NULL DEFAULT 0 AFTER activo,
ADD INDEX IF NOT EXISTS idx_role (role),
ADD INDEX IF NOT EXISTS idx_apellido (apellido),
ADD INDEX IF NOT EXISTS idx_activo (activo);
-- Bootstrap: el admin (cabrego@aal-law.com) queda como Socio con apellido Abrego
INSERT INTO users (email, name, role, apellido, activo, first_seen_at, last_login_at)
VALUES ('cabrego@aal-law.com', 'Carlos Abrego', 'socio', 'Abrego', 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE role='socio', activo=1, apellido='Abrego';
-- Seed: 15 apellidos placeholder para que los dropdowns no salgan vacíos.
-- Los emails son sintéticos (placeholder-*); el Socio los reemplaza desde el
-- Panel de Control conforme los abogados reales se vayan logueando.
INSERT IGNORE INTO users (email, name, role, apellido, activo, orden) VALUES
('placeholder-arias@aal-law.com', '(Asignar email real)', 'abogado', 'Arias', 1, 1),
('placeholder-abrego@aal-law.com', '(Asignar email real)', 'abogado', 'Abrego', 1, 2),
('placeholder-lopez@aal-law.com', '(Asignar email real)', 'abogado', 'Lopez', 1, 3),
('placeholder-altafulla@aal-law.com', '(Asignar email real)', 'abogado', 'Altafulla', 1, 4),
('placeholder-alvarez@aal-law.com', '(Asignar email real)', 'abogado', 'Álvarez', 1, 5),
('placeholder-gutierrez@aal-law.com', '(Asignar email real)', 'abogado', 'Gutiérrez', 1, 6),
('placeholder-cedeno@aal-law.com', '(Asignar email real)', 'abogado', 'Cedeño', 1, 7),
('placeholder-mariscal@aal-law.com', '(Asignar email real)', 'abogado', 'Mariscal', 1, 8),
('placeholder-avila@aal-law.com', '(Asignar email real)', 'abogado', 'Ávila', 1, 9),
('placeholder-agudo@aal-law.com', '(Asignar email real)', 'abogado', 'Agudo', 1, 10),
('placeholder-martinez@aal-law.com', '(Asignar email real)', 'abogado', 'Martínez', 1, 11),
('placeholder-degracia@aal-law.com', '(Asignar email real)', 'abogado', 'De Gracia', 1, 12),
('placeholder-gondola@aal-law.com', '(Asignar email real)', 'abogado', 'Góndola', 1, 13),
('placeholder-gonzalez@aal-law.com', '(Asignar email real)', 'abogado', 'González', 1, 14),
('placeholder-valdes@aal-law.com', '(Asignar email real)', 'abogado', 'Valdés', 1, 15);
-- Si el placeholder de Abrego ya existe y hay un usuario real Abrego con apellido asignado,
-- desactivar el placeholder para evitar duplicados visibles en dropdowns.
UPDATE users p
JOIN users r ON r.apellido = p.apellido AND r.id != p.id AND r.email NOT LIKE 'placeholder-%'
SET p.activo = 0
WHERE p.email LIKE 'placeholder-%' AND p.activo = 1;