Mejoras de seguridad y nueva tabla de turnos para ayudantes
- Agregado sistema de protección CSRF con tokens - Creada clase Session para gestión centralizada de sesiones - Mejorado manejo de errores en Database (sin die()) - Refactorizado Auth para usar nueva clase Session - Agregada validación CSRF a formularios de login y admin - Agregada validación de roles en modelo User - Mejorada vista de ayudante con tabla de horarios por semana - Agregada tabla de Turnos de Ayudantes con fechas en columnas
This commit is contained in:
@@ -7,6 +7,7 @@ require_once BASE_PATH . '/src/Auth.php';
|
||||
require_once BASE_PATH . '/src/User.php';
|
||||
require_once BASE_PATH . '/src/DiasHorarios.php';
|
||||
require_once BASE_PATH . '/src/Asignacion.php';
|
||||
require_once BASE_PATH . '/src/CSRF.php';
|
||||
|
||||
$auth = new Auth();
|
||||
$auth->requireAdmin();
|
||||
@@ -19,52 +20,57 @@ $message = '';
|
||||
$messageType = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
if (!CSRF::isValidRequest()) {
|
||||
$message = 'Error de validación del formulario';
|
||||
$messageType = 'danger';
|
||||
} else {
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
if ($action === 'asignar') {
|
||||
$userId = $_POST['user_id'] ?? 0;
|
||||
$semana = $_POST['semana'] ?? '';
|
||||
if ($action === 'asignar') {
|
||||
$userId = $_POST['user_id'] ?? 0;
|
||||
$semana = $_POST['semana'] ?? '';
|
||||
|
||||
if ($userId && $semana) {
|
||||
$asignacionModel->asignar($userId, $semana);
|
||||
$message = 'Turno asignado correctamente';
|
||||
$messageType = 'success';
|
||||
}
|
||||
} elseif ($action === 'rotar') {
|
||||
$semana = $_POST['semana'] ?? '';
|
||||
$asignacionActual = $asignacionModel->getAsignacionPorSemana($semana);
|
||||
|
||||
if ($asignacionActual) {
|
||||
$proximaPersona = $asignacionModel->getProximaPersona($asignacionActual['user_id']);
|
||||
if ($proximaPersona) {
|
||||
$asignacionModel->asignar($proximaPersona['id'], $semana);
|
||||
$message = 'Turno rotado a: ' . htmlspecialchars($proximaPersona['nombre']);
|
||||
if ($userId && $semana) {
|
||||
$asignacionModel->asignar($userId, $semana);
|
||||
$message = 'Turno asignado correctamente';
|
||||
$messageType = 'success';
|
||||
}
|
||||
}
|
||||
} elseif ($action === 'asignar_masivo') {
|
||||
$userIds = $_POST['user_ids'] ?? [];
|
||||
$semanaInicio = $_POST['semana_inicio'] ?? '';
|
||||
$rotacionAutomatica = isset($_POST['rotacion_automatica']) ? true : false;
|
||||
|
||||
if (!empty($userIds) && $semanaInicio) {
|
||||
$resultado = $asignacionModel->asignarMasivo($userIds, $semanaInicio, $rotacionAutomatica);
|
||||
} elseif ($action === 'rotar') {
|
||||
$semana = $_POST['semana'] ?? '';
|
||||
$asignacionActual = $asignacionModel->getAsignacionPorSemana($semana);
|
||||
|
||||
if ($resultado['success'] > 0) {
|
||||
$message = "Se asignaron {$resultado['success']} turnos correctamente";
|
||||
if ($rotacionAutomatica) {
|
||||
$message .= " con rotación automática para la siguiente semana";
|
||||
if ($asignacionActual) {
|
||||
$proximaPersona = $asignacionModel->getProximaPersona($asignacionActual['user_id']);
|
||||
if ($proximaPersona) {
|
||||
$asignacionModel->asignar($proximaPersona['id'], $semana);
|
||||
$message = 'Turno rotado a: ' . htmlspecialchars($proximaPersona['nombre']);
|
||||
$messageType = 'success';
|
||||
}
|
||||
$messageType = 'success';
|
||||
}
|
||||
|
||||
if (!empty($resultado['errors'])) {
|
||||
$message .= "<br>Errores: " . implode('<br>', $resultado['errors']);
|
||||
$messageType = 'warning';
|
||||
} elseif ($action === 'asignar_masivo') {
|
||||
$userIds = $_POST['user_ids'] ?? [];
|
||||
$semanaInicio = $_POST['semana_inicio'] ?? '';
|
||||
$rotacionAutomatica = isset($_POST['rotacion_automatica']) ? true : false;
|
||||
|
||||
if (!empty($userIds) && $semanaInicio) {
|
||||
$resultado = $asignacionModel->asignarMasivo($userIds, $semanaInicio, $rotacionAutomatica);
|
||||
|
||||
if ($resultado['success'] > 0) {
|
||||
$message = "Se asignaron {$resultado['success']} turnos correctamente";
|
||||
if ($rotacionAutomatica) {
|
||||
$message .= " con rotación automática para la siguiente semana";
|
||||
}
|
||||
$messageType = 'success';
|
||||
}
|
||||
|
||||
if (!empty($resultado['errors'])) {
|
||||
$message .= "<br>Errores: " . implode('<br>', $resultado['errors']);
|
||||
$messageType = 'warning';
|
||||
}
|
||||
} else {
|
||||
$message = 'Debes seleccionar al menos un ayudante y una semana';
|
||||
$messageType = 'danger';
|
||||
}
|
||||
} else {
|
||||
$message = 'Debes seleccionar al menos un ayudante y una semana';
|
||||
$messageType = 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +173,7 @@ $pageTitle = 'Asignación de Turnos';
|
||||
</div>
|
||||
|
||||
<form method="POST" class="d-flex gap-2">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="action" value="rotar">
|
||||
<input type="hidden" name="semana" value="<?= $currentWeekStart ?>">
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
@@ -178,6 +185,7 @@ $pageTitle = 'Asignación de Turnos';
|
||||
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="asignar">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="semana" value="<?= $currentWeekStart ?>">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Asignar a:</label>
|
||||
@@ -260,6 +268,7 @@ $pageTitle = 'Asignación de Turnos';
|
||||
</div>
|
||||
|
||||
<form method="POST" class="d-flex gap-2">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="action" value="asignar">
|
||||
<input type="hidden" name="semana" value="<?= $semanaVer ?>">
|
||||
<select class="form-select" name="user_id" style="max-width: 250px;">
|
||||
@@ -302,6 +311,7 @@ No hay asignación para la semana <?= $posicionSinAsignar ?> de 4 (<?= date('d/m
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" id="asignacionMasivaForm">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="action" value="asignar_masivo">
|
||||
|
||||
<div class="row mb-3">
|
||||
@@ -401,6 +411,7 @@ No hay asignación para la semana <?= $posicionSinAsignar ?> de 4 (<?= date('d/m
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<form method="POST" class="h-100 d-flex flex-column justify-content-center">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="action" value="rotacion_automatica">
|
||||
<button type="submit" class="btn btn-warning w-100">
|
||||
<i class="fas fa-sync"></i> Generar Rotación Automática
|
||||
@@ -429,6 +440,7 @@ No hay asignación para la semana <?= $posicionSinAsignar ?> de 4 (<?= date('d/m
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" id="reordenarForm">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="action" value="reordenar">
|
||||
|
||||
<p class="text-muted">
|
||||
|
||||
@@ -5,6 +5,7 @@ if (!defined('BASE_PATH')) {
|
||||
require_once BASE_PATH . '/config/config.php';
|
||||
require_once BASE_PATH . '/src/Auth.php';
|
||||
require_once BASE_PATH . '/src/DiasHorarios.php';
|
||||
require_once BASE_PATH . '/src/CSRF.php';
|
||||
|
||||
$auth = new Auth();
|
||||
$auth->requireAdmin();
|
||||
@@ -24,18 +25,23 @@ $diasNombres = [
|
||||
];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$dia = $_POST['dia'] ?? '';
|
||||
$hora_apertura = $_POST["hora_apertura_$dia"] ?? '';
|
||||
$hora_cierre = $_POST["hora_cierre_$dia"] ?? '';
|
||||
$activo = isset($_POST["activo_$dia"]) ? 1 : 0;
|
||||
|
||||
if (empty($dia) || empty($hora_apertura) || empty($hora_cierre)) {
|
||||
$message = 'Todos los campos son obligatorios';
|
||||
if (!CSRF::isValidRequest()) {
|
||||
$message = 'Error de validación del formulario';
|
||||
$messageType = 'danger';
|
||||
} else {
|
||||
$horariosModel->update($dia, compact('hora_apertura', 'hora_cierre', 'activo'));
|
||||
$message = 'Horario actualizado correctamente';
|
||||
$messageType = 'success';
|
||||
$dia = $_POST['dia'] ?? '';
|
||||
$hora_apertura = $_POST["hora_apertura_$dia"] ?? '';
|
||||
$hora_cierre = $_POST["hora_cierre_$dia"] ?? '';
|
||||
$activo = isset($_POST["activo_$dia"]) ? 1 : 0;
|
||||
|
||||
if (empty($dia) || empty($hora_apertura) || empty($hora_cierre)) {
|
||||
$message = 'Todos los campos son obligatorios';
|
||||
$messageType = 'danger';
|
||||
} else {
|
||||
$horariosModel->update($dia, compact('hora_apertura', 'hora_cierre', 'activo'));
|
||||
$message = 'Horario actualizado correctamente';
|
||||
$messageType = 'success';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +70,7 @@ $pageTitle = 'Configuración de Horarios';
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form method="POST" id="horariosForm">
|
||||
<?= CSRF::getTokenField() ?>
|
||||
<input type="hidden" name="dia" id="selectedDia" value="">
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
@@ -5,6 +5,8 @@ if (!defined('BASE_PATH')) {
|
||||
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->requireAdmin();
|
||||
@@ -14,59 +16,64 @@ $message = '';
|
||||
$messageType = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
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 ($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';
|
||||
|
||||
if (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);
|
||||
if ($user) {
|
||||
if ($user['activo']) {
|
||||
$userModel->deactivate($id);
|
||||
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->activate($id);
|
||||
$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';
|
||||
|
||||
if (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);
|
||||
if ($user) {
|
||||
if ($user['activo']) {
|
||||
$userModel->deactivate($id);
|
||||
} else {
|
||||
$userModel->activate($id);
|
||||
}
|
||||
$message = 'Estado actualizado';
|
||||
$messageType = 'success';
|
||||
}
|
||||
$message = 'Estado actualizado';
|
||||
$messageType = 'success';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,15 +140,16 @@ $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['user_id']): ?>
|
||||
<form method="POST" class="d-inline">
|
||||
<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; ?>
|
||||
<?php if ($u['id'] != Session::get('user_id')): ?>
|
||||
<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; ?>
|
||||
@@ -160,6 +168,7 @@ $pageTitle = 'Gestión de Usuarios';
|
||||
<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">
|
||||
|
||||
Reference in New Issue
Block a user