| 96 | efrain | 1 | <?php
 | 
        
           | 1389 | ariadna | 2 |   | 
        
           | 1415 | ariadna | 3 | // NOTA IMPORTANTE:
 | 
        
           |  |  | 4 | // Las credenciales y claves RSA NO DEBEN ESTAR HARDCODEADAS EN UN ENTORNO DE PRODUCCIÓN.
 | 
        
           |  |  | 5 | // Considere usar variables de entorno, un archivo de configuración externo, o las propias configuraciones de Moodle
 | 
        
           |  |  | 6 | // para almacenar LLWS_USERNAME, LLWS_PASSWORD, LLWS_RSA_N, LLWS_RSA_D, LLWS_RSA_E.
 | 
        
           |  |  | 7 | // Por simplicidad en este ejemplo, se mantienen aquí para la demostración de los cambios.
 | 
        
           |  |  | 8 |   | 
        
           | 96 | efrain | 9 | define('LLWS_USERNAME', 'leaderdslinked-ws');
 | 
        
           |  |  | 10 | define('LLWS_PASSWORD', 'KFB3lFsLp&*CpB0uc2VNc!zVn@w!EZqZ*jr$J0AlE@sYREUcyP');
 | 
        
           | 1415 | ariadna | 11 | define('LLWS_RSA_N', 34589927);     // Clave pública RSA N
 | 
        
           |  |  | 12 | define('LLWS_RSA_D', 4042211);      // Clave privada RSA D
 | 
        
           |  |  | 13 | define('LLWS_RSA_E', 7331);         // Clave pública RSA E
 | 
        
           |  |  | 14 | define('LLWS_CATEGORY_ID', 6);      // ID de categoría para cursos
 | 
        
           | 96 | efrain | 15 |   | 
        
           | 1389 | ariadna | 16 | // Inclusión de archivos necesarios de Moodle
 | 
        
           | 96 | efrain | 17 | require_once(__DIR__ . '/../config.php');
 | 
        
           |  |  | 18 | global $DB, $CFG;
 | 
        
           |  |  | 19 |   | 
        
           | 1389 | ariadna | 20 | // Inclusión de librerías de Moodle
 | 
        
           | 1383 | ariadna | 21 | require_once($CFG->libdir . '/moodlelib.php');
 | 
        
           | 96 | efrain | 22 | require_once($CFG->libdir . '/externallib.php');
 | 
        
           | 1383 | ariadna | 23 | require_once($CFG->libdir . '/authlib.php');
 | 
        
           | 1415 | ariadna | 24 | require_once($CFG->libdir . '/gdlib.php'); // Para procesamiento de imágenes
 | 
        
           |  |  | 25 | require_once($CFG->dirroot . '/user/lib.php'); // Para funciones de usuario
 | 
        
           |  |  | 26 | require_once(__DIR__ . '/rsa.php'); // Asegúrate de que esta ruta sea correcta para tu clase RSA
 | 
        
           |  |  | 27 | require_once(__DIR__ . '/lib.php'); // Asegúrate de que esta ruta sea correcta para tus funciones ll_get_user_by_email, ll_get_username_available, ll_create_user
 | 
        
           | 96 | efrain | 28 |   | 
        
           | 1409 | ariadna | 29 | // Helper function to output JSON error and exit
 | 
        
           | 1415 | ariadna | 30 | // NOTA: Estos headers solo se configuran cuando hay un error para una respuesta JSON.
 | 
        
           |  |  | 31 | // Para un login exitoso, no se necesitan estos headers.
 | 
        
           | 1409 | ariadna | 32 | function output_json_error($errorCode)
 | 
        
           |  |  | 33 | {
 | 
        
           | 1415 | ariadna | 34 |     // Es buena práctica asegurar que la sesión se cierre antes de la salida,
 | 
        
           |  |  | 35 |     // aunque el manejo de salida de Moodle podría cubrir esto.
 | 
        
           | 1409 | ariadna | 36 |     if (function_exists('session_write_close')) {
 | 
        
           |  |  | 37 |         session_write_close();
 | 
        
           |  |  | 38 |     }
 | 
        
           |  |  | 39 |     header('Content-Type: application/json');
 | 
        
           | 1415 | ariadna | 40 |     // Para entornos de producción, considera restringir Access-Control-Allow-Origin
 | 
        
           |  |  | 41 |     // a dominios específicos si esta vista será accedida vía AJAX desde otros orígenes.
 | 
        
           |  |  | 42 |     // Si es una redirección directa, CORS es irrelevante para una respuesta JSON.
 | 
        
           |  |  | 43 |     header('Access-Control-Allow-Origin: *');
 | 
        
           | 1409 | ariadna | 44 |     echo json_encode(['success' => false, 'data' => $errorCode]);
 | 
        
           |  |  | 45 |     exit;
 | 
        
           |  |  | 46 | }
 | 
        
           |  |  | 47 |   | 
        
           | 1415 | ariadna | 48 | // Obtención y sanitización de parámetros de la petición
 | 
        
           |  |  | 49 | $username   = trim(isset($_REQUEST['username']) ? filter_var($_REQUEST['username'], FILTER_SANITIZE_STRING) : '');
 | 
        
           |  |  | 50 | $password   = trim(isset($_REQUEST['password']) ? filter_var($_REQUEST['password'], FILTER_SANITIZE_STRING) : '');
 | 
        
           |  |  | 51 | $timestamp  = trim(isset($_REQUEST['timestamp']) ? filter_var($_REQUEST['timestamp'], FILTER_SANITIZE_STRING) : '');
 | 
        
           |  |  | 52 | // Usamos FILTER_VALIDATE_INT para asegurar que sea un entero y no un string numérico grande.
 | 
        
           |  |  | 53 | $rand       = intval(isset($_REQUEST['rand']) ? filter_var($_REQUEST['rand'], FILTER_VALIDATE_INT) : 0, 10);
 | 
        
           |  |  | 54 | $data       = trim(isset($_REQUEST['data']) ? filter_var($_REQUEST['data'], FILTER_SANITIZE_STRING) : '');
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 | // --- Validaciones de Seguridad ---
 | 
        
           |  |  | 57 |   | 
        
           |  |  | 58 | // Validación de parámetros de seguridad mínimos
 | 
        
           | 1401 | ariadna | 59 | if (empty($username) || empty($password) || empty($timestamp) || empty($rand) || !is_integer($rand)) {
 | 
        
           | 1409 | ariadna | 60 |     output_json_error('ERROR_SECURITY1');
 | 
        
           | 96 | efrain | 61 | }
 | 
        
           |  |  | 62 |   | 
        
           | 1415 | ariadna | 63 | // Validación del nombre de usuario de la API
 | 
        
           |  |  | 64 | if ($username !== LLWS_USERNAME) { // Usamos !== para comparación estricta
 | 
        
           | 1409 | ariadna | 65 |     output_json_error('ERROR_SECURITY2');
 | 
        
           | 1401 | ariadna | 66 | }
 | 
        
           | 96 | efrain | 67 |   | 
        
           | 1401 | ariadna | 68 | // Validación del formato del timestamp
 | 
        
           |  |  | 69 | $dt = \DateTime::createFromFormat('Y-m-d\TH:i:s', $timestamp);
 | 
        
           |  |  | 70 | if (!$dt) {
 | 
        
           | 1409 | ariadna | 71 |     output_json_error('ERROR_SECURITY3');
 | 
        
           | 1401 | ariadna | 72 | }
 | 
        
           | 96 | efrain | 73 |   | 
        
           | 1415 | ariadna | 74 | // Validación del rango de tiempo del timestamp (±5 minutos) para prevenir Replay Attacks
 | 
        
           | 1401 | ariadna | 75 | $t0 = $dt->getTimestamp();
 | 
        
           |  |  | 76 | $t1 = strtotime('-5 minutes');
 | 
        
           |  |  | 77 | $t2 = strtotime('+5 minutes');
 | 
        
           | 96 | efrain | 78 |   | 
        
           | 1401 | ariadna | 79 | if ($t0 < $t1 || $t0 > $t2) {
 | 
        
           | 1415 | ariadna | 80 |     output_json_error('ERROR_SECURITY4'); // Habilitado para prevenir Replay Attacks
 | 
        
           | 1401 | ariadna | 81 | }
 | 
        
           | 96 | efrain | 82 |   | 
        
           | 1415 | ariadna | 83 | // Validación de la contraseña (hash de la contraseña de la API + rand + timestamp)
 | 
        
           |  |  | 84 | $expectedPasswordString = $username . '-' . LLWS_PASSWORD . '-' . $rand . '-' . $timestamp;
 | 
        
           |  |  | 85 | if (!password_verify($expectedPasswordString, $password)) {
 | 
        
           | 1409 | ariadna | 86 |     output_json_error('ERROR_SECURITY5');
 | 
        
           | 1401 | ariadna | 87 | }
 | 
        
           | 96 | efrain | 88 |   | 
        
           | 1415 | ariadna | 89 | // --- Validación y Desencriptación de Datos de Usuario ---
 | 
        
           |  |  | 90 |   | 
        
           | 1401 | ariadna | 91 | // Validación de datos
 | 
        
           |  |  | 92 | if (empty($data)) {
 | 
        
           | 1409 | ariadna | 93 |     output_json_error('ERROR_PARAMETERS1');
 | 
        
           | 1401 | ariadna | 94 | }
 | 
        
           | 96 | efrain | 95 |   | 
        
           | 1401 | ariadna | 96 | // Decodificación de datos en base64
 | 
        
           |  |  | 97 | $data = base64_decode($data);
 | 
        
           | 1415 | ariadna | 98 | if ($data === false || empty($data)) { // base64_decode puede retornar false
 | 
        
           | 1409 | ariadna | 99 |     output_json_error('ERROR_PARAMETERS2');
 | 
        
           | 96 | efrain | 100 | }
 | 
        
           |  |  | 101 |   | 
        
           | 1401 | ariadna | 102 | // Desencriptación de datos usando RSA
 | 
        
           |  |  | 103 | try {
 | 
        
           | 1415 | ariadna | 104 |     $rsa = new rsa(); // Asegúrate de que la clase 'rsa' esté correctamente cargada.
 | 
        
           | 1401 | ariadna | 105 |     $rsa->setKeys(LLWS_RSA_N, LLWS_RSA_D, LLWS_RSA_E);
 | 
        
           |  |  | 106 |     $data = $rsa->decrypt($data);
 | 
        
           |  |  | 107 | } catch (Throwable $e) {
 | 
        
           | 1415 | ariadna | 108 |     // Registra el error para depuración, pero no lo expongas al cliente.
 | 
        
           |  |  | 109 |     error_log("RSA Decryption Error: " . $e->getMessage());
 | 
        
           | 1409 | ariadna | 110 |     output_json_error('ERROR_PARAMETERS3');
 | 
        
           | 1401 | ariadna | 111 | }
 | 
        
           | 1383 | ariadna | 112 |   | 
        
           | 1401 | ariadna | 113 | // Conversión de datos a array
 | 
        
           | 1415 | ariadna | 114 | $data = (array) json_decode($data, true); // Añadido 'true' para asegurar un array asociativo
 | 
        
           | 1401 | ariadna | 115 | if (empty($data)) {
 | 
        
           | 1409 | ariadna | 116 |     output_json_error('ERROR_PARAMETERS4');
 | 
        
           | 1401 | ariadna | 117 | }
 | 
        
           | 96 | efrain | 118 |   | 
        
           | 1401 | ariadna | 119 | // Extracción y validación de datos del usuario
 | 
        
           |  |  | 120 | $email      = trim(isset($data['email']) ? filter_var($data['email'], FILTER_SANITIZE_EMAIL) : '');
 | 
        
           | 1415 | ariadna | 121 | $first_name = trim(isset($data['first_name']) ? filter_var($data['first_name'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) : '');
 | 
        
           |  |  | 122 | $last_name  = trim(isset($data['last_name']) ? filter_var($data['last_name'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) : '');
 | 
        
           | 96 | efrain | 123 |   | 
        
           | 1415 | ariadna | 124 | // Asegúrate de que los datos esenciales del usuario estén presentes y sean válidos.
 | 
        
           | 1401 | ariadna | 125 | if (!filter_var($email, FILTER_VALIDATE_EMAIL) || empty($first_name) || empty($last_name)) {
 | 
        
           | 1409 | ariadna | 126 |     output_json_error('ERROR_PARAMETERS5');
 | 
        
           | 1401 | ariadna | 127 | }
 | 
        
           | 96 | efrain | 128 |   | 
        
           | 1415 | ariadna | 129 | // --- Búsqueda o Creación de Usuario en Moodle ---
 | 
        
           |  |  | 130 |   | 
        
           |  |  | 131 | $user = ll_get_user_by_email($email); // Asume que esta función busca al usuario por email
 | 
        
           |  |  | 132 | $new_user = false;
 | 
        
           |  |  | 133 |   | 
        
           | 1401 | ariadna | 134 | if ($user) {
 | 
        
           | 1415 | ariadna | 135 |     // Usuario encontrado
 | 
        
           | 1401 | ariadna | 136 | } else {
 | 
        
           | 1415 | ariadna | 137 |     // Usuario no encontrado, proceder a la creación
 | 
        
           | 1401 | ariadna | 138 |     $new_user = true;
 | 
        
           | 1415 | ariadna | 139 |     $username_moodle = ll_get_username_available($first_name, $last_name); // Genera un nombre de usuario disponible para Moodle
 | 
        
           |  |  | 140 |     $user = ll_create_user($username_moodle, $email, $first_name, $last_name); // Crea el usuario
 | 
        
           | 1401 | ariadna | 141 |   | 
        
           | 1415 | ariadna | 142 |     // Procesamiento de imagen de perfil si se proporciona y el usuario fue creado
 | 
        
           | 1401 | ariadna | 143 |     if ($user) {
 | 
        
           | 1415 | ariadna | 144 |         $filename   = trim(isset($data['image_filename']) ? filter_var($data['image_filename'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) : '');
 | 
        
           | 1401 | ariadna | 145 |         $content    = trim(isset($data['image_content']) ? filter_var($data['image_content'], FILTER_SANITIZE_STRING) : '');
 | 
        
           |  |  | 146 |   | 
        
           | 1415 | ariadna | 147 |         // Validación básica de nombre de archivo para evitar path traversal
 | 
        
           |  |  | 148 |         if ($filename && strpos($filename, '..') === false && strpos($filename, DIRECTORY_SEPARATOR) === false) {
 | 
        
           |  |  | 149 |             $tempfile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $filename; // Usar directorio temporal del sistema
 | 
        
           | 1401 | ariadna | 150 |             try {
 | 
        
           | 1415 | ariadna | 151 |                 $decoded_content = base64_decode($content);
 | 
        
           |  |  | 152 |                 if ($decoded_content !== false && !empty($decoded_content)) {
 | 
        
           |  |  | 153 |                     file_put_contents($tempfile, $decoded_content);
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |                     if (file_exists($tempfile)) {
 | 
        
           |  |  | 156 |                         $usericonid = process_new_icon(context_user::instance($user->id, MUST_EXIST), 'user', 'icon', 0, $tempfile);
 | 
        
           |  |  | 157 |                         if ($usericonid) {
 | 
        
           |  |  | 158 |                             $DB->set_field('user', 'picture', $usericonid, array('id' => $user->id));
 | 
        
           |  |  | 159 |                         }
 | 
        
           | 1401 | ariadna | 160 |                     }
 | 
        
           | 96 | efrain | 161 |                 }
 | 
        
           | 1401 | ariadna | 162 |             } catch (\Throwable $e) {
 | 
        
           | 1415 | ariadna | 163 |                 // IMPORTANT: Registra el error de la imagen, pero no abortes el login del usuario si la imagen falla.
 | 
        
           |  |  | 164 |                 error_log("Error processing user image for user ID {$user->id}: " . $e->getMessage());
 | 
        
           | 1401 | ariadna | 165 |             } finally {
 | 
        
           | 1415 | ariadna | 166 |                 // Asegúrate de eliminar el archivo temporal
 | 
        
           | 1401 | ariadna | 167 |                 if (file_exists($tempfile)) {
 | 
        
           |  |  | 168 |                     unlink($tempfile);
 | 
        
           |  |  | 169 |                 }
 | 
        
           | 96 | efrain | 170 |             }
 | 
        
           |  |  | 171 |         }
 | 
        
           |  |  | 172 |     }
 | 
        
           | 1401 | ariadna | 173 | }
 | 
        
           | 96 | efrain | 174 |   | 
        
           | 1415 | ariadna | 175 | // Verificación de creación/recuperación de usuario
 | 
        
           | 1401 | ariadna | 176 | if (!$user) {
 | 
        
           | 1409 | ariadna | 177 |     output_json_error('ERROR_MOODLE1');
 | 
        
           | 1383 | ariadna | 178 | }
 | 
        
           | 96 | efrain | 179 |   | 
        
           | 1415 | ariadna | 180 | // --- Inscripción en Cursos para Usuarios Nuevos ---
 | 
        
           |  |  | 181 |   | 
        
           | 1401 | ariadna | 182 | if ($new_user) {
 | 
        
           | 96 | efrain | 183 |     $role = $DB->get_record('role', array('archetype' => 'student'));
 | 
        
           |  |  | 184 |     $enrolmethod = 'manual';
 | 
        
           | 1383 | ariadna | 185 |   | 
        
           | 1415 | ariadna | 186 |     $courses = get_courses(); // Obtiene todos los cursos
 | 
        
           | 1383 | ariadna | 187 |     foreach ($courses as $course) {
 | 
        
           | 1415 | ariadna | 188 |         // CORRECCIÓN: Error tipográfico 'categoy_id' a 'category_id'
 | 
        
           |  |  | 189 |         if ($course->category_id == LLWS_CATEGORY_ID) {
 | 
        
           | 96 | efrain | 190 |             $context = context_course::instance($course->id);
 | 
        
           | 1415 | ariadna | 191 |             if (!is_enrolled($context, $user)) { // Verifica si el usuario ya está inscrito
 | 
        
           | 96 | efrain | 192 |                 $enrol = enrol_get_plugin($enrolmethod);
 | 
        
           |  |  | 193 |                 if ($enrol === null) {
 | 
        
           | 1415 | ariadna | 194 |                     // Si el método de matriculación manual no existe, loguea un error y continúa.
 | 
        
           |  |  | 195 |                     // No debería abortar el login del usuario por esto.
 | 
        
           |  |  | 196 |                     error_log("Enrolment method '{$enrolmethod}' not found for course ID {$course->id}.");
 | 
        
           |  |  | 197 |                     continue; // Pasa al siguiente curso
 | 
        
           | 96 | efrain | 198 |                 }
 | 
        
           | 1415 | ariadna | 199 |   | 
        
           |  |  | 200 |                 // Obtener o crear una instancia de matriculación manual para el curso
 | 
        
           |  |  | 201 |                 $instance = $enrol->add_default_instance($course); // Esto intenta encontrar o crear una instancia por defecto
 | 
        
           |  |  | 202 |                 if ($instance === null) {
 | 
        
           |  |  | 203 |                     // Si add_default_instance falla (ej. no hay permisos), intenta crear una nueva instancia.
 | 
        
           |  |  | 204 |                     // Esto es menos común si add_default_instance no funciona, pero es una alternativa.
 | 
        
           |  |  | 205 |                     $instanceid = $enrol->add_instance($course);
 | 
        
           | 96 | efrain | 206 |                     $instance = $DB->get_record('enrol', array('id' => $instanceid));
 | 
        
           |  |  | 207 |                 }
 | 
        
           | 1415 | ariadna | 208 |   | 
        
           |  |  | 209 |                 if ($instance) {
 | 
        
           |  |  | 210 |                     $enrol->enrol_user($instance, $user->id, $role->id);
 | 
        
           |  |  | 211 |                 } else {
 | 
        
           |  |  | 212 |                     error_log("Failed to get or create manual enrolment instance for course ID {$course->id}.");
 | 
        
           |  |  | 213 |                 }
 | 
        
           | 96 | efrain | 214 |             }
 | 
        
           |  |  | 215 |         }
 | 
        
           |  |  | 216 |     }
 | 
        
           |  |  | 217 | }
 | 
        
           |  |  | 218 |   | 
        
           | 1415 | ariadna | 219 | // --- Completar el Proceso de Inicio de Sesión ---
 | 
        
           |  |  | 220 |   | 
        
           |  |  | 221 | // Obtener datos completos del usuario (asegura que todos los campos de Moodle estén cargados)
 | 
        
           | 1401 | ariadna | 222 | $user = get_complete_user_data('id', $user->id);
 | 
        
           | 1415 | ariadna | 223 |   | 
        
           | 1401 | ariadna | 224 | if ($user) {
 | 
        
           |  |  | 225 |     // Verificar si la cuenta está confirmada
 | 
        
           | 1392 | ariadna | 226 |     if (empty($user->confirmed)) {
 | 
        
           | 1409 | ariadna | 227 |         output_json_error('ACCOUNT_NOT_CONFIRMED');
 | 
        
           | 1392 | ariadna | 228 |     }
 | 
        
           |  |  | 229 |   | 
        
           | 1401 | ariadna | 230 |     // Verificar si la contraseña ha expirado (solo para autenticación LDAP)
 | 
        
           | 1392 | ariadna | 231 |     $userauth = get_auth_plugin($user->auth);
 | 
        
           |  |  | 232 |     if (!isguestuser() && !empty($userauth->config->expiration) && $userauth->config->expiration == 1) {
 | 
        
           |  |  | 233 |         $days2expire = $userauth->password_expire($user->username);
 | 
        
           |  |  | 234 |         if (intval($days2expire) < 0) {
 | 
        
           | 1409 | ariadna | 235 |             output_json_error('PASSWORD_EXPIRED');
 | 
        
           | 1391 | ariadna | 236 |         }
 | 
        
           | 1392 | ariadna | 237 |     }
 | 
        
           | 1391 | ariadna | 238 |   | 
        
           | 1415 | ariadna | 239 |     // CORRECCIÓN: Para un flujo de login web, Moodle maneja la sesión existente.
 | 
        
           |  |  | 240 |     // complete_user_login() es suficiente para establecer la sesión del usuario.
 | 
        
           |  |  | 241 |     // Eliminar el cierre agresivo de todas las sesiones a menos que sea un requisito muy específico.
 | 
        
           |  |  | 242 |     // Si la sesión actual ya está autenticada, complete_user_login() la actualizará.
 | 
        
           |  |  | 243 |     // Si necesitas forzar un re-login de la sesión actual, puedes hacerlo de forma más granular:
 | 
        
           |  |  | 244 |     /*
 | 
        
           |  |  | 245 |     if (isloggedin() && get_userid() !== $user->id) { // Si un usuario diferente ya está logueado en esta sesión
 | 
        
           | 1414 | ariadna | 246 |         \core\session\manager::terminate_current();
 | 
        
           |  |  | 247 |         session_destroy();
 | 
        
           | 1415 | ariadna | 248 |         setcookie('MoodleSession', '', time() - 3600, '/'); // Eliminar la cookie de la sesión anterior
 | 
        
           | 1414 | ariadna | 249 |     }
 | 
        
           | 1415 | ariadna | 250 |     */
 | 
        
           | 1414 | ariadna | 251 |   | 
        
           | 1415 | ariadna | 252 |     // Completar el proceso de inicio de sesión de Moodle.
 | 
        
           |  |  | 253 |     // Esto establecerá la sesión del usuario $user.
 | 
        
           | 1413 | ariadna | 254 |     complete_user_login($user);
 | 
        
           | 1401 | ariadna | 255 |   | 
        
           | 1415 | ariadna | 256 |     // Aplicar límite de inicio de sesión concurrente (descomentado si es necesario)
 | 
        
           |  |  | 257 |     // \core\session\manager::apply_concurrent_login_limit($user->id, session_id());
 | 
        
           | 1391 | ariadna | 258 |   | 
        
           | 1415 | ariadna | 259 |     // Configurar cookie de nombre de usuario (Moodle lo maneja internamente)
 | 
        
           | 1392 | ariadna | 260 |     if (!empty($CFG->nolastloggedin)) {
 | 
        
           |  |  | 261 |         // No almacenar último usuario conectado en cookie
 | 
        
           |  |  | 262 |     } else if (empty($CFG->rememberusername)) {
 | 
        
           | 1401 | ariadna | 263 |         // Sin cookies permanentes, eliminar la anterior si existe
 | 
        
           | 1392 | ariadna | 264 |         set_moodle_cookie('');
 | 
        
           |  |  | 265 |     } else {
 | 
        
           |  |  | 266 |         set_moodle_cookie($user->username);
 | 
        
           |  |  | 267 |     }
 | 
        
           | 1391 | ariadna | 268 |   | 
        
           | 1415 | ariadna | 269 |     // Limpiar mensajes de error y redirección de sesión antes de la redirección final
 | 
        
           | 1392 | ariadna | 270 |     unset($SESSION->loginerrormsg);
 | 
        
           |  |  | 271 |     unset($SESSION->logininfomsg);
 | 
        
           | 1415 | ariadna | 272 |     unset($SESSION->loginredirect); // Descartar loginredirect si estamos redirigiendo
 | 
        
           | 1401 | ariadna | 273 |   | 
        
           |  |  | 274 |     // Configurar la URL de destino
 | 
        
           | 1415 | ariadna | 275 |     $urltogo = $CFG->wwwroot . '/my'; // Página "Mi Moodle"
 | 
        
           | 1391 | ariadna | 276 |   | 
        
           | 1415 | ariadna | 277 |     // Verificar que la sesión se haya iniciado correctamente antes de redirigir
 | 
        
           | 1398 | ariadna | 278 |     if (isloggedin() && !isguestuser()) {
 | 
        
           | 1415 | ariadna | 279 |         // Redirección HTTP para una vista web exitosa
 | 
        
           | 1401 | ariadna | 280 |         redirect($urltogo);
 | 
        
           |  |  | 281 |     } else {
 | 
        
           | 1415 | ariadna | 282 |         // Falló la autenticación final en Moodle, a pesar de las validaciones previas.
 | 
        
           |  |  | 283 |         output_json_error('LOGIN_FAILED_MOODLE');
 | 
        
           | 1399 | ariadna | 284 |     }
 | 
        
           | 1401 | ariadna | 285 | } else {
 | 
        
           | 1415 | ariadna | 286 |     // Esto debería ser capturado por output_json_error('ERROR_MOODLE1') anteriormente,
 | 
        
           |  |  | 287 |     // pero es un fallback.
 | 
        
           | 1409 | ariadna | 288 |     output_json_error('USER_NOT_FOUND');
 | 
        
           | 96 | efrain | 289 | }
 | 
        
           | 1415 | ariadna | 290 |   | 
        
           |  |  | 291 | // El script debería terminar con una redirección o una respuesta JSON de error.
 | 
        
           |  |  | 292 | // El 'exit;' final es redundante si se usa redirect() o output_json_error() que ya contienen exit().
 | 
        
           |  |  | 293 | exit;
 |