Files
contenedor_ibiza/public/admin/usuarios.php
nickpons666 67c4d8173f 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
2026-01-31 01:54:14 -06:00

285 lines
13 KiB
PHP
Executable File

<?php
if (!defined('BASE_PATH')) {
define('BASE_PATH', dirname(__DIR__, 2));
}
require_once BASE_PATH . '/config/config.php';
require_once BASE_PATH . '/src/Auth.php';
require_once BASE_PATH . '/src/User.php';
require_once BASE_PATH . '/src/CSRF.php';
require_once BASE_PATH . '/src/Session.php';
$auth = new Auth();
$auth->requireCoordinador();
$userModel = new User();
$message = '';
$messageType = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!CSRF::isValidRequest()) {
$message = 'Error de validación del formulario';
$messageType = 'danger';
} else {
$action = $_POST['action'] ?? '';
if ($action === 'create') {
$nombre = trim($_POST['nombre'] ?? '');
$email = trim($_POST['email'] ?? '');
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$rol = $_POST['rol'] ?? 'ayudante';
if (empty($nombre) || empty($email) || empty($password)) {
$message = 'Todos los campos son obligatorios';
$messageType = 'danger';
} elseif ($userModel->getByEmail($email)) {
$message = 'El email ya está registrado';
$messageType = 'danger';
} elseif ($username && $userModel->usernameExists($username)) {
$message = 'El username ya está en uso';
$messageType = 'danger';
} else {
$userModel->create(compact('nombre', 'email', 'username', 'password', 'rol'));
$message = 'Usuario creado exitosamente';
$messageType = 'success';
}
} elseif ($action === 'update') {
$id = $_POST['id'] ?? 0;
$nombre = trim($_POST['nombre'] ?? '');
$email = trim($_POST['email'] ?? '');
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$rol = $_POST['rol'] ?? 'ayudante';
// 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)) {
$message = 'El username ya está en uso';
$messageType = 'danger';
}
else {
$userModel->update($id, compact('nombre', 'email', 'username', 'password', 'rol'));
$message = 'Usuario actualizado exitosamente';
$messageType = 'success';
}
} 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);
} else {
$userModel->activate($id);
}
$message = 'Estado actualizado';
$messageType = 'success';
}
}
}
}
}
$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';
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Usuarios - Contenedor Ibiza</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<?php include BASE_PATH . '/public/partials/navbar.php'; ?>
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Gestión de Usuarios</h2>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#userModal" onclick="resetForm()">
+ Nuevo Usuario
</button>
</div>
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<div class="card shadow-sm">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>Username</th>
<th>Nombre</th>
<th>Email</th>
<th>Rol</th>
<th>Estado</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $u): ?>
<tr>
<td><?= htmlspecialchars($u['username'] ?? '-') ?></td>
<td><?= htmlspecialchars($u['nombre']) ?></td>
<td><?= htmlspecialchars($u['email']) ?></td>
<td>
<?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>
<span class="badge bg-<?= $u['activo'] ? 'success' : 'secondary' ?>">
<?= $u['activo'] ? 'Activo' : 'Inactivo' ?>
</span>
</td>
<td>
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#userModal"
onclick="editUser(<?= $u['id'] ?>, '<?= htmlspecialchars($u['nombre']) ?>', '<?= htmlspecialchars($u['email']) ?>', '<?= htmlspecialchars($u['username'] ?? '') ?>', '<?= $u['rol'] ?>')">
Editar
</button>
<?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">
<input type="hidden" name="id" value="<?= $u['id'] ?>">
<button type="submit" class="btn btn-sm btn-<?= $u['activo'] ? 'outline-warning' : 'outline-success' ?>">
<?= $u['activo'] ? 'Desactivar' : 'Activar' ?>
</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal fade" id="userModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle">Nuevo Usuario</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" id="userForm">
<?= CSRF::getTokenField() ?>
<input type="hidden" name="action" value="create" id="formAction">
<input type="hidden" name="id" value="" id="userId">
<div class="modal-body">
<div class="mb-3">
<label for="nombre" class="form-label">Nombre Completo</label>
<input type="text" class="form-control" id="nombre" name="nombre" required>
</div>
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" placeholder="Opcional">
<small class="text-muted">Para iniciar sesión con nombre de usuario</small>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Contraseña</label>
<input type="password" class="form-control" id="password" name="password">
<small class="text-muted">Dejar en blanco para mantener la actual</small>
</div>
<div class="mb-3">
<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>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar</button>
</div>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
function resetForm() {
document.getElementById('modalTitle').textContent = 'Nuevo Usuario';
document.getElementById('formAction').value = 'create';
document.getElementById('userId').value = '';
document.getElementById('userForm').reset();
document.getElementById('password').required = true;
}
function editUser(id, nombre, email, username, rol) {
document.getElementById('modalTitle').textContent = 'Editar Usuario';
document.getElementById('formAction').value = 'update';
document.getElementById('userId').value = id;
document.getElementById('nombre').value = nombre;
document.getElementById('email').value = email;
document.getElementById('username').value = username;
document.getElementById('rol').value = rol;
document.getElementById('password').required = false;
}
</script>
</body>
</html>