feat: Implementar rol Coordinador con permisos granulares
- Crear nuevo rol Coordinador con permisos específicos de gestión - Modificar Auth.php para soportar isCoordinador() y requireCoordinador() - Actualizar User.php con método getUsuariosGestion() para incluir coordinadores - Corregir Asignacion.php para que getAyudantesPorOrden() incluya coordinadores - Crear panel especial para coordinadores en coordinador.php - Implementar restricciones granulares en usuarios.php • Coordinadores no pueden ver/editar/desactivar administradores • No pueden crear otros administradores (se convierte a coordinador) • Solo pueden gestionar ayudantes y otros coordinadores - Actualizar navbar para mostrar rol específico con badges - Mejorar ayudante.php para que coordinadores puedan usar navbar completo - Añadir secciones especiales de gestión para coordinadores - Actualizar todos los PDFs y bot de Telegram para incluir coordinadores - Mantener retrocompatibilidad con usuarios y administradores existentes Permisos Coordinador: ✅ Ver/editar usuarios y ayudantes ✅ Gestionar turnos y orden de rotación ✅ Generar turnos automáticamente ✅ Exportar PDFs y usar bot de Telegram ❌ Acceder a configuración general, logs, webhook ❌ Administrar otros administradores
This commit is contained in:
@@ -9,7 +9,7 @@ require_once BASE_PATH . '/src/CSRF.php';
|
||||
require_once BASE_PATH . '/src/Session.php';
|
||||
|
||||
$auth = new Auth();
|
||||
$auth->requireAdmin();
|
||||
$auth->requireCoordinador();
|
||||
|
||||
$userModel = new User();
|
||||
$message = '';
|
||||
@@ -51,13 +51,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$password = $_POST['password'] ?? '';
|
||||
$rol = $_POST['rol'] ?? 'ayudante';
|
||||
|
||||
if (empty($nombre) || empty($email)) {
|
||||
// Obtener usuario actual para verificar su rol
|
||||
$usuarioActual = $userModel->getById($id);
|
||||
|
||||
// Prevenir que coordinadores editen administradores
|
||||
if ($usuarioActual && $usuarioActual['rol'] === 'admin' && !$auth->isAdmin()) {
|
||||
$message = 'No tienes permisos para editar administradores';
|
||||
$messageType = 'danger';
|
||||
}
|
||||
// Solo los administradores pueden asignar rol de administrador
|
||||
elseif ($rol === 'admin' && !$auth->isAdmin()) {
|
||||
$rol = 'coordinador';
|
||||
}
|
||||
elseif (empty($nombre) || empty($email)) {
|
||||
$message = 'Nombre y email son obligatorios';
|
||||
$messageType = 'danger';
|
||||
} elseif ($userModel->usernameExists($username, $id)) {
|
||||
}
|
||||
elseif ($userModel->usernameExists($username, $id)) {
|
||||
$message = 'El username ya está en uso';
|
||||
$messageType = 'danger';
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$userModel->update($id, compact('nombre', 'email', 'username', 'password', 'rol'));
|
||||
$message = 'Usuario actualizado exitosamente';
|
||||
$messageType = 'success';
|
||||
@@ -65,6 +79,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
} elseif ($action === 'toggle') {
|
||||
$id = $_POST['id'] ?? 0;
|
||||
$user = $userModel->getById($id);
|
||||
|
||||
// Prevenir que coordinadores desactiven administradores
|
||||
if ($user && $user['rol'] === 'admin' && !$auth->isAdmin()) {
|
||||
$message = 'No tienes permisos para modificar administradores';
|
||||
$messageType = 'danger';
|
||||
}
|
||||
elseif ($user && $user['id'] == Session::get('user_id')) {
|
||||
$message = 'No puedes desactivar tu propio usuario';
|
||||
$messageType = 'danger';
|
||||
}
|
||||
else {
|
||||
if ($user) {
|
||||
if ($user['activo']) {
|
||||
$userModel->deactivate($id);
|
||||
@@ -77,8 +102,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$users = $userModel->getAll(true);
|
||||
|
||||
// Filtrar administradores para coordinadores
|
||||
if ($auth->isCoordinador() && !$auth->isAdmin()) {
|
||||
$users = array_filter($users, function($user) {
|
||||
return $user['rol'] !== 'admin';
|
||||
});
|
||||
}
|
||||
$currentPage = 'usuarios';
|
||||
$pageTitle = 'Gestión de Usuarios';
|
||||
?>
|
||||
@@ -126,8 +159,19 @@ $pageTitle = 'Gestión de Usuarios';
|
||||
<td><?= htmlspecialchars($u['nombre']) ?></td>
|
||||
<td><?= htmlspecialchars($u['email']) ?></td>
|
||||
<td>
|
||||
<span class="badge bg-<?= $u['rol'] === 'admin' ? 'danger' : 'primary' ?>">
|
||||
<?= ucfirst($u['rol']) ?>
|
||||
<?php
|
||||
$badgeClass = 'primary';
|
||||
if ($u['rol'] === 'admin') $badgeClass = 'danger';
|
||||
elseif ($u['rol'] === 'coordinador') $badgeClass = 'success';
|
||||
?>
|
||||
<span class="badge bg-<?= $badgeClass ?>">
|
||||
<?php
|
||||
if ($u['rol'] === 'coordinador') {
|
||||
echo '🎯 Coordinador';
|
||||
} else {
|
||||
echo ucfirst($u['rol']);
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
@@ -140,7 +184,12 @@ $pageTitle = 'Gestión de Usuarios';
|
||||
onclick="editUser(<?= $u['id'] ?>, '<?= htmlspecialchars($u['nombre']) ?>', '<?= htmlspecialchars($u['email']) ?>', '<?= htmlspecialchars($u['username'] ?? '') ?>', '<?= $u['rol'] ?>')">
|
||||
Editar
|
||||
</button>
|
||||
<?php if ($u['id'] != Session::get('user_id')): ?>
|
||||
<?php
|
||||
// Determinar si puede desactivar este usuario
|
||||
$puedeDesactivar = ($u['id'] != Session::get('user_id')) && $u['rol'] !== 'admin';
|
||||
?>
|
||||
|
||||
<?php if ($puedeDesactivar): ?>
|
||||
<form method="POST" class="d-inline">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="action" value="toggle">
|
||||
@@ -194,7 +243,10 @@ $pageTitle = 'Gestión de Usuarios';
|
||||
<label for="rol" class="form-label">Rol</label>
|
||||
<select class="form-select" id="rol" name="rol">
|
||||
<option value="ayudante">Ayudante</option>
|
||||
<option value="coordinador">🎯 Coordinador</option>
|
||||
<?php if ($auth->isAdmin()): ?>
|
||||
<option value="admin">Administrador</option>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,24 +15,41 @@ $dbName = getenv('DB_NAME') ?: 'No configurado';
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<?php if ($auth->isAdmin()): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'dashboard' ? 'active' : '' ?>" href="/admin/index.php">Dashboard</a>
|
||||
</li>
|
||||
<?php else: ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'coordinador' ? 'active' : '' ?>" href="/admin/coordinador.php">🎯 Panel</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'usuarios' ? 'active' : '' ?>" href="/admin/usuarios.php">Usuarios</a>
|
||||
</li>
|
||||
|
||||
<?php if ($auth->isAdmin()): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'horarios' ? 'active' : '' ?>" href="/admin/horarios.php">Horarios</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'asignaciones' ? 'active' : '' ?>" href="/admin/asignaciones.php">Asignaciones</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'vista-ayudante' ? 'active' : '' ?>" href="/ayudante.php">👥 Vista Ayudante</a>
|
||||
</li>
|
||||
|
||||
<?php if ($auth->isAdmin()): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'webhook' ? 'active' : '' ?>" href="/admin/webhook.php">🤖 Bot</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'logs' ? 'active' : '' ?>" href="/admin/logs.php">Logs</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
@@ -44,7 +61,18 @@ $dbName = getenv('DB_NAME') ?: 'No configurado';
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><span class="dropdown-item-text d-block"><strong>Usuario:</strong> <?= htmlspecialchars($user['nombre'] ?? 'Usuario') ?></span></li>
|
||||
<li><span class="dropdown-item-text d-block"><strong>Rol:</strong> <?= htmlspecialchars(ucfirst($user['rol'] ?? '')) ?></span></li>
|
||||
<li><span class="dropdown-item-text d-block"><strong>Rol:</strong>
|
||||
<?php
|
||||
$rol = $user['rol'] ?? '';
|
||||
if ($rol === 'admin') {
|
||||
echo 'Administrador';
|
||||
} elseif ($rol === 'coordinador') {
|
||||
echo '🎯 Coordinador';
|
||||
} else {
|
||||
echo htmlspecialchars(ucfirst($rol));
|
||||
}
|
||||
?>
|
||||
</span></li>
|
||||
<li><span class="dropdown-item-text d-block small text-muted"><strong>DB Host:</strong> <?= htmlspecialchars($dbHost) ?></span></li>
|
||||
<li><span class="dropdown-item-text d-block small text-muted"><strong>DB Name:</strong> <?= htmlspecialchars($dbName) ?></span></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
@@ -221,7 +221,7 @@ public function asignar($userId, $semanaInicio) {
|
||||
SELECT u.*, ro.orden
|
||||
FROM users u
|
||||
LEFT JOIN rotacion_orden ro ON u.id = ro.user_id AND ro.activo = 1
|
||||
WHERE u.rol = 'ayudante' AND u.activo = 1
|
||||
WHERE (u.rol = 'ayudante' OR u.rol = 'coordinador') AND u.activo = 1
|
||||
ORDER BY COALESCE(ro.orden, 999), u.nombre
|
||||
");
|
||||
return $stmt->fetchAll();
|
||||
|
||||
17
src/Auth.php
17
src/Auth.php
@@ -43,10 +43,19 @@ class Auth {
|
||||
return Session::get('user_rol') === 'ayudante';
|
||||
}
|
||||
|
||||
public function isCoordinador() {
|
||||
return Session::get('user_rol') === 'coordinador';
|
||||
}
|
||||
|
||||
public function hasRole($role) {
|
||||
return Session::get('user_rol') === $role;
|
||||
}
|
||||
|
||||
public function hasAnyRole($roles) {
|
||||
$userRole = Session::get('user_rol');
|
||||
return in_array($userRole, (array)$roles);
|
||||
}
|
||||
|
||||
public function getCurrentUser() {
|
||||
if (!$this->isLoggedIn()) {
|
||||
return null;
|
||||
@@ -73,6 +82,14 @@ class Auth {
|
||||
}
|
||||
}
|
||||
|
||||
public function requireCoordinador($redirectUrl = '/ayudante.php') {
|
||||
$this->requireAuth($redirectUrl);
|
||||
if (!$this->isCoordinador() && !$this->isAdmin()) {
|
||||
header('Location: ' . $redirectUrl);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireRole($roles, $redirectUrl = '/') {
|
||||
$this->requireAuth($redirectUrl);
|
||||
$userRole = Session::get('user_rol');
|
||||
|
||||
Reference in New Issue
Block a user