From 7e85c2a1f2818807ebdba7cac6564d2de0f89e60 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 20:40:10 +0000 Subject: [PATCH 1/7] Initial plan From c0a93ce1095db94744463902eb31d2d362d476fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 20:50:53 +0000 Subject: [PATCH 2/7] Redesign UI to match Google Workspace integrated feel Co-authored-by: naielv <109038805+naielv@users.noreply.github.com> --- public_html/_incl/pre-body.php | 711 +++++++++++++++------------------ public_html/index.php | 265 ++++++------ 2 files changed, 439 insertions(+), 537 deletions(-) diff --git a/public_html/_incl/pre-body.php b/public_html/_incl/pre-body.php index d7b6592..9a39d47 100755 --- a/public_html/_incl/pre-body.php +++ b/public_html/_incl/pre-body.php @@ -38,412 +38,361 @@ if (!empty($displayName)) { " /> + + + @@ -548,17 +464,95 @@ if (!empty($displayName)) { }); })(); + + +
+ + + + + + +
+
+ + + + +
+ +
+
+ +
+ +
+
+ Organización activa +
+
+ +
+ 1): ?> +
Cambiar organización:
+ +
+ + +
+ + +
+
Gestionar cuenta diff --git a/public_html/_incl/switch_tenant.php b/public_html/_incl/switch_tenant.php new file mode 100644 index 0000000..65e6891 --- /dev/null +++ b/public_html/_incl/switch_tenant.php @@ -0,0 +1,28 @@ + 300) { - $username = $_SESSION["auth_user"]; - $user_filename = safe_username_to_filename($username); - if ($user_filename !== "") { - $userdata = json_decode(file_get_contents("/DATA/Usuarios/" . $user_filename . ".json"), true); - $_SESSION["auth_data"] = $userdata; - } - $_SESSION["last_reload_time"] = time(); + } elseif ($load_mode !== "never") { + $last = $_SESSION["last_reload_time"] ?? 0; + if (time() - $last > 300) { + $row = db_get_user($_SESSION["auth_user"]); + if ($row) { + $_SESSION["auth_data"] = db_build_auth_data($row); + init_active_centro($_SESSION["auth_data"]); } - } else { + $_SESSION["last_reload_time"] = time(); + } + if (!isset($_SESSION["last_reload_time"])) { $_SESSION["last_reload_time"] = time(); } } } - -function user_is_authenticated() +function user_is_authenticated(): bool { return isset($_SESSION["auth_ok"]) && $_SESSION["auth_ok"] === true; } -function user_has_permission($perm) -{ - return in_array($perm, $_SESSION["auth_data"]["permissions"] ?? []); -} -/** - * Returns all centro/tenant IDs the authenticated user belongs to. - * Supports both the legacy single-centro format (entreaulas.centro = "string") - * and the new multi-tenant format (entreaulas.centros = ["a", "b"]). - */ -function get_user_centros($auth_data = null) +function user_has_permission(string $perm): bool { - $data = $auth_data ?? $_SESSION["auth_data"] ?? []; - $ea = $data["entreaulas"] ?? []; - - if (!empty($ea["centros"]) && is_array($ea["centros"])) { - return array_values($ea["centros"]); - } - if (!empty($ea["centro"])) { - return [$ea["centro"]]; - } - return []; -} - -/** - * Ensures $_SESSION['active_centro'] is set to a valid centro for the user. - * Call after user data is loaded/reloaded. - */ -function init_active_centro($auth_data = null) -{ - $centros = get_user_centros($auth_data); - if (empty($centros)) { - $_SESSION['active_centro'] = null; - return; - } - // Keep existing selection only if it is still valid - if (!empty($_SESSION['active_centro']) && in_array($_SESSION['active_centro'], $centros, true)) { - return; - } - $_SESSION['active_centro'] = $centros[0]; + return in_array($perm, $_SESSION["auth_data"]["permissions"] ?? [], true); } diff --git a/public_html/_install.php b/public_html/_install.php index 764e6ca..c9eb756 100644 --- a/public_html/_install.php +++ b/public_html/_install.php @@ -1,28 +1,25 @@ 'Administrador', - 'email' => "$admin_user@nomail.arpa", - 'permissions' => ['*', 'sysadmin:access', 'entreaulas:access'], - 'password_hash' => $password_hash - ]; - if (!is_dir("/DATA/Usuarios")) { - mkdir("/DATA/Usuarios", 0777, true); - } - file_put_contents("/DATA/Usuarios/$admin_user.json", json_encode($admin_userdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - file_put_contents("/DATA/SISTEMA_INSTALADO.txt", "Sistema instalado el ".date("Y-m-d H:i:s")."\n"); + db_upsert_user([ + 'username' => $admin_user, + 'display_name' => 'Administrador', + 'email' => "$admin_user@nomail.arpa", + 'permissions' => ['*', 'sysadmin:access', 'entreaulas:access'], + 'password_hash' => password_hash($admin_password, PASSWORD_DEFAULT), + ]); + db_set_config('installed', '1'); header("Location: /_login.php"); exit; break; diff --git a/public_html/_login.php b/public_html/_login.php index 324ac4e..98d36e3 100755 --- a/public_html/_login.php +++ b/public_html/_login.php @@ -1,8 +1,9 @@ $name, - "email" => $email, - "permissions" => ["public"], - "password_hash" => password_hash($password, PASSWORD_DEFAULT), - "google_auth" => true, - "#" => "Este usuario fue creado automáticamente al iniciar sesión con Google por primera vez.", - ]; - file_put_contents($userfile, json_encode($userdata)); + db_upsert_user([ + 'username' => $username, + 'display_name' => $name, + 'email' => $email, + 'permissions' => ['public'], + 'password_hash' => password_hash($password, PASSWORD_DEFAULT), + 'google_auth' => true, + '#' => 'Este usuario fue creado automáticamente al iniciar sesión con Google por primera vez.', + ]); + $user_row = db_get_user($username); } - + session_regenerate_id(true); - $_SESSION['auth_user'] = $email; - $_SESSION['auth_data'] = $userdata; - $_SESSION['auth_ok'] = true; + $_SESSION['auth_user'] = $username; + $_SESSION['auth_data'] = db_build_auth_data($user_row); + $_SESSION['auth_ok'] = true; + init_active_centro($_SESSION['auth_data']); $cookie_options = ["expires" => time() + (86400 * 30), "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"]; - setcookie("auth_user", $email, $cookie_options); - setcookie("auth_pass_b64", base64_encode($password), $cookie_options); + setcookie("auth_user", $username, $cookie_options); + setcookie("auth_pass_b64", base64_encode($password), $cookie_options); $redir = safe_redir($state["redir"] ?? "/"); @@ -161,20 +164,19 @@ if ($_GET["clear_session"] == "1") { die(); } if (isset($_POST["user"])) { - $valid = ""; - $user = trim(strtolower($_POST["user"])); + $user = trim(strtolower($_POST["user"])); $password = $_POST["password"]; - $user_filename = safe_username_to_filename($user); - $userdata = ($user_filename !== "") ? json_decode(@file_get_contents("/DATA/Usuarios/" . $user_filename . ".json"), true) : null; - if (!is_array($userdata) || !isset($userdata["password_hash"])) { + $row = db_get_user($user); + if (!$row || !isset($row["password_hash"])) { $_GET["_result"] = "El usuario no existe."; - } elseif (password_verify($password, $userdata["password_hash"])) { + } elseif (password_verify($password, $row["password_hash"])) { session_regenerate_id(true); $_SESSION['auth_user'] = $user; - $_SESSION['auth_data'] = $userdata; - $_SESSION['auth_ok'] = true; + $_SESSION['auth_data'] = db_build_auth_data($row); + $_SESSION['auth_ok'] = true; + init_active_centro($_SESSION['auth_data']); $cookie_options = ["expires" => time() + (86400 * 30), "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"]; - setcookie("auth_user", $user, $cookie_options); + setcookie("auth_user", $user, $cookie_options); setcookie("auth_pass_b64", base64_encode($password), $cookie_options); $redir = safe_redir($_GET["redir"] ?? "/"); header("Location: $redir"); @@ -182,9 +184,8 @@ if (isset($_POST["user"])) { } else { $_GET["_result"] = "La contraseña no es correcta."; } - } -if (!file_exists("/DATA/SISTEMA_INSTALADO.txt")) { +if (db_get_config('installed') !== '1') { header("Location: /_install.php"); die(); } diff --git a/public_html/account/index.php b/public_html/account/index.php index 0ea6b70..aa9838b 100644 --- a/public_html/account/index.php +++ b/public_html/account/index.php @@ -1,44 +1,131 @@ -
-
-

¡Hola, !

- Tu Email: - Tu Nombre de Usuario: -
-
- Código QR - " alt="QR Code de Nombre de Usuario" style="margin: 0 auto;"> - Escanea este código para iniciar sesión. Es como tu contraseña, pero más fácil. -
-
- - - \ No newline at end of file + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/public_html/account/register.php b/public_html/account/register.php index 7dbc0f5..1752e34 100644 --- a/public_html/account/register.php +++ b/public_html/account/register.php @@ -1,36 +1,27 @@ $_POST['display_name'], - 'email' => $_POST['email'], - 'password_hash' => password_hash($_POST['password'], PASSWORD_DEFAULT), - '_meta_signup' => [ - 'invitation_code' => $invi_code - ], - 'permissions' => [] - ]; - if ($invitations[$invi_code]["active"] != true) { - header("Location: /?_resultcolor=red&_result=" . urlencode("Código de invitación no válido.")); - exit; - } - $username = $_POST['username']; - if (file_exists("/DATA/Usuarios/$username.json")) { + $username = strtolower(trim($_POST['username'] ?? '')); + if (db_get_user($username)) { header("Location: /?_resultcolor=red&_result=" . urlencode("El nombre de usuario ya existe. Por favor, elige otro.")); exit; } - file_put_contents("/DATA/Usuarios/$username.json", json_encode($userdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - // Deactivate invitation code if it's single-use - if ($invitations[$invi_code]["single_use"] === true) { - $invitations[$invi_code]["active"] = false; - file_put_contents("/DATA/Invitaciones_de_usuarios.json", json_encode($invitations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + db_upsert_user([ + 'username' => $username, + 'display_name' => $_POST['display_name'] ?? '', + 'email' => $_POST['email'] ?? '', + 'password_hash' => password_hash($_POST['password'], PASSWORD_DEFAULT), + 'permissions' => [], + '_meta_signup' => ['invitation_code' => $invi_code], + ]); + if ($invitation['single_use']) { + db_deactivate_invitation($invi_code); } header("Location: /?_result=" . urlencode("Cuenta creada correctamente. Ya puedes iniciar sesión.")); exit; diff --git a/public_html/aulatek/api/comedor.php b/public_html/aulatek/api/comedor.php index 320ca98..36aa8d9 100644 --- a/public_html/aulatek/api/comedor.php +++ b/public_html/aulatek/api/comedor.php @@ -2,24 +2,7 @@ header("Content-Type: application/json; charset=utf-8"); require_once "_incl/auth_redir.php"; require_once "../_incl/tools.security.php"; - -function menu_types_path($centro_id, $aulario_id) { - $centro = safe_centro_id($centro_id); - $aulario = safe_id_segment($aulario_id); - if ($centro === '' || $aulario === '') { - return null; - } - return "/DATA/entreaulas/Centros/$centro/Aularios/$aulario/Comedor-MenuTypes.json"; -} - -function comedor_day_base_dir($centro_id, $aulario_id, $ym, $day) { - $centro = safe_centro_id($centro_id); - $aulario = safe_id_segment($aulario_id); - if ($centro === '' || $aulario === '') { - return null; - } - return "/DATA/entreaulas/Centros/$centro/Aularios/$aulario/Comedor/$ym/$day"; -} +require_once "../../_incl/db.php"; // Check permissions if (!in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? [])) { @@ -33,64 +16,48 @@ if ($centro_id === "") { die(json_encode(["error" => "Centro not found in session", "code" => "INVALID_SESSION"])); } -$action = $_GET["action"] ?? ($_POST["action"] ?? ""); +$action = $_GET["action"] ?? ($_POST["action"] ?? ""); $aulario_id = safe_id_segment($_GET["aulario"] ?? $_POST["aulario"] ?? ""); -// Validate aulario_id if ($aulario_id === "") { http_response_code(400); die(json_encode(["error" => "aulario parameter is required", "code" => "MISSING_PARAM"])); } -// Verify that the user has access to this aulario -$userAulas = $_SESSION["auth_data"]["entreaulas"]["aulas"] ?? []; -$userAulas = array_values(array_filter(array_map('safe_id_segment', $userAulas))); +$userAulas = array_values(array_filter(array_map('safe_id_segment', $_SESSION["auth_data"]["entreaulas"]["aulas"] ?? []))); if (!in_array($aulario_id, $userAulas, true)) { http_response_code(403); die(json_encode(["error" => "Access denied to this aulario", "code" => "FORBIDDEN"])); } -$aulario_path = safe_aulario_config_path($centro_id, $aulario_id); -$aulario = ($aulario_path && file_exists($aulario_path)) ? json_decode(file_get_contents($aulario_path), true) : null; +$aulario = db_get_aulario($centro_id, $aulario_id); -// Handle shared comedor data $source_aulario_id = $aulario_id; $is_shared = false; if ($aulario && !empty($aulario["shared_comedor_from"])) { $shared_from = safe_id_segment($aulario["shared_comedor_from"]); - $shared_aulario_path = safe_aulario_config_path($centro_id, $shared_from); - if ($shared_aulario_path && file_exists($shared_aulario_path)) { + if (db_get_aulario($centro_id, $shared_from)) { $source_aulario_id = $shared_from; $is_shared = true; } } -// Check edit permissions (must be sysadmin and not shared) $canEdit = in_array("sysadmin:access", $_SESSION["auth_data"]["permissions"] ?? []) && !$is_shared; -// Helper functions -function get_menu_types($centro_id, $source_aulario_id) { - $menuTypesPath = menu_types_path($centro_id, $source_aulario_id); - $defaultMenuTypes = [ - ["id" => "basal", "label" => "Menú basal", "color" => "#0d6efd"], - ["id" => "vegetariano", "label" => "Menú vegetariano", "color" => "#198754"], - ["id" => "alergias", "label" => "Menú alergias", "color" => "#dc3545"], - ]; +$defaultMenuTypes = [ + ["id" => "basal", "label" => "Menú basal", "color" => "#0d6efd"], + ["id" => "vegetariano", "label" => "Menú vegetariano", "color" => "#198754"], + ["id" => "alergias", "label" => "Menú alergias", "color" => "#dc3545"], +]; - if ($menuTypesPath === null) { +function get_menu_types($centro_id, $source_aulario_id) { + global $defaultMenuTypes; + $types = db_get_comedor_menu_types($centro_id, $source_aulario_id); + if (empty($types)) { + db_set_comedor_menu_types($centro_id, $source_aulario_id, $defaultMenuTypes); return $defaultMenuTypes; } - - if (!file_exists($menuTypesPath)) { - if (!is_dir(dirname($menuTypesPath))) { - mkdir(dirname($menuTypesPath), 0777, true); - } - file_put_contents($menuTypesPath, json_encode($defaultMenuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - return $defaultMenuTypes; - } - - $menuTypes = json_decode(@file_get_contents($menuTypesPath), true); - return (is_array($menuTypes) && count($menuTypes) > 0) ? $menuTypes : $defaultMenuTypes; + return $types; } function blank_menu() { @@ -98,7 +65,7 @@ function blank_menu() { "plates" => [ "primero" => ["name" => "", "pictogram" => ""], "segundo" => ["name" => "", "pictogram" => ""], - "postre" => ["name" => "", "pictogram" => ""], + "postre" => ["name" => "", "pictogram" => ""], ] ]; } @@ -113,43 +80,25 @@ switch ($action) { case "get_menu_types": handle_get_menu_types(); break; - case "get_menu": handle_get_menu(); break; - case "save_menu": - if (!$canEdit) { - http_response_code(403); - die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); - } + if (!$canEdit) { http_response_code(403); die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); } handle_save_menu(); break; - case "add_menu_type": - if (!$canEdit) { - http_response_code(403); - die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); - } + if (!$canEdit) { http_response_code(403); die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); } handle_add_menu_type(); break; - case "delete_menu_type": - if (!$canEdit) { - http_response_code(403); - die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); - } + if (!$canEdit) { http_response_code(403); die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); } handle_delete_menu_type(); break; - case "rename_menu_type": - if (!$canEdit) { - http_response_code(403); - die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); - } + if (!$canEdit) { http_response_code(403); die(json_encode(["error" => "Insufficient permissions to edit", "code" => "FORBIDDEN"])); } handle_rename_menu_type(); break; - default: http_response_code(400); die(json_encode(["error" => "Invalid action", "code" => "INVALID_ACTION"])); @@ -157,298 +106,102 @@ switch ($action) { function handle_get_menu_types() { global $centro_id, $source_aulario_id; - - $menuTypes = get_menu_types($centro_id, $source_aulario_id); - echo json_encode([ - "success" => true, - "menu_types" => $menuTypes - ]); + echo json_encode(["success" => true, "menu_types" => get_menu_types($centro_id, $source_aulario_id)]); } function handle_get_menu() { global $centro_id, $source_aulario_id; - $date = $_GET["date"] ?? date("Y-m-d"); $menuTypeId = safe_id_segment($_GET["menu"] ?? ""); - - // Validate date $dateObj = DateTime::createFromFormat("Y-m-d", $date); - if (!$dateObj) { - http_response_code(400); - die(json_encode(["error" => "Invalid date format", "code" => "INVALID_FORMAT"])); - } + if (!$dateObj) { http_response_code(400); die(json_encode(["error" => "Invalid date format", "code" => "INVALID_FORMAT"])); } $date = $dateObj->format("Y-m-d"); - - // Get menu types - $menuTypes = get_menu_types($centro_id, $source_aulario_id); - $menuTypeIds = []; - foreach ($menuTypes as $t) { - if (!empty($t["id"])) { - $menuTypeIds[] = $t["id"]; - } - } - - if ($menuTypeId === "" || !in_array($menuTypeId, $menuTypeIds)) { - $menuTypeId = $menuTypeIds[0] ?? "basal"; - } - - // Get menu data - $ym = $dateObj->format("Y-m"); + $menuTypes = get_menu_types($centro_id, $source_aulario_id); + $menuTypeIds = array_column($menuTypes, "id"); + if ($menuTypeId === "" || !in_array($menuTypeId, $menuTypeIds)) { $menuTypeId = $menuTypeIds[0] ?? "basal"; } + $ym = $dateObj->format("Y-m"); $day = $dateObj->format("d"); - $baseDir = comedor_day_base_dir($centro_id, $source_aulario_id, $ym, $day); - if ($baseDir === null) { - http_response_code(400); - die(json_encode(["error" => "Invalid path parameters", "code" => "INVALID_PATH"])); - } - $dataPath = "$baseDir/_datos.json"; - - $menuData = [ - "date" => $date, - "menus" => [] - ]; - - if (file_exists($dataPath)) { - $existing = json_decode(file_get_contents($dataPath), true); - if (is_array($existing)) { - $menuData = array_merge($menuData, $existing); - } - } - - if (!isset($menuData["menus"][$menuTypeId])) { - $menuData["menus"][$menuTypeId] = blank_menu(); - } - - $menuForType = $menuData["menus"][$menuTypeId]; - - echo json_encode([ - "success" => true, - "date" => $date, - "menu_type" => $menuTypeId, - "menu_types" => $menuTypes, - "menu" => $menuForType - ]); + $menuData = ["date" => $date, "menus" => []]; + $existing = db_get_comedor_entry($centro_id, $source_aulario_id, $ym, $day); + if (!empty($existing)) { $menuData = array_merge($menuData, $existing); } + if (!isset($menuData["menus"][$menuTypeId])) { $menuData["menus"][$menuTypeId] = blank_menu(); } + echo json_encode(["success" => true, "date" => $date, "menu_type" => $menuTypeId, "menu_types" => $menuTypes, "menu" => $menuData["menus"][$menuTypeId]]); } function handle_save_menu() { global $centro_id, $source_aulario_id; - - // Parse JSON body - $input = json_decode(file_get_contents("php://input"), true); - if (!$input) { - $input = $_POST; - } - - $date = $input["date"] ?? date("Y-m-d"); + $input = json_decode(file_get_contents("php://input"), true) ?: $_POST; + $date = $input["date"] ?? date("Y-m-d"); $menuTypeId = safe_id_segment($input["menu_type"] ?? ""); - $plates = $input["plates"] ?? []; - - // Validate date + $plates = $input["plates"] ?? []; $dateObj = DateTime::createFromFormat("Y-m-d", $date); - if (!$dateObj) { - http_response_code(400); - die(json_encode(["error" => "Invalid date format", "code" => "INVALID_FORMAT"])); - } + if (!$dateObj) { http_response_code(400); die(json_encode(["error" => "Invalid date format", "code" => "INVALID_FORMAT"])); } $date = $dateObj->format("Y-m-d"); - - // Validate menu type - $menuTypes = get_menu_types($centro_id, $source_aulario_id); - $validMenuTypeIds = []; - foreach ($menuTypes as $t) { - if (!empty($t["id"])) { - $validMenuTypeIds[] = $t["id"]; - } - } - - if (!in_array($menuTypeId, $validMenuTypeIds)) { - http_response_code(400); - die(json_encode(["error" => "Invalid menu type", "code" => "INVALID_MENU_TYPE"])); - } - - // Get existing menu data - $ym = $dateObj->format("Y-m"); + $menuTypes = get_menu_types($centro_id, $source_aulario_id); + $validMenuTypeIds = array_column($menuTypes, "id"); + if (!in_array($menuTypeId, $validMenuTypeIds)) { http_response_code(400); die(json_encode(["error" => "Invalid menu type", "code" => "INVALID_MENU_TYPE"])); } + $ym = $dateObj->format("Y-m"); $day = $dateObj->format("d"); - $baseDir = comedor_day_base_dir($centro_id, $source_aulario_id, $ym, $day); - if ($baseDir === null) { - http_response_code(400); - die(json_encode(["error" => "Invalid path parameters", "code" => "INVALID_PATH"])); - } - $dataPath = "$baseDir/_datos.json"; - - $menuData = [ - "date" => $date, - "menus" => [] - ]; - - if (file_exists($dataPath)) { - $existing = json_decode(file_get_contents($dataPath), true); - if (is_array($existing)) { - $menuData = array_merge($menuData, $existing); + $menuData = ["date" => $date, "menus" => []]; + $existing = db_get_comedor_entry($centro_id, $source_aulario_id, $ym, $day); + if (!empty($existing)) { $menuData = array_merge($menuData, $existing); } + if (!isset($menuData["menus"][$menuTypeId])) { $menuData["menus"][$menuTypeId] = blank_menu(); } + foreach (["primero", "segundo", "postre"] as $plateKey) { + if (isset($plates[$plateKey]["name"])) { + $menuData["menus"][$menuTypeId]["plates"][$plateKey]["name"] = trim($plates[$plateKey]["name"]); } } - - if (!isset($menuData["menus"][$menuTypeId])) { - $menuData["menus"][$menuTypeId] = blank_menu(); - } - - // Update plates - $validPlates = ["primero", "segundo", "postre"]; - foreach ($validPlates as $plateKey) { - if (isset($plates[$plateKey])) { - if (isset($plates[$plateKey]["name"])) { - $menuData["menus"][$menuTypeId]["plates"][$plateKey]["name"] = trim($plates[$plateKey]["name"]); - } - // Note: pictogram upload not supported via JSON API - use form-data instead - } - } - - // Save menu - if (!is_dir($baseDir)) { - mkdir($baseDir, 0777, true); - } - file_put_contents($dataPath, json_encode($menuData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - - echo json_encode([ - "success" => true, - "date" => $date, - "menu_type" => $menuTypeId, - "menu" => $menuData["menus"][$menuTypeId] - ]); + db_set_comedor_entry($centro_id, $source_aulario_id, $ym, $day, $menuData); + echo json_encode(["success" => true, "date" => $date, "menu_type" => $menuTypeId, "menu" => $menuData["menus"][$menuTypeId]]); } function handle_add_menu_type() { global $centro_id, $source_aulario_id; - - $input = json_decode(file_get_contents("php://input"), true); - if (!$input) { - $input = $_POST; - } - - $newId = safe_id_segment(strtolower(trim($input["id"] ?? ""))); + $input = json_decode(file_get_contents("php://input"), true) ?: $_POST; + $newId = safe_id_segment(strtolower(trim($input["id"] ?? ""))); $newLabel = trim($input["label"] ?? ""); $newColor = trim($input["color"] ?? "#0d6efd"); - - if ($newId === "" || $newLabel === "") { - http_response_code(400); - die(json_encode(["error" => "id and label are required", "code" => "MISSING_PARAM"])); - } - - $menuTypesPath = menu_types_path($centro_id, $source_aulario_id); - if ($menuTypesPath === null) { - http_response_code(400); - die(json_encode(["error" => "Invalid path parameters", "code" => "INVALID_PATH"])); - } + if ($newId === "" || $newLabel === "") { http_response_code(400); die(json_encode(["error" => "id and label are required", "code" => "MISSING_PARAM"])); } $menuTypes = get_menu_types($centro_id, $source_aulario_id); - - // Check if already exists foreach ($menuTypes as $t) { - if (($t["id"] ?? "") === $newId) { - http_response_code(400); - die(json_encode(["error" => "Menu type already exists", "code" => "DUPLICATE"])); - } + if (($t["id"] ?? "") === $newId) { http_response_code(400); die(json_encode(["error" => "Menu type already exists", "code" => "DUPLICATE"])); } } - $menuTypes[] = ["id" => $newId, "label" => $newLabel, "color" => $newColor]; - file_put_contents($menuTypesPath, json_encode($menuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - - echo json_encode([ - "success" => true, - "menu_type" => ["id" => $newId, "label" => $newLabel, "color" => $newColor], - "message" => "Menu type added successfully" - ]); + db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); + echo json_encode(["success" => true, "menu_type" => ["id" => $newId, "label" => $newLabel, "color" => $newColor], "message" => "Menu type added successfully"]); } function handle_delete_menu_type() { global $centro_id, $source_aulario_id; - - $input = json_decode(file_get_contents("php://input"), true); - if (!$input) { - $input = $_POST; - } - + $input = json_decode(file_get_contents("php://input"), true) ?: $_POST; $deleteId = safe_id_segment(trim($input["id"] ?? "")); - - if ($deleteId === "") { - http_response_code(400); - die(json_encode(["error" => "id is required", "code" => "MISSING_PARAM"])); - } - - $menuTypesPath = menu_types_path($centro_id, $source_aulario_id); - if ($menuTypesPath === null) { - http_response_code(400); - die(json_encode(["error" => "Invalid path parameters", "code" => "INVALID_PATH"])); - } - $menuTypes = get_menu_types($centro_id, $source_aulario_id); - - $deleted = false; - $newMenuTypes = []; - foreach ($menuTypes as $t) { - if (($t["id"] ?? "") === $deleteId) { - $deleted = true; - } else { - $newMenuTypes[] = $t; - } - } - - if (!$deleted) { - http_response_code(404); - die(json_encode(["error" => "Menu type not found", "code" => "NOT_FOUND"])); - } - - file_put_contents($menuTypesPath, json_encode($newMenuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - - echo json_encode([ - "success" => true, - "message" => "Menu type deleted successfully" - ]); + if ($deleteId === "") { http_response_code(400); die(json_encode(["error" => "id is required", "code" => "MISSING_PARAM"])); } + $menuTypes = get_menu_types($centro_id, $source_aulario_id); + $newMenuTypes = array_values(array_filter($menuTypes, fn($t) => ($t["id"] ?? "") !== $deleteId)); + if (count($newMenuTypes) === count($menuTypes)) { http_response_code(404); die(json_encode(["error" => "Menu type not found", "code" => "NOT_FOUND"])); } + db_set_comedor_menu_types($centro_id, $source_aulario_id, $newMenuTypes); + echo json_encode(["success" => true, "message" => "Menu type deleted successfully"]); } function handle_rename_menu_type() { global $centro_id, $source_aulario_id; - - $input = json_decode(file_get_contents("php://input"), true); - if (!$input) { - $input = $_POST; - } - + $input = json_decode(file_get_contents("php://input"), true) ?: $_POST; $renameId = safe_id_segment(trim($input["id"] ?? "")); $newLabel = trim($input["label"] ?? ""); $newColor = trim($input["color"] ?? ""); - - if ($renameId === "" || $newLabel === "") { - http_response_code(400); - die(json_encode(["error" => "id and label are required", "code" => "MISSING_PARAM"])); - } - - $menuTypesPath = menu_types_path($centro_id, $source_aulario_id); - if ($menuTypesPath === null) { - http_response_code(400); - die(json_encode(["error" => "Invalid path parameters", "code" => "INVALID_PATH"])); - } + if ($renameId === "" || $newLabel === "") { http_response_code(400); die(json_encode(["error" => "id and label are required", "code" => "MISSING_PARAM"])); } $menuTypes = get_menu_types($centro_id, $source_aulario_id); - $found = false; foreach ($menuTypes as &$t) { if (($t["id"] ?? "") === $renameId) { $t["label"] = $newLabel; - if ($newColor !== "") { - $t["color"] = $newColor; - } + if ($newColor !== "") { $t["color"] = $newColor; } $found = true; break; } } unset($t); - - if (!$found) { - http_response_code(404); - die(json_encode(["error" => "Menu type not found", "code" => "NOT_FOUND"])); - } - - file_put_contents($menuTypesPath, json_encode($menuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - - echo json_encode([ - "success" => true, - "menu_type" => ["id" => $renameId, "label" => $newLabel, "color" => $newColor], - "message" => "Menu type renamed successfully" - ]); + if (!$found) { http_response_code(404); die(json_encode(["error" => "Menu type not found", "code" => "NOT_FOUND"])); } + db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); + echo json_encode(["success" => true, "message" => "Menu type renamed successfully"]); } diff --git a/public_html/aulatek/aulario.php b/public_html/aulatek/aulario.php index df80422..9259f3f 100644 --- a/public_html/aulatek/aulario.php +++ b/public_html/aulatek/aulario.php @@ -2,11 +2,11 @@ require_once "_incl/auth_redir.php"; require_once "_incl/pre-body.php"; require_once "../_incl/tools.security.php"; +require_once "../_incl/db.php"; $aulario_id = safe_id_segment($_GET["id"] ?? ""); -$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); -$aulario_path = safe_aulario_config_path($centro_id, $aulario_id); -$aulario = ($aulario_path && file_exists($aulario_path)) ? json_decode(file_get_contents($aulario_path), true) : null; +$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); +$aulario = db_get_aulario($centro_id, $aulario_id); if (!$aulario || !is_array($aulario)) { ?> diff --git a/public_html/aulatek/comedor.php b/public_html/aulatek/comedor.php index 3b47bdd..32e7d0d 100644 --- a/public_html/aulatek/comedor.php +++ b/public_html/aulatek/comedor.php @@ -1,6 +1,7 @@ "basal", "label" => "Menú basal", "color" => "#0d6efd"], + ["id" => "basal", "label" => "Menú basal", "color" => "#0d6efd"], ["id" => "vegetariano", "label" => "Menú vegetariano", "color" => "#198754"], - ["id" => "alergias", "label" => "Menú alergias", "color" => "#dc3545"], + ["id" => "alergias", "label" => "Menú alergias", "color" => "#dc3545"], ]; -if (!file_exists($menuTypesPath)) { - if (!is_dir(dirname($menuTypesPath))) { - mkdir(dirname($menuTypesPath), 0777, true); - } - file_put_contents($menuTypesPath, json_encode($defaultMenuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); -} -$menuTypes = json_decode(@file_get_contents($menuTypesPath), true); +$menuTypes = db_get_comedor_menu_types($centro_id, $source_aulario_id); if (!is_array($menuTypes) || count($menuTypes) === 0) { $menuTypes = $defaultMenuTypes; + db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); } $menuTypeIds = []; @@ -71,10 +65,9 @@ if (!in_array($menuTypeId, $menuTypeIds, true)) { $menuTypeId = $menuTypeIds[0] ?? "basal"; } -$ym = $dateObj->format("Y-m"); +$ym = $dateObj->format("Y-m"); $day = $dateObj->format("d"); -$baseDir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$source_aulario_id/Comedor/$ym/$day"; -$dataPath = "$baseDir/_datos.json"; + function blank_menu() { @@ -91,11 +84,9 @@ $menuData = [ "date" => $date, "menus" => [] ]; -if (file_exists($dataPath)) { - $existing = json_decode(file_get_contents($dataPath), true); - if (is_array($existing)) { - $menuData = array_merge($menuData, $existing); - } +$existing = db_get_comedor_entry($centro_id, $source_aulario_id, $ym, $day); +if (is_array($existing) && !empty($existing)) { + $menuData = array_merge($menuData, $existing); } if (!isset($menuData["menus"][$menuTypeId])) { $menuData["menus"][$menuTypeId] = blank_menu(); @@ -251,14 +242,11 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) { if ($newId !== "" && $newLabel !== "") { $exists = false; foreach ($menuTypes as $t) { - if (($t["id"] ?? "") === $newId) { - $exists = true; - break; - } + if (($t["id"] ?? "") === $newId) { $exists = true; break; } } if (!$exists) { $menuTypes[] = ["id" => $newId, "label" => $newLabel, "color" => $newColor]; - file_put_contents($menuTypesPath, json_encode($menuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); header("Location: /entreaulas/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($newId)); exit; } @@ -268,19 +256,10 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) { if ($action === "delete_type") { $deleteId = safe_id_segment(trim($_POST["delete_type_id"] ?? "")); if ($deleteId !== "") { - $deleted = false; - $newMenuTypes = []; - foreach ($menuTypes as $t) { - if (($t["id"] ?? "") === $deleteId) { - $deleted = true; - } else { - $newMenuTypes[] = $t; - } - } - if ($deleted) { + $newMenuTypes = array_values(array_filter($menuTypes, fn($t) => ($t["id"] ?? "") !== $deleteId)); + if (count($newMenuTypes) !== count($menuTypes)) { $menuTypes = $newMenuTypes; - file_put_contents($menuTypesPath, json_encode($menuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - // Redirect to the first available menu type or default + db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); $redirectMenuId = !empty($menuTypes) ? $menuTypes[0]["id"] : "basal"; header("Location: /entreaulas/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($redirectMenuId)); exit; @@ -296,15 +275,12 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) { foreach ($menuTypes as &$t) { if (($t["id"] ?? "") === $renameId) { $t["label"] = $newLabel; - if ($newColor !== "") { - $t["color"] = $newColor; - } + if ($newColor !== "") { $t["color"] = $newColor; } break; } } - // Clean up the reference to avoid accidental usage after the loop unset($t); - file_put_contents($menuTypesPath, json_encode($menuTypes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); header("Location: /entreaulas/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($renameId)); exit; } @@ -316,23 +292,19 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) { $menuData["menus"][$menuTypeId] = blank_menu(); } + // Pictogram images still stored on filesystem in Comedor dir + $baseDir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$source_aulario_id/Comedor/$ym/$day"; $plates = ["primero", "segundo", "postre"]; foreach ($plates as $plate) { $name = trim($_POST["name_" . $plate] ?? ""); $menuData["menus"][$menuTypeId]["plates"][$plate]["name"] = $name; - $pictUpload = handle_image_upload("pictogram_file_" . $plate, $menuTypeId . "_" . $plate . "_pict", $baseDir, $uploadErrors); - if ($pictUpload !== null) { $menuData["menus"][$menuTypeId]["plates"][$plate]["pictogram"] = $pictUpload; } - } - if (!is_dir($baseDir)) { - mkdir($baseDir, 0777, true); - } - file_put_contents($dataPath, json_encode($menuData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + db_set_comedor_entry($centro_id, $source_aulario_id, $ym, $day, $menuData); $saveNotice = "Menú guardado correctamente."; } } @@ -359,11 +331,10 @@ foreach ($userAulas as $aulaId) { if ($aulaIdSafe === "") { continue; } - $aulaPath = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aulaIdSafe.json"; - $aulaData = file_exists($aulaPath) ? json_decode(file_get_contents($aulaPath), true) : null; + $aulaData = db_get_aulario($centro_id, $aulaIdSafe); $aulaOptions[] = [ - "id" => $aulaIdSafe, - "name" => $aulaData["name"] ?? $aulaIdSafe + "id" => $aulaIdSafe, + "name" => $aulaData["name"] ?? $aulaIdSafe, ]; } require_once "_incl/pre-body.php"; diff --git a/public_html/aulatek/index.php b/public_html/aulatek/index.php old mode 100755 new mode 100644 index ce0271a..09e12d7 --- a/public_html/aulatek/index.php +++ b/public_html/aulatek/index.php @@ -2,30 +2,29 @@ require_once "_incl/auth_redir.php"; require_once "_incl/pre-body.php"; require_once "../_incl/tools.security.php"; +require_once "../_incl/db.php"; ?>
-

¡Hola, !

+

¡Hola, !

Bienvenidx a la plataforma de gestión de aularios conectados. Desde aquí podrás administrar los aularios asociados a tu cuenta.
- - - diff --git a/public_html/aulatek/paneldiario.php b/public_html/aulatek/paneldiario.php index e11a5f3..056229a 100755 --- a/public_html/aulatek/paneldiario.php +++ b/public_html/aulatek/paneldiario.php @@ -1,6 +1,7 @@ format("Y-m-d"); - $menuTypesPath = ($centro_id !== '' && $source_aulario_id !== '') ? "/DATA/entreaulas/Centros/$centro_id/Aularios/$source_aulario_id/Comedor-MenuTypes.json" : ""; $defaultMenuTypes = [ ["id" => "basal", "label" => "Menú basal", "color" => "#0d6efd"], ["id" => "vegetariano", "label" => "Menú vegetariano", "color" => "#198754"], ["id" => "alergias", "label" => "Menú alergias", "color" => "#dc3545"], ]; - $menuTypes = ($menuTypesPath !== '' && file_exists($menuTypesPath)) ? json_decode(@file_get_contents($menuTypesPath), true) : null; + $menuTypes = ($centro_id !== '' && $source_aulario_id !== '') ? db_get_comedor_menu_types($centro_id, $source_aulario_id) : []; if (!is_array($menuTypes) || count($menuTypes) === 0) { $menuTypes = $defaultMenuTypes; } @@ -822,17 +820,13 @@ switch ($view_action) { $menuTypeId = $menuTypeIds[0] ?? "basal"; } - $ym = $dateObj->format("Y-m"); + $ym = $dateObj->format("Y-m"); $day = $dateObj->format("d"); - $dataPath = ($centro_id !== '' && $source_aulario_id !== '') ? "/DATA/entreaulas/Centros/$centro_id/Aularios/$source_aulario_id/Comedor/$ym/$day/_datos.json" : ""; - $menuData = [ - "date" => $date, - "menus" => [] - ]; - if ($dataPath !== '' && file_exists($dataPath)) { - $existing = json_decode(file_get_contents($dataPath), true); - if (is_array($existing)) { + $menuData = ["date" => $date, "menus" => []]; + if ($centro_id !== '' && $source_aulario_id !== '') { + $existing = db_get_comedor_entry($centro_id, $source_aulario_id, $ym, $day); + if (!empty($existing)) { $menuData = array_merge($menuData, $existing); } } diff --git a/public_html/aulatek/proyectos.php b/public_html/aulatek/proyectos.php index 7ff347c..d68606b 100644 --- a/public_html/aulatek/proyectos.php +++ b/public_html/aulatek/proyectos.php @@ -1,6 +1,7 @@ $aulario_id, - "project_id" => $project_id, - "permission" => "request_edit" + "project_id" => $project_id, + "permission" => "request_edit", ]; $message = "Proyecto compartido correctamente."; } - file_put_contents($target_config_path, json_encode($target_config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + // Save back: build extra JSON excluding standard fields + $extra_skip = ['name', 'icon']; + $extra = []; + foreach ($target_config as $k => $v) { + if (!in_array($k, $extra_skip, true)) { + $extra[$k] = $v; + } + } + db()->prepare( + "UPDATE aularios SET extra = ? WHERE centro_id = ? AND aulario_id = ?" + )->execute([json_encode($extra, JSON_UNESCAPED_UNICODE), $centro_id, $target_aulario]); } } } @@ -1570,10 +1565,9 @@ $view = $current_project ? "project" : "list"; @@ -1636,27 +1630,14 @@ $view = $current_project ? "project" : "list"; $entry, - "name" => $config["name"] ?? "Aulario Desconocido", - "linked_projects" => $config["linked_projects"] ?? [] - ]; - } - } - } + foreach ($aularios_db as $aid => $adata) { + $aularios[] = [ + "id" => $aid, + "name" => $adata["name"] ?? "Aulario Desconocido", + "linked_projects" => $adata["linked_projects"] ?? [], + ]; } return $aularios; } @@ -1918,10 +1899,8 @@ $view = $current_project ? "project" : "list";
diff --git a/public_html/aulatek/supercafe.php b/public_html/aulatek/supercafe.php index e1d0355..1b53a4a 100644 --- a/public_html/aulatek/supercafe.php +++ b/public_html/aulatek/supercafe.php @@ -1,6 +1,7 @@ $aulario_data) { $aulario_name = $aulario_data['name'] ?? $aulario_id; - $alumnos_path = "$aularios_path/$aulario_id/Alumnos"; + $alumnos_path = "$aularios_dir/$aulario_id/Alumnos"; if (!is_dir($alumnos_path)) { continue; } foreach (glob("$alumnos_path/*/", GLOB_ONLYDIR) ?: [] as $alumno_dir) { $alumno_name = basename($alumno_dir); - $key = $aulario_id . ':' . $alumno_name; + $key = $aulario_id . ':' . $alumno_name; $personas[$key] = [ 'Nombre' => $alumno_name, 'Region' => $aulario_name, @@ -62,7 +58,6 @@ if ($centro_id === '') { exit; } -define('SC_DATA_DIR', "/DATA/entreaulas/Centros/$centro_id/SuperCafe/Comandas"); define('SC_MAX_DEBTS', 3); $estados_colores = [ @@ -81,20 +76,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $can_edit) { $action = $_POST['action'] ?? ''; if ($action === 'change_status') { - $order_id = safe_id($_POST['order_id'] ?? ''); + $order_id = safe_id($_POST['order_id'] ?? ''); $new_status = $_POST['status'] ?? ''; if ($order_id !== '' && array_key_exists($new_status, $estados_colores)) { - $order_file = SC_DATA_DIR . '/' . $order_id . '.json'; - if (is_readable($order_file)) { - $data = json_decode(file_get_contents($order_file), true); - if (is_array($data)) { - $data['Estado'] = $new_status; - file_put_contents( - $order_file, - json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), - LOCK_EX - ); - } + $row = db_get_supercafe_order($centro_id, $order_id); + if ($row) { + db_upsert_supercafe_order( + $centro_id, $order_id, + $row['fecha'], $row['persona'], $row['comanda'], $row['notas'], $new_status + ); } } header('Location: /entreaulas/supercafe.php'); @@ -104,34 +94,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $can_edit) { if ($action === 'delete') { $order_id = safe_id($_POST['order_id'] ?? ''); if ($order_id !== '') { - $order_file = SC_DATA_DIR . '/' . $order_id . '.json'; - if (is_file($order_file)) { - unlink($order_file); - } + db()->prepare('DELETE FROM supercafe_orders WHERE centro_id = ? AND order_ref = ?') + ->execute([$centro_id, $order_id]); } header('Location: /entreaulas/supercafe.php'); exit; } } -// Load all orders +// Load all orders from DB +$db_orders = db_get_supercafe_orders($centro_id); $orders = []; -if (is_dir(SC_DATA_DIR)) { - $files = glob(SC_DATA_DIR . '/*.json') ?: []; - foreach ($files as $file) { - $data = json_decode(file_get_contents($file), true); - if (!is_array($data)) { - continue; - } - $data['_id'] = basename($file, '.json'); - $orders[] = $data; - } +foreach ($db_orders as $row) { + $orders[] = [ + '_id' => $row['order_ref'], + 'Fecha' => $row['fecha'], + 'Persona'=> $row['persona'], + 'Comanda'=> $row['comanda'], + 'Notas' => $row['notas'], + 'Estado' => $row['estado'], + ]; } // Sort newest first (by Fecha desc) -usort($orders, function ($a, $b) { - return strcmp($b['Fecha'] ?? '', $a['Fecha'] ?? ''); -}); +usort($orders, fn($a, $b) => strcmp($b['Fecha'] ?? '', $a['Fecha'] ?? '')); $orders_active = array_filter($orders, fn($o) => ($o['Estado'] ?? '') !== 'Deuda'); $orders_deuda = array_filter($orders, fn($o) => ($o['Estado'] ?? '') === 'Deuda'); @@ -139,6 +125,7 @@ $orders_deuda = array_filter($orders, fn($o) => ($o['Estado'] ?? '') === 'Deuda require_once "_incl/pre-body.php"; ?> +

SuperCafe – Cafetería

diff --git a/public_html/aulatek/supercafe_edit.php b/public_html/aulatek/supercafe_edit.php index ded87ea..2e187b7 100644 --- a/public_html/aulatek/supercafe_edit.php +++ b/public_html/aulatek/supercafe_edit.php @@ -1,6 +1,7 @@ $aulario_data) { $aulario_name = $aulario_data['name'] ?? $aulario_id; - $alumnos_path = "$aularios_path/$aulario_id/Alumnos"; + $alumnos_path = "$aularios_dir/$aulario_id/Alumnos"; if (!is_dir($alumnos_path)) { continue; } $alumno_dirs = glob("$alumnos_path/*/", GLOB_ONLYDIR) ?: []; - usort($alumno_dirs, function ($a, $b) { - return strcasecmp(basename($a), basename($b)); - }); + usort($alumno_dirs, fn($a, $b) => strcasecmp(basename($a), basename($b))); foreach ($alumno_dirs as $alumno_dir) { $alumno_name = basename($alumno_dir); - // Key uses ':' as separator; safe_id_segment chars [A-Za-z0-9_-] exclude ':' - $key = $aulario_id . ':' . $alumno_name; + $key = $aulario_id . ':' . $alumno_name; $personas[$key] = [ 'Nombre' => $alumno_name, 'Region' => $aulario_name, @@ -62,43 +51,14 @@ function sc_load_personas_from_alumnos($centro_id) return $personas; } -function sc_load_menu($sc_base) -{ - $path = "$sc_base/Menu.json"; - if (!file_exists($path)) { - return []; - } - $data = json_decode(file_get_contents($path), true); - return is_array($data) ? $data : []; -} - -function sc_count_debts($persona_key) -{ - if (!is_dir(SC_DATA_DIR)) { - return 0; - } - $count = 0; - foreach (glob(SC_DATA_DIR . '/*.json') ?: [] as $file) { - $data = json_decode(file_get_contents($file), true); - if (is_array($data) - && ($data['Persona'] ?? '') === $persona_key - && ($data['Estado'] ?? '') === 'Deuda') { - $count++; - } - } - return $count; -} - // Determine if creating or editing $order_id = safe_id($_GET['id'] ?? ''); $is_new = $order_id === ''; if ($is_new) { - $raw_id = uniqid('sc', true); - $order_id = preg_replace('/[^a-zA-Z0-9_-]/', '', $raw_id); + $order_id = db_next_supercafe_ref($centro_id); } -$order_file = SC_DATA_DIR . '/' . $order_id . '.json'; - +// Load existing order from DB (or defaults) $order_data = [ 'Fecha' => date('Y-m-d'), 'Persona' => '', @@ -106,15 +66,21 @@ $order_data = [ 'Notas' => '', 'Estado' => 'Pedido', ]; -if (!$is_new && is_readable($order_file)) { - $existing = json_decode(file_get_contents($order_file), true); - if (is_array($existing)) { - $order_data = array_merge($order_data, $existing); +if (!$is_new) { + $existing = db_get_supercafe_order($centro_id, $order_id); + if ($existing) { + $order_data = [ + 'Fecha' => $existing['fecha'], + 'Persona' => $existing['persona'], + 'Comanda' => $existing['comanda'], + 'Notas' => $existing['notas'], + 'Estado' => $existing['estado'], + ]; } } $personas = sc_load_personas_from_alumnos($centro_id); -$menu = sc_load_menu($sc_base); +$menu = db_get_supercafe_menu($centro_id); // Group personas by aulario for the optgroup picker $personas_by_aulario = []; @@ -133,11 +99,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $estado = 'Pedido'; } - // Validar persona if ($persona_key === '' || (!empty($personas) && !array_key_exists($persona_key, $personas))) { $error = '¡Hay que elegir una persona válida!'; } else { - // Construir comanda desde los campos de categoría visual $comanda_parts = []; if (!empty($menu)) { foreach ($menu as $category => $items) { @@ -152,48 +116,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $comanda_parts[] = $manual; } } - $comanda_str = implode(', ', $comanda_parts); - - // Comprobar deudas - $prev_persona = $order_data['Persona'] ?? ''; + $comanda_str = implode(', ', $comanda_parts); + $prev_persona = $order_data['Persona']; if ($is_new || $prev_persona !== $persona_key) { - $debt_count = sc_count_debts($persona_key); + $debt_count = db_supercafe_count_debts($centro_id, $persona_key); if ($debt_count >= SC_MAX_DEBTS) { $error = 'Esta persona tiene ' . $debt_count . ' comandas en deuda. No se puede realizar el pedido.'; } } - if ($error === '') { - $new_data = [ - 'Fecha' => date('Y-m-d'), - 'Persona' => $persona_key, - 'Comanda' => $comanda_str, - 'Notas' => $notas, - 'Estado' => $is_new ? 'Pedido' : $estado, - ]; - - if (!is_dir(SC_DATA_DIR)) { - mkdir(SC_DATA_DIR, 0755, true); - } - - $tmp = SC_DATA_DIR . '/.' . $order_id . '.tmp'; - $bytes = file_put_contents( - $tmp, - json_encode($new_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), - LOCK_EX + db_upsert_supercafe_order( + $centro_id, $order_id, + date('Y-m-d'), $persona_key, $comanda_str, $notas, + $is_new ? 'Pedido' : $estado ); - if ($bytes === false || !rename($tmp, $order_file)) { - @unlink($tmp); - $error = 'Error al guardar la comanda.'; - } else { - header('Location: /entreaulas/supercafe.php'); - exit; - } + header('Location: /entreaulas/supercafe.php'); + exit; } } } require_once "_incl/pre-body.php"; + ?>

Comanda

diff --git a/public_html/club/cal.php b/public_html/club/cal.php index 97ba209..d67ebb4 100755 --- a/public_html/club/cal.php +++ b/public_html/club/cal.php @@ -1,10 +1,11 @@ $_POST["title"], - "note" => $_POST["note"], - "mapa" => [ - "url" => $_POST["mapa_url"] - ] - ]; + "title" => $_POST["title"], + "note" => $_POST["note"], + "mapa" => ["url" => $_POST["mapa_url"]], + ]; $file = $_POST["date"]; - $val = file_put_contents("/DATA/club/IMG/$file/data.json", json_encode($data, JSON_UNESCAPED_SLASHES)); + db_set_club_event($file, $data); header("Location: /club/"); die(); } diff --git a/public_html/club/index.php b/public_html/club/index.php index 167fd72..0dc861c 100755 --- a/public_html/club/index.php +++ b/public_html/club/index.php @@ -1,5 +1,6 @@
  • - diff --git a/public_html/club/upload/upload.php b/public_html/club/upload/upload.php index 920456a..0811646 100755 --- a/public_html/club/upload/upload.php +++ b/public_html/club/upload/upload.php @@ -1,7 +1,8 @@ prepare("DELETE FROM aularios WHERE centro_id = ? AND aulario_id = ?") + ->execute([$centro_id, $aulario_id]); + // Remove comedor, diario, panel data + db()->prepare("DELETE FROM comedor_menu_types WHERE centro_id = ? AND aulario_id = ?") + ->execute([$centro_id, $aulario_id]); + db()->prepare("DELETE FROM comedor_entries WHERE centro_id = ? AND aulario_id = ?") + ->execute([$centro_id, $aulario_id]); + db()->prepare("DELETE FROM diario_entries WHERE centro_id = ? AND aulario_id = ?") + ->execute([$centro_id, $aulario_id]); + db()->prepare("DELETE FROM panel_alumno WHERE centro_id = ? AND aulario_id = ?") + ->execute([$centro_id, $aulario_id]); + // Remove filesystem directory with student photos $aulario_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id"; - function rrmdir($dir) { + function rrmdir($dir) + { if (is_dir($dir)) { - $objects = scandir($dir); - foreach ($objects as $object) { - if ($object != "." && $object != "..") { - $obj_path = $dir . "/" . $object; - if (is_dir($obj_path)) { - rrmdir($obj_path); - } else { - unlink($obj_path); - } + foreach (scandir($dir) as $object) { + if ($object !== "." && $object !== "..") { + $p = "$dir/$object"; + is_dir($p) ? rrmdir($p) : unlink($p); } } rmdir($dir); } } rrmdir($aulario_dir); - // Remove aulario config file - unlink($aulario_file); header("Location: ?action=index"); exit(); break; case "create": - $user_data = $_SESSION["auth_data"]; - $centro_id = safe_path_segment(Sf($_POST["centro"] ?? "")); - if (empty($centro_id) || !is_dir("/DATA/entreaulas/Centros/$centro_id")) { + $centro_id = safe_path_segment(Sf($_POST["centro"] ?? "")); + $aulario_id = strtolower(preg_replace("/[^a-zA-Z0-9_-]/", "_", Sf($_POST["name"] ?? ""))); + if (empty($centro_id) || empty($aulario_id)) { + die("Datos incompletos."); + } + // Ensure centro exists in DB + $stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); + $stmt->execute([$centro_id]); + if (!$stmt->fetch()) { die("Centro no válido."); } - $aulario_id = strtolower(preg_replace("/[^a-zA-Z0-9_-]/", "_", Sf($_POST["name"] ?? ""))); - $aulario_data = [ - "name" => Sf($_POST["name"] ?? ""), - "icon" => Sf($_POST["icon"] ?? "/static/logo-entreaulas.png") - ]; - // Make path recursive (mkdir -p equivalent) - @mkdir("/DATA/entreaulas/Centros/$centro_id/Aularios/", 0777, true); - @mkdir("/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id/Proyectos/", 0777, true); - file_put_contents("/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id.json", json_encode($aulario_data)); - // Update user data - $_SESSION["auth_data"]["entreaulas"]["aulas"][] = $aulario_id; + db()->prepare( + "INSERT OR IGNORE INTO aularios (centro_id, aulario_id, name, icon) VALUES (?, ?, ?, ?)" + )->execute([ + $centro_id, $aulario_id, + Sf($_POST["name"] ?? ""), + Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"), + ]); + // Create Alumnos directory for photo-based features + @mkdir("/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id/Proyectos/", 0755, true); header("Location: ?action=index"); exit(); break; case "save_edit": $aulario_id = safe_path_segment(Sf($_POST["aulario_id"] ?? "")); - $centro_id = safe_path_segment(Sf($_POST["centro_id"] ?? "")); - $aulario_file = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id.json"; - if (!file_exists($aulario_file)) { + $centro_id = safe_path_segment(Sf($_POST["centro_id"] ?? "")); + if ($aulario_id === "" || $centro_id === "") { + die("Parámetros inválidos."); + } + // Fetch existing extra data + $existing = db_get_aulario($centro_id, $aulario_id); + if ($existing === null) { die("Aulario no encontrado."); } - $aulario_data = json_decode(file_get_contents($aulario_file), true); - $aulario_data["name"] = Sf($_POST["name"] ?? ""); - $aulario_data["icon"] = Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"); - - // Handle shared comedor configuration - $share_comedor_from = safe_path_segment(Sf($_POST["share_comedor_from"] ?? "")); - - if (!empty($share_comedor_from) && $share_comedor_from !== "none") { - $aulario_data["shared_comedor_from"] = $share_comedor_from; - } else { - unset($aulario_data["shared_comedor_from"]); - } - - // Handle linked projects configuration - $linked_projects = []; - $linked_aularios = $_POST["linked_aulario"] ?? []; - $linked_project_ids = $_POST["linked_project_id"] ?? []; - $linked_permissions = $_POST["linked_permission"] ?? []; - - for ($i = 0; $i < count($linked_aularios); $i++) { - $src_aul = safe_path_segment($linked_aularios[$i] ?? ""); - $proj_id = safe_path_segment($linked_project_ids[$i] ?? ""); - $perm = in_array(($linked_permissions[$i] ?? "read_only"), ["read_only", "request_edit", "full_edit"], true) - ? ($linked_permissions[$i] ?? "read_only") - : "read_only"; - if (!empty($src_aul) && !empty($proj_id)) { - $linked_projects[] = [ - "source_aulario" => $src_aul, - "project_id" => $proj_id, - "permission" => $perm - ]; + // Build extra JSON preserving any existing extra fields + $extra_skip = ['name', 'icon']; + $extra = []; + foreach ($existing as $k => $v) { + if (!in_array($k, $extra_skip, true)) { + $extra[$k] = $v; } } - - if (count($linked_projects) > 0) { - $aulario_data["linked_projects"] = $linked_projects; - } else { - unset($aulario_data["linked_projects"]); + // Update shared_comedor_from if posted + if (isset($_POST['shared_comedor_from'])) { + $extra['shared_comedor_from'] = Sf($_POST['shared_comedor_from']); } - @mkdir("/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id/Proyectos/", 0777, true); - file_put_contents($aulario_file, json_encode($aulario_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - header("Location: ?action=edit&aulario=" . urlencode($aulario_id) . "¢ro=" . urlencode($centro_id) . "&saved=1"); + db()->prepare( + "UPDATE aularios SET name = ?, icon = ?, extra = ? WHERE centro_id = ? AND aulario_id = ?" + )->execute([ + Sf($_POST["name"] ?? ""), + Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"), + json_encode($extra), + $centro_id, + $aulario_id, + ]); + header("Location: ?action=edit&aulario=" . urlencode($aulario_id) . "¢ro=" . urlencode($centro_id) . "&_result=" . urlencode("Cambios guardados.")); exit(); break; } -require_once "_incl/pre-body.php"; $view_action = $_GET["action"] ?? "index"; switch ($view_action) { case "new": - ?> + require_once "_incl/pre-body.php"; + $centro_id = safe_path_segment(Sf($_GET["centro"] ?? "")); + $all_centros = db_get_centro_ids(); +?>
    -

    Nuevo Aulario

    - - Aquí puedes crear un nuevo aulario para el centro que administras. - +

    Nuevo Aulario

    - - - ' . htmlspecialchars($centro_id) . ''; - } - ?> + + +
    - - + +
    - - + +
    - $aul_name) { - $proj_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aul_id/Proyectos"; - if (is_dir($proj_dir)) { - $projects = []; - $files = glob("$proj_dir/*.json"); - foreach ($files as $file) { - $proj_data = json_decode(file_get_contents($file), true); - // Only include root projects (no parent) - if ($proj_data && ($proj_data["parent_id"] ?? null) === null) { - $projects[] = [ - "id" => $proj_data["id"] ?? basename($file, ".json"), - "name" => $proj_data["name"] ?? "Sin nombre" - ]; - } - } - if (count($projects) > 0) { - $available_projects_by_aulario[$aul_id] = $projects; - } - } - } + $other_aularios = db_get_aularios($centro_id); ?> - -
    Cambios guardados correctamente.
    -
    -

    Editar Aulario:

    +

    Aulario:

    + +
    - - + +
    - - + +
    - -
    -

    Compartir Menú Comedor

    -

    Configura desde qué aulario compartir los datos del menú comedor. Si se selecciona un aulario origen, este aulario mostrará los menús del aulario seleccionado en lugar de los propios.

    -
    - - + + $adata): if ($aid === $aulario_id) continue; ?> +
    - -
    -

    Proyectos Enlazados

    -

    Selecciona proyectos raíz específicos de otros aularios para mostrarlos en este aulario. Puedes configurar el nivel de permisos: Solo lectura, Solicitar permiso para cambiar, o Cambiar sin solicitar.

    - -
    - "", "project_id" => "", "permission" => "read_only"]]; - } - foreach ($existing_links as $idx => $link): - $source_aul = $link['source_aulario'] ?? ''; - $proj_id = $link['project_id'] ?? ''; - $permission = $link['permission'] ?? 'read_only'; - ?> -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    - - - - - - -
    -
    - - - +
    + + + +
    -
    -

    Gestión de Aularios

    - - Desde esta sección puedes administrar los aularios asociados al centro que estás administrando. - - - - - - - - - - - '; - echo ''; - echo ''; - echo ''; - echo ''; - } - ?> - -
    IconoNombre - + Nuevo -
    Icono' . htmlspecialchars($aula_data['name'] ?? 'Sin Nombre') . '
    ' . $centro_id . '
    Gestionar
    +

    Gestión de Aularios

    + + +

    + + + + + + + + + $adata): ?> + + + + + + + +
    IconoNombre+ Nuevo
    Editar
    +
    - \ No newline at end of file diff --git a/public_html/sysadmin/centros.php b/public_html/sysadmin/centros.php index 5cb06dd..2aa6be5 100644 --- a/public_html/sysadmin/centros.php +++ b/public_html/sysadmin/centros.php @@ -1,10 +1,11 @@ prepare("SELECT id FROM centros WHERE centro_id = ?"); + $existing->execute([$centro_id]); + if ($existing->fetch()) { die("El centro ya existe."); } - mkdir($centro_path, 0777, true); + // Create DB record + db()->prepare("INSERT INTO centros (centro_id) VALUES (?)")->execute([$centro_id]); + // Keep filesystem directory for activity photos (Panel/Actividades) + $centro_path = "/DATA/entreaulas/Centros/$centro_id"; + if (!is_dir($centro_path)) { + mkdir($centro_path, 0755, true); + } header("Location: ?action=index"); exit(); break; case "create_activity": ini_set('memory_limit', '512M'); - ini_set("display_errors", 1); ini_set('upload_max_filesize', '256M'); ini_set('post_max_size', '256M'); $centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); - $centro_path = "/DATA/entreaulas/Centros/$centro_id"; - if (!is_dir($centro_path)) { + // Validate centro exists in DB + $stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); + $stmt->execute([$centro_id]); + if (!$stmt->fetch()) { die("Centro no válido."); } - $activity_name = safe_path_segment(Sf($_POST["name"] ?? '')); + $activity_name = safe_path_segment(Sf($_POST["name"] ?? '')); if (empty($activity_name)) { die("Nombre de la actividad no proporcionado."); } @@ -47,22 +57,20 @@ switch ($form_action) { if ($activity_photo === null || $activity_photo["error"] !== UPLOAD_ERR_OK) { die("Error al subir la foto."); } - $activity_path = "$centro_path/Panel/Actividades/$activity_name"; + $activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$activity_name"; if (is_dir($activity_path)) { die("La actividad ya existe."); } - mkdir($activity_path, 0777, true); - $photo_path = "$activity_path/photo.jpg"; - move_uploaded_file($activity_photo["tmp_name"], $photo_path); + mkdir($activity_path, 0755, true); + move_uploaded_file($activity_photo["tmp_name"], "$activity_path/photo.jpg"); header("Location: ?action=edit¢ro=" . urlencode($centro_id)); exit(); break; case "edit_activity": ini_set('memory_limit', '512M'); - ini_set("display_errors", 1); ini_set('upload_max_filesize', '256M'); ini_set('post_max_size', '256M'); - $centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); + $centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $activity_name = safe_path_segment(Sf($_GET['activity'] ?? '')); $activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$activity_name"; if (!is_dir($activity_path)) { @@ -70,27 +78,26 @@ switch ($form_action) { } $activity_photo = $_FILES["file"] ?? null; if ($activity_photo !== null && $activity_photo["error"] === UPLOAD_ERR_OK) { - $photo_path = "$activity_path/photo.jpg"; - move_uploaded_file($activity_photo["tmp_name"], $photo_path); + move_uploaded_file($activity_photo["tmp_name"], "$activity_path/photo.jpg"); } - if (safe_path_segment(Sf($_POST['nombre'] ?? '')) != $activity_name) { - $new_activity_name = safe_path_segment(Sf($_POST['nombre'] ?? '')); - $new_activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$new_activity_name"; - if (is_dir($new_activity_path)) { + $new_name = safe_path_segment(Sf($_POST['nombre'] ?? '')); + if ($new_name !== $activity_name && $new_name !== '') { + $new_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$new_name"; + if (is_dir($new_path)) { die("Ya existe una actividad con ese nombre."); } - rename($activity_path, $new_activity_path); + rename($activity_path, $new_path); } - header("Location: ?action=edit¢ro=" . urlencode($centro_id));; + header("Location: ?action=edit¢ro=" . urlencode($centro_id)); exit(); break; } -require_once "_incl/pre-body.php"; +require_once "_incl/pre-body.php"; $view_action = $_GET["action"] ?? "index"; switch ($view_action) { case "edit_activity": - $centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); + $centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $activity_name = safe_path_segment(Sf($_GET['activity'] ?? '')); $activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$activity_name"; if (!is_dir($activity_path)) { @@ -99,22 +106,20 @@ switch ($view_action) { ?>
    -

    Gestión de la Actividad:

    - - Desde esta sección puedes administrar la actividad seleccionada del panel del centro . - -
    +

    Gestión de la Actividad:

    +
    - +

    @@ -128,18 +133,16 @@ switch ($view_action) { break; case "new_activity": $centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); - $centro_path = "/DATA/entreaulas/Centros/$centro_id"; - if (!is_dir($centro_path)) { + $stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); + $stmt->execute([$centro_id]); + if (!$stmt->fetch()) { die("Centro no válido."); } ?>

    Nueva Actividad del Panel

    - - Aquí puedes crear una nueva actividad para el panel del centro . - - +
    @@ -155,13 +158,10 @@ switch ($view_action) { +?>

    Nuevo Centro

    - - Aquí puedes crear un nuevo centro para el sistema. -
    @@ -171,22 +171,21 @@ switch ($view_action) {
    - prepare("SELECT id FROM centros WHERE centro_id = ?"); + $stmt->execute([$centro_id]); + if (!$stmt->fetch()) { die("Centro no válido."); } + $aularios = db_get_aularios($centro_id); + $activities = glob("/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/*", GLOB_ONLYDIR) ?: []; ?>
    -

    Gestión del Centro:

    - - Desde esta sección puedes administrar el centro seleccionado. - +

    Gestión del Centro:

    @@ -195,25 +194,18 @@ switch ($view_action) { - - - + + - '; - echo ''; - echo ''; - echo ''; - echo ''; - } - ?> + $aula): ?> + + + + + +
    IconoNombre - + Nuevo - IconoNombre+ Nuevo
    Icono' . htmlspecialchars($aula_data['name'] ?? 'Sin Nombre') . 'Gestionar
    IconoGestionar
    @@ -224,70 +216,52 @@ switch ($view_action) { - - - + + - '; - echo ''; - echo ''; - echo ''; - echo ''; - } - ?> + + + + + + + +
    FotoNombre - + Nuevo - FotoNombre+ Nuevo
    Foto' . htmlspecialchars($activity_name) . 'Gestionar
    Gestionar
    - -

    Gestión de Centros

    - - Desde esta sección puedes administrar los centros asociados al sistema. - - - + + - '; - echo ''; - echo ''; - echo ''; - } - ?> + + + + + +
    Nombre - + Nuevo - Centro+ Nuevo
    ' . htmlspecialchars($centro_id) . 'Gestionar
    Gestionar
    - \ No newline at end of file +require_once "_incl/post-body.php"; diff --git a/public_html/sysadmin/invitations.php b/public_html/sysadmin/invitations.php index 2364f2e..50b1af6 100644 --- a/public_html/sysadmin/invitations.php +++ b/public_html/sysadmin/invitations.php @@ -1,100 +1,91 @@ true, - "single_use" => $single_use - ]; - file_put_contents("/DATA/Invitaciones_de_usuarios.json", json_encode($invitations, JSON_PRETTY_PRINT)); - header("Location: /sysadmin/invitations.php?_result=" . urlencode("Código $invitation_code creado correctamente.")); + db_upsert_invitation($code, true, $single_use); + header("Location: /sysadmin/invitations.php?_result=" . urlencode("Código $code creado correctamente.")); exit; break; case "delete": - // Handle deletion logic here - $invitations = json_decode(file_get_contents("/DATA/Invitaciones_de_usuarios.json"), true) ?? []; - $invitation_code = strtoupper($_POST['invitation_code'] ?? ''); - if (isset($invitations[$invitation_code])) { - unset($invitations[$invitation_code]); - file_put_contents("/DATA/Invitaciones_de_usuarios.json", json_encode($invitations, JSON_PRETTY_PRINT)); - } - header("Location: /sysadmin/invitations.php?_result=" . urlencode("Codigo $invitation_code borrado")); + $code = strtoupper(trim($_POST['invitation_code'] ?? '')); + db_delete_invitation($code); + header("Location: /sysadmin/invitations.php?_result=" . urlencode("Código $code borrado.")); exit; break; } require_once "_incl/pre-body.php"; -switch ($_GET['action']) { +switch ($_GET['action'] ?? 'index') { case "new": - ?> -
    -
    -

    Nueva invitación de usuario

    -
    -
    -
    -
    - - - Formato: 123456-ABCDEF -
    -
    - - -
    - -
    +?> +
    +
    +

    Nueva invitación de usuario

    + +
    +
    +
    + + + Formato: 123456-ABCDEF
    - +
    + + +
    + +
    -
    - +
    +
    + -
    -
    -

    Invitaciones de usuarios

    - Desde aquí puedes gestionar las invitaciones de usuarios. - - - - - - - $inv_data) { - echo ""; - echo ""; - echo ""; - echo ""; - } - ?> - -
    Codigo de invitación - + Nuevo -
    " . htmlspecialchars($inv_key) . ""; - echo '
    '; - echo ''; - echo ''; - echo '
    '; - echo "
    -
    -
    + $invitations = db_get_all_invitations(); +?> +
    +
    +

    Invitaciones de usuarios

    + + + + + + + + + + + + + + + + + +
    CódigoActivoUso único+ Nuevo
    +
    + + +
    +
    +
    +
    prepare("UPDATE users SET password_hash = ?, updated_at = datetime('now') WHERE id = ?") + ->execute([password_hash($new_password, PASSWORD_DEFAULT), $row['id']]); - if (empty($new_password)) { - die("La contraseña no puede estar vacía."); - } - - if ($new_password !== $confirm_password) { - die("Las contraseñas no coinciden."); - } - - if (strlen($new_password) < 6) { - die("La contraseña debe tener al menos 6 caracteres."); - } - - $userfile = "/DATA/Usuarios/$username.json"; - if (!file_exists($userfile)) { - die("Usuario no encontrado."); - } - - $userdata = json_decode(file_get_contents($userfile), true); - $userdata['password_hash'] = password_hash($new_password, PASSWORD_DEFAULT); - - file_put_contents($userfile, json_encode($userdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); - - header("Location: users.php?action=edit&user=" . urlencode($username) . "&_result=" . urlencode("Contraseña restablecida correctamente a las " . date("H:i:s") . " (hora servidor).")); - exit; - break; + header("Location: users.php?action=edit&user=" . urlencode($username) . "&_result=" . urlencode("Contraseña restablecida correctamente a las " . date("H:i:s") . " (hora servidor).")); + exit; + break; } require_once "_incl/pre-body.php"; - $username = safe_username($_GET['user'] ?? ''); if (empty($username)) { - die("Usuario no especificado."); + die("Usuario no especificado."); } - -$userfile = "/DATA/Usuarios/$username.json"; -if (!file_exists($userfile)) { - die("Usuario no encontrado."); +$row = db_get_user($username); +if (!$row) { + die("Usuario no encontrado."); } - -$userdata = json_decode(file_get_contents($userfile), true); ?> -
    -

    Restablecer Contraseña:

    - +

    Restablecer Contraseña:

    Mínimo 6 caracteres
    -
    - - - + - Cancelar + Cancelar
    - diff --git a/public_html/sysadmin/users.php b/public_html/sysadmin/users.php index 5ab2696..3aa49e5 100644 --- a/public_html/sysadmin/users.php +++ b/public_html/sysadmin/users.php @@ -1,89 +1,54 @@ $_POST['display_name'] ?? '', - 'email' => $_POST['email'] ?? '', - 'permissions' => $permissions, - 'entreaulas' => [ - 'centro' => safe_centro_id($_POST['centro'] ?? ''), - 'role' => $_POST['role'] ?? '', - 'aulas' => $aulas - ] - ]; - // Merge old and new data to preserve any other fields, like password hashes or custom metadata. - $userdata = array_merge($userdata_old, $userdata_new); - $user_dir = rtrim(USERS_DIR, '/'); - $user_file = get_user_file_path($username); - if (!is_dir($user_dir) || !is_writable($user_dir)) { - die("No se puede guardar el usuario: directorio de datos no disponible."); - } - $json_data = json_encode($userdata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); - if ($json_data === false) { - die("No se puede guardar el usuario: error al codificar los datos."); - } - $tmp_file = tempnam($user_dir, 'user_'); - if ($tmp_file === false) { - die("No se puede guardar el usuario: no se pudo crear un archivo temporal."); - } - $bytes_written = file_put_contents($tmp_file, $json_data, LOCK_EX); - if ($bytes_written === false) { - @unlink($tmp_file); - die("No se puede guardar el usuario: error al escribir en el disco."); - } - if (!rename($tmp_file, $user_file)) { - @unlink($tmp_file); - die("No se puede guardar el usuario: no se pudo finalizar la grabación del archivo."); - } - header("Location: ?action=edit&user=" . urlencode($username) . "&_result=" . urlencode("Cambios guardados correctamente a las ".date("H:i:s")." (hora servidor).")); - exit; - break; + db_upsert_user([ + 'username' => $username, + 'display_name' => $_POST['display_name'] ?? '', + 'email' => $_POST['email'] ?? '', + 'permissions' => $permissions, + 'entreaulas' => [ + 'centro' => safe_centro_id($_POST['centro'] ?? ''), + 'role' => $_POST['role'] ?? '', + 'aulas' => $aulas, + ], + ]); + header("Location: ?action=edit&user=" . urlencode($username) . "&_result=" . urlencode("Cambios guardados correctamente a las " . date("H:i:s") . " (hora servidor).")); + exit; + break; } switch ($_GET['action'] ?? '') { - case 'add': - require_once "_incl/pre-body.php"; + case 'add': + require_once "_incl/pre-body.php"; + $all_centros = db_get_centro_ids(); ?>
    @@ -104,70 +69,52 @@ switch ($_GET['action'] ?? '') { Permisos:
    -

    - +

    +

    -
    +
    - +
    -

    - +

    +

    -
    +
    - +
    - +
    - +
    -

    - +

    +

    -
    +
    - +
    - +
    @@ -183,13 +130,9 @@ switch ($_GET['action'] ?? '') {
    @@ -205,112 +148,91 @@ switch ($_GET['action'] ?? '') {
    -

    Editar Usuario:

    +

    Editar Usuario:

    - +
    - +
    Permisos:
    -

    - +

    +

    -
    +
    - > - + > +
    -

    - +

    +

    -
    +
    - > - + > +
    - > - + > +
    - > - + > +
    -

    - +

    +

    -
    +
    - > - + > +
    - > - + > +
    - +
    @@ -320,104 +242,81 @@ switch ($_GET['action'] ?? '') {

    - '; - echo ''; - echo ''; - echo '
    '; - } - ?> + $aula_data): ?> +
    + > + +
    +

    Cambiar contraseña

    -

    Para cambiar la contraseña de este usuario, utiliza la herramienta de restablecimiento de contraseñas disponible en el siguiente enlace:

    - Restablecer Contraseña + Restablecer Contraseña
    - -
    -
    -

    Gestión de Usuarios

    -

    Desde esta sección puedes gestionar los usuarios del sistema. Puedes agregar, editar o eliminar usuarios según sea necesario.

    - - - - - - - - - - - "; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - } - ?> - -
    UsuarioNombreCorreo - + Nuevo -
    " . htmlspecialchars($username) . "" . htmlspecialchars($userdata['display_name'] ?? 'N/A') . "" . htmlspecialchars($userdata['email'] ?? 'N/A') . ""; - echo 'Editar '; - echo 'Eliminar'; - echo "
    -
    -
    +
    +
    +

    Gestión de Usuarios

    +

    Desde esta sección puedes gestionar los usuarios del sistema.

    + + + + + + + + + + + + + + + + + + + +
    UsuarioNombreCorreo+ Nuevo
    + Editar +
    +
    +
    + \ No newline at end of file From 6aaee59b3d6341ab2f9bc02caaea31dff980b1f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 22:02:32 +0000 Subject: [PATCH 5/7] fix: address code review feedback (DB filename, migration query, error handling) Co-authored-by: naielv <109038805+naielv@users.noreply.github.com> --- public_html/_incl/db.php | 4 ++-- public_html/_incl/migrations/002_import_json.php | 5 +++-- public_html/sysadmin/aularios.php | 7 +++++-- public_html/sysadmin/centros.php | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/public_html/_incl/db.php b/public_html/_incl/db.php index 5980588..ce53f17 100644 --- a/public_html/_incl/db.php +++ b/public_html/_incl/db.php @@ -4,12 +4,12 @@ * * Provides a PDO SQLite connection and a lightweight migration runner. * All application data previously stored as JSON files under /DATA is now - * persisted in /DATA/axia4.db. + * persisted in /DATA/axia4.sqlite. * * Usage: db() → returns the shared PDO instance (auto-migrates on first call). */ -define('DB_PATH', '/DATA/axia4.db'); +define('DB_PATH', '/DATA/axia4.sqlite'); define('MIGRATIONS_DIR', __DIR__ . '/migrations'); // ── Connection ──────────────────────────────────────────────────────────────── diff --git a/public_html/_incl/migrations/002_import_json.php b/public_html/_incl/migrations/002_import_json.php index cbc5e9c..869c674 100644 --- a/public_html/_incl/migrations/002_import_json.php +++ b/public_html/_incl/migrations/002_import_json.php @@ -63,8 +63,9 @@ if (is_dir($users_dir)) { $user_id = (int) $db->lastInsertId(); if ($user_id === 0) { // Already existed – look it up - $row = $db->prepare("SELECT id FROM users WHERE username = ?")->execute([$username]); - $user_id = (int) $db->query("SELECT id FROM users WHERE username = " . $db->quote($username))->fetchColumn(); + $stmt2 = $db->prepare("SELECT id FROM users WHERE username = ?"); + $stmt2->execute([$username]); + $user_id = (int) $stmt2->fetchColumn(); } // Entreaulas centro assignment diff --git a/public_html/sysadmin/aularios.php b/public_html/sysadmin/aularios.php index 1a1651b..434e717 100644 --- a/public_html/sysadmin/aularios.php +++ b/public_html/sysadmin/aularios.php @@ -72,8 +72,11 @@ switch ($form_action) { Sf($_POST["name"] ?? ""), Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"), ]); - // Create Alumnos directory for photo-based features - @mkdir("/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id/Proyectos/", 0755, true); + // Create Proyectos directory for project file storage + $proyectos_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id/Proyectos/"; + if (!is_dir($proyectos_dir)) { + mkdir($proyectos_dir, 0755, true); + } header("Location: ?action=index"); exit(); break; diff --git a/public_html/sysadmin/centros.php b/public_html/sysadmin/centros.php index 2aa6be5..e4de35f 100644 --- a/public_html/sysadmin/centros.php +++ b/public_html/sysadmin/centros.php @@ -32,8 +32,8 @@ switch ($form_action) { db()->prepare("INSERT INTO centros (centro_id) VALUES (?)")->execute([$centro_id]); // Keep filesystem directory for activity photos (Panel/Actividades) $centro_path = "/DATA/entreaulas/Centros/$centro_id"; - if (!is_dir($centro_path)) { - mkdir($centro_path, 0755, true); + if (!is_dir($centro_path) && !mkdir($centro_path, 0755, true) && !is_dir($centro_path)) { + error_log("centros.php: failed to create directory $centro_path"); } header("Location: ?action=index"); exit(); From a8936e55a23b5e52877314fd48d83376e570b75d Mon Sep 17 00:00:00 2001 From: Naiel <109038805+naielv@users.noreply.github.com> Date: Sat, 7 Mar 2026 12:30:08 +0000 Subject: [PATCH 6/7] Add organization management functionality and logo image - Implemented organization creation, editing, and activity management in orgs.php. - Added safe path segment function to sanitize input. - Included file upload handling for activity photos. - Created a new logo image for the application. --- README.md | 6 +- public_html/_incl/db.php | 318 +++++++++++---- .../_incl/migrations/003_organizaciones.sql | 163 ++++++++ public_html/_incl/pre-body.php | 58 ++- public_html/_incl/switch_tenant.php | 26 +- public_html/_incl/tools.auth.php | 8 +- public_html/_incl/tools.security.php | 49 ++- public_html/_install.php | 2 +- public_html/_login.php | 30 +- public_html/account/index.php | 31 +- public_html/aulatek/__menu.php | 4 +- public_html/aulatek/_filefetch.php | 17 +- public_html/aulatek/_incl/auth_redir.php | 6 +- public_html/aulatek/_incl/pre-body.php | 6 +- public_html/aulatek/alumnos.php | 14 +- public_html/aulatek/api/README.comedor.md | 20 +- public_html/aulatek/api/comedor.php | 10 +- public_html/aulatek/aulario.php | 14 +- public_html/aulatek/comedor.php | 26 +- public_html/aulatek/diario.php | 10 +- public_html/aulatek/index.php | 9 +- public_html/aulatek/paneldiario.php | 60 +-- public_html/aulatek/pdf_secure_viewer.php | 2 +- public_html/aulatek/proyectos.php | 50 +-- public_html/aulatek/supercafe.php | 19 +- public_html/aulatek/supercafe_edit.php | 371 +++++++++++++++--- public_html/entreaulas/index.php | 11 +- public_html/index.php | 12 +- .../{logo-aularios.png => logo-aulatek.png} | Bin public_html/sysadmin/__menu.php | 7 + public_html/sysadmin/aularios.php | 32 +- public_html/sysadmin/index.php | 6 +- .../sysadmin/{centros.php => orgs.php} | 132 ++++--- public_html/sysadmin/users.php | 269 +++++++++---- 34 files changed, 1292 insertions(+), 506 deletions(-) create mode 100644 public_html/_incl/migrations/003_organizaciones.sql rename public_html/static/{logo-aularios.png => logo-aulatek.png} (100%) rename public_html/sysadmin/{centros.php => orgs.php} (56%) diff --git a/README.md b/README.md index 3dccc19..bee20d3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Axia4 -Axia4 is a unified platform for EuskadiTech and Sketaria, providing various services including EntreAulas (connected classroom management system). +Axia4 is a unified platform for EuskadiTech and Sketaria, providing various services including AulaTek (connected classroom management system). ## Quick Start with Docker @@ -13,7 +13,7 @@ cd Axia4 # 2. Create the data directory structure mkdir -p DATA/entreaulas/Usuarios -mkdir -p DATA/entreaulas/Centros +mkdir -p DATA/entreaulas/Organizaciones # 3. Start the application docker compose up -d @@ -29,7 +29,7 @@ docker compose up -d ## Features -- **EntreAulas**: Management system for connected classrooms +- **AulaTek**: Management system for connected classrooms - **Aularios**: Centralized access to classroom resources - Integration with multiple external services diff --git a/public_html/_incl/db.php b/public_html/_incl/db.php index ce53f17..be53e3a 100644 --- a/public_html/_incl/db.php +++ b/public_html/_incl/db.php @@ -126,39 +126,65 @@ function db_get_all_users(): array /** * Build the auth_data session array from a DB user row. * Preserves the same format existing code expects: - * auth_data.permissions, auth_data.entreaulas.centro, .role, .aulas, .centros + * auth_data.permissions, auth_data.active_organizations auth_data.organizations. */ function db_build_auth_data(array $row): array { $permissions = json_decode($row['permissions'] ?? '[]', true) ?: []; $meta = json_decode($row['meta'] ?? '{}', true) ?: []; + $ea = [ + 'organization' => '', + 'organizations' => [], + 'role' => '', + 'aulas' => [], + 'organizations_data' => [], + ]; - // Fetch all centro assignments for this user + // Fetch all organization assignments for this user $stmt = db()->prepare( - 'SELECT centro_id, role, aulas - FROM user_centros + 'SELECT org_id, role, ea_aulas + FROM user_orgs WHERE user_id = ? - ORDER BY centro_id' + ORDER BY org_id' ); $stmt->execute([$row['id']]); - $centro_rows = $stmt->fetchAll(); - - $ea = ['centro' => '', 'centros' => [], 'role' => '', 'aulas' => []]; - if (!empty($centro_rows)) { - $first = $centro_rows[0]; - $ea['centro'] = $first['centro_id']; // legacy compat + $org_rows = $stmt->fetchAll(); + $orgs = []; + if (!empty($org_rows)) { + $first = $org_rows[0]; + foreach ($org_rows as $r) { + $orgs[] = $r['org_id']; + } + $ea['organization'] = $first['org_id']; $ea['role'] = $first['role']; - $ea['aulas'] = json_decode($first['aulas'] ?? '[]', true) ?: []; - $ea['centros'] = array_column($centro_rows, 'centro_id'); - $ea['centros_data'] = $centro_rows; + $ea['aulas'] = json_decode($first['ea_aulas'] ?? '[]', true) ?: []; + $ea['organizations'] = $orgs; + $ea['organizations_data'] = $org_rows; } + $active_org = $ea['organization'] ?? ''; + $aulatek = [ + 'organizacion' => $active_org, + 'organizaciones' => $orgs, + 'organization' => $active_org, + 'organizations' => $orgs, + 'centro' => $active_org, + 'centros' => $orgs, + 'role' => $ea['role'] ?? '', + 'aulas' => $ea['aulas'] ?? [], + ]; + return array_merge($meta, [ 'display_name' => $row['display_name'], 'email' => $row['email'], 'password_hash' => $row['password_hash'], 'permissions' => $permissions, - 'entreaulas' => $ea, + 'orgs' => $orgs, + 'organizations' => $orgs, + 'active_organization' => $active_org, + 'active_organizations' => $ea, + 'aulatek' => $aulatek, + 'entreaulas' => $aulatek, 'google_auth' => (bool) $row['google_auth'], ]); } @@ -166,7 +192,7 @@ function db_build_auth_data(array $row): array /** * Create or update a user. * $data keys: username, display_name, email, password_hash, permissions[], - * google_auth, entreaulas{centro,centros[],role,aulas[]}, + any extra meta. + * google_auth, entreaulas{organizacion,organizaciones[],role,aulas[]}, + any extra meta. * Returns the user ID. */ function db_upsert_user(array $data): int @@ -180,7 +206,9 @@ function db_upsert_user(array $data): int $permissions = json_encode($data['permissions'] ?? []); $meta_skip = ['username', 'display_name', 'email', 'password_hash', - 'permissions', 'entreaulas', 'google_auth']; + 'permissions', 'entreaulas', 'google_auth', + 'orgs', 'organizations', 'organization', 'organizacion', + 'role', 'aulas']; $meta = []; foreach ($data as $k => $v) { if (!in_array($k, $meta_skip, true)) { @@ -228,53 +256,119 @@ function db_upsert_user(array $data): int $user_id = (int) $pdo->lastInsertId(); } - // Update centro assignments when entreaulas data is provided - if (array_key_exists('entreaulas', $data)) { + // Update organization assignments if tenant data is provided. + $has_org_payload = array_key_exists('entreaulas', $data) + || array_key_exists('orgs', $data) + || array_key_exists('organizations', $data) + || array_key_exists('organization', $data) + || array_key_exists('organizacion', $data); + + if ($has_org_payload) { $ea = $data['entreaulas'] ?? []; - $pdo->prepare('DELETE FROM user_centros WHERE user_id = ?')->execute([$user_id]); - // Support both legacy single centro and new multi-centro - $centros = []; - if (!empty($ea['centros']) && is_array($ea['centros'])) { - $centros = $ea['centros']; - } elseif (!empty($ea['centro'])) { - $centros = [$ea['centro']]; + $organizations = []; + $candidate_lists = [ + $data['organizations'] ?? null, + $data['orgs'] ?? null, + $ea['organizaciones'] ?? null, + $ea['organizations'] ?? null, + $ea['centros'] ?? null, + ]; + foreach ($candidate_lists as $list) { + if (is_array($list) && !empty($list)) { + $organizations = $list; + break; + } + } + if (empty($organizations)) { + foreach ([ + $data['organization'] ?? null, + $data['organizacion'] ?? null, + $ea['organizacion'] ?? null, + $ea['organization'] ?? null, + $ea['centro'] ?? null, + ] as $single) { + if (!empty($single)) { + $organizations = [$single]; + break; + } + } } - $role = $ea['role'] ?? ''; - $aulas = json_encode($ea['aulas'] ?? []); - $ins_centro = $pdo->prepare('INSERT OR IGNORE INTO centros (centro_id) VALUES (?)'); - $ins_uc = $pdo->prepare( - 'INSERT OR REPLACE INTO user_centros (user_id, centro_id, role, aulas) VALUES (?, ?, ?, ?)' + $organizations = array_values(array_unique(array_filter(array_map( + static function ($value): string { + return preg_replace('/[^a-zA-Z0-9._-]/', '', (string) $value); + }, + $organizations + )))); + + $role = (string) ($data['role'] ?? $ea['role'] ?? ''); + $aulas_payload = $data['aulas'] ?? $ea['aulas'] ?? []; + if (!is_array($aulas_payload)) { + $aulas_payload = []; + } + $aulas = json_encode($aulas_payload, JSON_UNESCAPED_UNICODE); + + $pdo->prepare('DELETE FROM user_orgs WHERE user_id = ?')->execute([$user_id]); + + $ins_org = $pdo->prepare('INSERT OR IGNORE INTO organizaciones (org_id, org_name) VALUES (?, ?)'); + $ins_uo = $pdo->prepare( + 'INSERT OR REPLACE INTO user_orgs (user_id, org_id, role, ea_aulas) VALUES (?, ?, ?, ?)' ); - foreach ($centros as $cid) { - if ($cid === '') { + foreach ($organizations as $org_id) { + if ($org_id === '') { continue; } - $ins_centro->execute([$cid]); - $ins_uc->execute([$user_id, $cid, $role, $aulas]); + $ins_org->execute([$org_id, $org_id]); + $ins_uo->execute([$user_id, $org_id, $role, $aulas]); } } return $user_id; } -/** Delete a user and their centro assignments. */ +/** Delete a user and their organization assignments. */ function db_delete_user(string $username): void { db()->prepare('DELETE FROM users WHERE username = ?')->execute([strtolower($username)]); } -// ── Centro helpers ──────────────────────────────────────────────────────────── +// ── Organization helpers ───────────────────────────────────────────────────── + +function db_get_organizations(): array +{ + return db()->query('SELECT org_id, org_name FROM organizaciones ORDER BY org_id')->fetchAll(); +} + +function db_get_organization_ids(): array +{ + return db()->query('SELECT org_id FROM organizaciones ORDER BY org_id')->fetchAll(PDO::FETCH_COLUMN); +} + +function db_get_organizaciones(): array +{ + return db_get_organizations(); +} + +function get_organizations(): array +{ + return db_get_organizations(); +} function db_get_centros(): array { - return db()->query('SELECT centro_id, name FROM centros ORDER BY centro_id')->fetchAll(); + $rows = db_get_organizations(); + return array_map(static function (array $row): array { + return [ + 'centro_id' => $row['org_id'], + 'name' => $row['org_name'], + ]; + }, $rows); } function db_get_centro_ids(): array { - return db()->query('SELECT centro_id FROM centros ORDER BY centro_id')->fetchAll(PDO::FETCH_COLUMN); + return db_get_organization_ids(); } // ── Aulario helpers ─────────────────────────────────────────────────────────── @@ -283,7 +377,7 @@ function db_get_centro_ids(): array function db_get_aulario(string $centro_id, string $aulario_id): ?array { $stmt = db()->prepare( - 'SELECT name, icon, extra FROM aularios WHERE centro_id = ? AND aulario_id = ?' + 'SELECT name, icon, extra FROM aularios WHERE org_id = ? AND aulario_id = ?' ); $stmt->execute([$centro_id, $aulario_id]); $row = $stmt->fetch(); @@ -298,7 +392,7 @@ function db_get_aulario(string $centro_id, string $aulario_id): ?array function db_get_aularios(string $centro_id): array { $stmt = db()->prepare( - 'SELECT aulario_id, name, icon, extra FROM aularios WHERE centro_id = ? ORDER BY aulario_id' + 'SELECT aulario_id, name, icon, extra FROM aularios WHERE org_id = ? ORDER BY aulario_id' ); $stmt->execute([$centro_id]); $result = []; @@ -316,7 +410,7 @@ function db_get_aularios(string $centro_id): array function db_get_supercafe_menu(string $centro_id): array { - $stmt = db()->prepare('SELECT data FROM supercafe_menu WHERE centro_id = ?'); + $stmt = db()->prepare('SELECT data FROM supercafe_menu WHERE org_id = ?'); $stmt->execute([$centro_id]); $row = $stmt->fetch(); if ($row === false) { @@ -327,7 +421,7 @@ function db_get_supercafe_menu(string $centro_id): array function db_set_supercafe_menu(string $centro_id, array $menu): void { - db()->prepare('INSERT OR REPLACE INTO supercafe_menu (centro_id, data, updated_at) VALUES (?, ?, datetime(\'now\'))') + db()->prepare('INSERT OR REPLACE INTO supercafe_menu (org_id, data, updated_at) VALUES (?, ?, datetime(\'now\'))') ->execute([$centro_id, json_encode($menu, JSON_UNESCAPED_UNICODE)]); } @@ -335,7 +429,7 @@ function db_set_supercafe_menu(string $centro_id, array $menu): void function db_get_supercafe_orders(string $centro_id): array { $stmt = db()->prepare( - 'SELECT * FROM supercafe_orders WHERE centro_id = ? ORDER BY created_at DESC' + 'SELECT * FROM supercafe_orders WHERE org_id = ? ORDER BY created_at DESC' ); $stmt->execute([$centro_id]); return $stmt->fetchAll(); @@ -345,7 +439,7 @@ function db_get_supercafe_orders(string $centro_id): array function db_get_supercafe_order(string $centro_id, string $order_ref): ?array { $stmt = db()->prepare( - 'SELECT * FROM supercafe_orders WHERE centro_id = ? AND order_ref = ?' + 'SELECT * FROM supercafe_orders WHERE org_id = ? AND order_ref = ?' ); $stmt->execute([$centro_id, $order_ref]); $row = $stmt->fetch(); @@ -363,9 +457,9 @@ function db_upsert_supercafe_order( string $estado ): void { db()->prepare( - 'INSERT INTO supercafe_orders (centro_id, order_ref, fecha, persona, comanda, notas, estado) + 'INSERT INTO supercafe_orders (org_id, order_ref, fecha, persona, comanda, notas, estado) VALUES (?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(centro_id, order_ref) DO UPDATE SET + ON CONFLICT(org_id, order_ref) DO UPDATE SET fecha = excluded.fecha, persona = excluded.persona, comanda = excluded.comanda, @@ -378,7 +472,7 @@ function db_upsert_supercafe_order( function db_next_supercafe_ref(string $centro_id): string { $stmt = db()->prepare( - "SELECT order_ref FROM supercafe_orders WHERE centro_id = ? ORDER BY id DESC LIMIT 1" + "SELECT order_ref FROM supercafe_orders WHERE org_id = ? ORDER BY id DESC LIMIT 1" ); $stmt->execute([$centro_id]); $last = $stmt->fetchColumn(); @@ -393,7 +487,7 @@ function db_next_supercafe_ref(string $centro_id): string function db_supercafe_count_debts(string $centro_id, string $persona_key): int { $stmt = db()->prepare( - "SELECT COUNT(*) FROM supercafe_orders WHERE centro_id = ? AND persona = ? AND estado = 'Deuda'" + "SELECT COUNT(*) FROM supercafe_orders WHERE org_id = ? AND persona = ? AND estado = 'Deuda'" ); $stmt->execute([$centro_id, $persona_key]); return (int) $stmt->fetchColumn(); @@ -404,7 +498,7 @@ function db_supercafe_count_debts(string $centro_id, string $persona_key): int function db_get_comedor_menu_types(string $centro_id, string $aulario_id): array { $stmt = db()->prepare( - 'SELECT data FROM comedor_menu_types WHERE centro_id = ? AND aulario_id = ?' + 'SELECT data FROM comedor_menu_types WHERE org_id = ? AND aulario_id = ?' ); $stmt->execute([$centro_id, $aulario_id]); $row = $stmt->fetch(); @@ -417,14 +511,14 @@ function db_get_comedor_menu_types(string $centro_id, string $aulario_id): array function db_set_comedor_menu_types(string $centro_id, string $aulario_id, array $types): void { db()->prepare( - 'INSERT OR REPLACE INTO comedor_menu_types (centro_id, aulario_id, data) VALUES (?, ?, ?)' + 'INSERT OR REPLACE INTO comedor_menu_types (org_id, aulario_id, data) VALUES (?, ?, ?)' )->execute([$centro_id, $aulario_id, json_encode($types, JSON_UNESCAPED_UNICODE)]); } function db_get_comedor_entry(string $centro_id, string $aulario_id, string $ym, string $day): array { $stmt = db()->prepare( - 'SELECT data FROM comedor_entries WHERE centro_id = ? AND aulario_id = ? AND year_month = ? AND day = ?' + 'SELECT data FROM comedor_entries WHERE org_id = ? AND aulario_id = ? AND year_month = ? AND day = ?' ); $stmt->execute([$centro_id, $aulario_id, $ym, $day]); $row = $stmt->fetch(); @@ -437,7 +531,7 @@ function db_get_comedor_entry(string $centro_id, string $aulario_id, string $ym, function db_set_comedor_entry(string $centro_id, string $aulario_id, string $ym, string $day, array $data): void { db()->prepare( - 'INSERT OR REPLACE INTO comedor_entries (centro_id, aulario_id, year_month, day, data) VALUES (?, ?, ?, ?, ?)' + 'INSERT OR REPLACE INTO comedor_entries (org_id, aulario_id, year_month, day, data) VALUES (?, ?, ?, ?, ?)' )->execute([$centro_id, $aulario_id, $ym, $day, json_encode($data, JSON_UNESCAPED_UNICODE)]); } @@ -446,7 +540,7 @@ function db_set_comedor_entry(string $centro_id, string $aulario_id, string $ym, function db_get_diario_entry(string $centro_id, string $aulario_id, string $entry_date): array { $stmt = db()->prepare( - 'SELECT data FROM diario_entries WHERE centro_id = ? AND aulario_id = ? AND entry_date = ?' + 'SELECT data FROM diario_entries WHERE org_id = ? AND aulario_id = ? AND entry_date = ?' ); $stmt->execute([$centro_id, $aulario_id, $entry_date]); $row = $stmt->fetch(); @@ -459,7 +553,7 @@ function db_get_diario_entry(string $centro_id, string $aulario_id, string $entr function db_set_diario_entry(string $centro_id, string $aulario_id, string $entry_date, array $data): void { db()->prepare( - 'INSERT OR REPLACE INTO diario_entries (centro_id, aulario_id, entry_date, data) VALUES (?, ?, ?, ?)' + 'INSERT OR REPLACE INTO diario_entries (org_id, aulario_id, entry_date, data) VALUES (?, ?, ?, ?)' )->execute([$centro_id, $aulario_id, $entry_date, json_encode($data, JSON_UNESCAPED_UNICODE)]); } @@ -468,7 +562,7 @@ function db_set_diario_entry(string $centro_id, string $aulario_id, string $entr function db_get_panel_alumno(string $centro_id, string $aulario_id, string $alumno): array { $stmt = db()->prepare( - 'SELECT data FROM panel_alumno WHERE centro_id = ? AND aulario_id = ? AND alumno = ?' + 'SELECT data FROM panel_alumno WHERE org_id = ? AND aulario_id = ? AND alumno = ?' ); $stmt->execute([$centro_id, $aulario_id, $alumno]); $row = $stmt->fetch(); @@ -481,7 +575,7 @@ function db_get_panel_alumno(string $centro_id, string $aulario_id, string $alum function db_set_panel_alumno(string $centro_id, string $aulario_id, string $alumno, array $data): void { db()->prepare( - 'INSERT OR REPLACE INTO panel_alumno (centro_id, aulario_id, alumno, data) VALUES (?, ?, ?, ?)' + 'INSERT OR REPLACE INTO panel_alumno (org_id, aulario_id, alumno, data) VALUES (?, ?, ?, ?)' )->execute([$centro_id, $aulario_id, $alumno, json_encode($data, JSON_UNESCAPED_UNICODE)]); } @@ -559,31 +653,113 @@ function db_set_club_event(string $date_ref, array $data): void // ── Multi-tenant helpers ────────────────────────────────────────────────────── -/** Return all centro IDs the authenticated user belongs to. */ -function get_user_centros(?array $auth_data = null): array +/** Return all organization IDs the authenticated user belongs to. */ +function get_user_organizations(?array $auth_data = null): array { $data = $auth_data ?? $_SESSION['auth_data'] ?? []; - $ea = $data['entreaulas'] ?? []; + $orgs = $data['organizations'] + ?? $data['orgs'] + ?? $data['aulatek']['organizaciones'] + ?? $data['aulatek']['organizations'] + ?? $data['aulatek']['centros'] + ?? $data['entreaulas']['organizaciones'] + ?? $data['entreaulas']['organizations'] + ?? $data['entreaulas']['centros'] + ?? []; - if (!empty($ea['centros']) && is_array($ea['centros'])) { - return array_values($ea['centros']); + if (!empty($orgs) && is_array($orgs)) { + return array_values(array_unique(array_filter($orgs, static function ($value): bool { + return is_string($value) && $value !== ''; + }))); } - if (!empty($ea['centro'])) { - return [$ea['centro']]; + if (!empty($orgs)) { + return [(string) $orgs]; } + + foreach ([ + $data['active_organization'] ?? null, + $data['aulatek']['organizacion'] ?? null, + $data['aulatek']['organization'] ?? null, + $data['aulatek']['centro'] ?? null, + $data['entreaulas']['organizacion'] ?? null, + $data['entreaulas']['organization'] ?? null, + $data['entreaulas']['centro'] ?? null, + ] as $single) { + if (is_string($single) && $single !== '') { + return [$single]; + } + } + return []; } -/** Ensure $_SESSION['active_centro'] is set to a valid centro. */ -function init_active_centro(?array $auth_data = null): void +/** Spanish alias used by pre-body.php menu rendering. */ +function get_user_organizaciones(?array $auth_data = null): array { - $centros = get_user_centros($auth_data); - if (empty($centros)) { + $org_ids = get_user_organizations($auth_data); + if (empty($org_ids)) { + return []; + } + $name_by_id = []; + foreach (db_get_organizations() as $org_row) { + $name_by_id[$org_row['org_id']] = $org_row['org_name']; + } + + $result = []; + foreach ($org_ids as $org_id) { + $result[$org_id] = $name_by_id[$org_id] ?? $org_id; + } + return $result; +} + +function get_user_centros(?array $auth_data = null): array +{ + return get_user_organizations($auth_data); +} + +/** Ensure active organization session keys are set and mirrored for legacy code. */ +function init_active_org(?array $auth_data = null): void +{ + $organizations = get_user_organizations($auth_data); + if (empty($organizations)) { + $_SESSION['active_organization'] = null; + $_SESSION['active_organizacion'] = null; $_SESSION['active_centro'] = null; return; } - if (!empty($_SESSION['active_centro']) && in_array($_SESSION['active_centro'], $centros, true)) { - return; + + $current = $_SESSION['active_organization'] + ?? $_SESSION['active_organizacion'] + ?? $_SESSION['active_centro'] + ?? null; + + if (!is_string($current) || !in_array($current, $organizations, true)) { + $current = $organizations[0]; } - $_SESSION['active_centro'] = $centros[0]; + + $_SESSION['active_organization'] = $current; + $_SESSION['active_organizacion'] = $current; + $_SESSION['active_centro'] = $current; + + if (!isset($_SESSION['auth_data']) || !is_array($_SESSION['auth_data'])) { + $_SESSION['auth_data'] = []; + } + $_SESSION['auth_data']['active_organization'] = $current; + if (!isset($_SESSION['auth_data']['aulatek']) || !is_array($_SESSION['auth_data']['aulatek'])) { + $_SESSION['auth_data']['aulatek'] = []; + } + $_SESSION['auth_data']['aulatek']['organizacion'] = $current; + $_SESSION['auth_data']['aulatek']['organization'] = $current; + $_SESSION['auth_data']['aulatek']['centro'] = $current; + if (!isset($_SESSION['auth_data']['entreaulas']) || !is_array($_SESSION['auth_data']['entreaulas'])) { + $_SESSION['auth_data']['entreaulas'] = []; + } + $_SESSION['auth_data']['entreaulas']['organizacion'] = $current; + $_SESSION['auth_data']['entreaulas']['organization'] = $current; + $_SESSION['auth_data']['entreaulas']['centro'] = $current; +} + +function init_active_centro(?array $auth_data = null): void +{ + init_active_org($auth_data); } diff --git a/public_html/_incl/migrations/003_organizaciones.sql b/public_html/_incl/migrations/003_organizaciones.sql new file mode 100644 index 0000000..a526e72 --- /dev/null +++ b/public_html/_incl/migrations/003_organizaciones.sql @@ -0,0 +1,163 @@ +-- filepath: /workspaces/Axia4/public_html/_incl/migrations/003_organizaciones.sql +-- Axia4 Migration 003: Rename centros to organizaciones +-- Migrates the centros table to organizaciones with org_id and org_name columns. + +PRAGMA journal_mode = WAL; +PRAGMA foreign_keys = ON; + +-- ── Create new organizaciones table ────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS organizaciones ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT UNIQUE NOT NULL, + org_name TEXT NOT NULL DEFAULT '', + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +-- ── Migrate data from centros to organizaciones ────────────────────────────── +INSERT INTO organizaciones (org_id, org_name, created_at) +SELECT centro_id, COALESCE(name, centro_id), created_at +FROM centros +WHERE NOT EXISTS ( + SELECT 1 FROM organizaciones WHERE org_id = centros.centro_id +); + +-- ── Update foreign key references in user_centros ────────────────────────────── +-- user_centros.centro_id → user_centros.org_id (rename column if needed via recreation) +-- For SQLite, we need to recreate the table due to FK constraint changes + +CREATE TABLE user_centros_new ( + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + role TEXT NOT NULL DEFAULT '', + ea_aulas TEXT NOT NULL DEFAULT '[]', + PRIMARY KEY (user_id, org_id) +); + +INSERT INTO user_centros_new (user_id, org_id, role, ea_aulas) +SELECT user_id, centro_id, role, aulas FROM user_centros; + +DROP TABLE user_centros; +ALTER TABLE user_centros_new RENAME TO user_orgs; + +-- ── Update foreign key references in aularios ────────────────────────────────── +CREATE TABLE aularios_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + aulario_id TEXT NOT NULL, + name TEXT NOT NULL DEFAULT '', + icon TEXT NOT NULL DEFAULT '', + extra TEXT NOT NULL DEFAULT '{}', + UNIQUE (org_id, aulario_id) +); + +INSERT INTO aularios_new (id, org_id, aulario_id, name, icon, extra) +SELECT id, centro_id, aulario_id, name, icon, extra FROM aularios; + +DROP TABLE aularios; +ALTER TABLE aularios_new RENAME TO aularios; + +-- ── Update foreign key references in remaining tables ────────────────────────── +-- supercafe_menu +CREATE TABLE supercafe_menu_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + data TEXT NOT NULL DEFAULT '{}', + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + UNIQUE (org_id) +); + +INSERT INTO supercafe_menu_new (id, org_id, data, updated_at) +SELECT id, centro_id, data, updated_at FROM supercafe_menu; + +DROP TABLE supercafe_menu; +ALTER TABLE supercafe_menu_new RENAME TO supercafe_menu; + +-- supercafe_orders +CREATE TABLE supercafe_orders_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + order_ref TEXT NOT NULL, + fecha TEXT NOT NULL, + persona TEXT NOT NULL, + comanda TEXT NOT NULL DEFAULT '', + notas TEXT NOT NULL DEFAULT '', + estado TEXT NOT NULL DEFAULT 'Pedido', + created_at TEXT NOT NULL DEFAULT (datetime('now')), + UNIQUE (org_id, order_ref) +); + +INSERT INTO supercafe_orders_new (id, org_id, order_ref, fecha, persona, comanda, notas, estado, created_at) +SELECT id, centro_id, order_ref, fecha, persona, comanda, notas, estado, created_at FROM supercafe_orders; + +DROP TABLE supercafe_orders; +ALTER TABLE supercafe_orders_new RENAME TO supercafe_orders; + +-- comedor_menu_types +CREATE TABLE comedor_menu_types_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + aulario_id TEXT NOT NULL, + data TEXT NOT NULL DEFAULT '[]', + UNIQUE (org_id, aulario_id) +); + +INSERT INTO comedor_menu_types_new (id, org_id, aulario_id, data) +SELECT id, centro_id, aulario_id, data FROM comedor_menu_types; + +DROP TABLE comedor_menu_types; +ALTER TABLE comedor_menu_types_new RENAME TO comedor_menu_types; + +-- comedor_entries +CREATE TABLE comedor_entries_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + aulario_id TEXT NOT NULL, + year_month TEXT NOT NULL, + day TEXT NOT NULL, + data TEXT NOT NULL DEFAULT '{}', + UNIQUE (org_id, aulario_id, year_month, day) +); + +INSERT INTO comedor_entries_new (id, org_id, aulario_id, year_month, day, data) +SELECT id, centro_id, aulario_id, year_month, day, data FROM comedor_entries; + +DROP TABLE comedor_entries; +ALTER TABLE comedor_entries_new RENAME TO comedor_entries; + +-- diario_entries +CREATE TABLE diario_entries_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + aulario_id TEXT NOT NULL, + entry_date TEXT NOT NULL, + data TEXT NOT NULL DEFAULT '{}', + UNIQUE (org_id, aulario_id, entry_date) +); + +INSERT INTO diario_entries_new (id, org_id, aulario_id, entry_date, data) +SELECT id, centro_id, aulario_id, entry_date, data FROM diario_entries; + +DROP TABLE diario_entries; +ALTER TABLE diario_entries_new RENAME TO diario_entries; + +-- panel_alumno +CREATE TABLE panel_alumno_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + org_id TEXT NOT NULL REFERENCES organizaciones(org_id) ON DELETE CASCADE, + aulario_id TEXT NOT NULL, + alumno TEXT NOT NULL, + data TEXT NOT NULL DEFAULT '{}', + UNIQUE (org_id, aulario_id, alumno) +); + +INSERT INTO panel_alumno_new (id, org_id, aulario_id, alumno, data) +SELECT id, centro_id, aulario_id, alumno, data FROM panel_alumno; + +DROP TABLE panel_alumno; +ALTER TABLE panel_alumno_new RENAME TO panel_alumno; + +-- ── Drop old centros table ───────────────────────────────────────────────────── +DROP TABLE IF EXISTS centros; + +-- ── Verify migration ─────────────────────────────────────────────────────────── +-- SELECT COUNT(*) as total_organizaciones FROM organizaciones; \ No newline at end of file diff --git a/public_html/_incl/pre-body.php b/public_html/_incl/pre-body.php index 0c4cc49..9f83c1b 100755 --- a/public_html/_incl/pre-body.php +++ b/public_html/_incl/pre-body.php @@ -27,11 +27,13 @@ if (!empty($displayName)) { $initials = mb_strtoupper($first . $last); } -// Tenant (centro) management -$userCentros = get_user_centros($_SESSION["auth_data"] ?? []); -$activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ''); - +// Tenant (organización) management +$userOrganizaciones = get_user_organizaciones($_SESSION["auth_data"] ?? []); +$activeOrganizacionId = $_SESSION['active_organizacion'] + ?? ($_SESSION["auth_data"]["aulatek"]["organizacion"] ?? ($_SESSION["auth_data"]["entreaulas"]["organizacion"] ?? '')); +$activeOrganizacionName = $userOrganizaciones[$activeOrganizacionId] ?? ''; +?> @@ -170,6 +172,7 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula font-weight: 400; white-space: nowrap; transition: background 0.15s ease; + border: 1px solid grey; } .sidebar-link:hover { background: var(--gw-hover); color: var(--gw-text-primary); text-decoration: none; } .sidebar-link.active, .sidebar-link:focus-visible { background: var(--gw-blue-light); color: var(--gw-blue); font-weight: 500; } @@ -505,9 +508,9 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula Club - + - EntreAulas + AulaTek @@ -530,22 +533,22 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula
    - -
    + +
    Organización activa
    -
    @@ -569,22 +572,11 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula
    diff --git a/public_html/_incl/switch_tenant.php b/public_html/_incl/switch_tenant.php index 65e6891..d0cb8b4 100644 --- a/public_html/_incl/switch_tenant.php +++ b/public_html/_incl/switch_tenant.php @@ -1,8 +1,8 @@ $admin_user, 'display_name' => 'Administrador', 'email' => "$admin_user@nomail.arpa", - 'permissions' => ['*', 'sysadmin:access', 'entreaulas:access'], + 'permissions' => ['*', 'sysadmin:access', 'aulatek:access'], 'password_hash' => password_hash($admin_password, PASSWORD_DEFAULT), ]); db_set_config('installed', '1'); diff --git a/public_html/_login.php b/public_html/_login.php index 98d36e3..853a30e 100755 --- a/public_html/_login.php +++ b/public_html/_login.php @@ -7,33 +7,21 @@ if (!isset($AuthConfig)) { } $DOMAIN = $_SERVER["HTTP_X_FORWARDED_HOST"] ?? $_SERVER["HTTP_HOST"]; -/** - * Return a safe redirect URL: only allow relative paths starting with a single slash. - * Falls back to "/" for any external, protocol-relative, or otherwise unsafe URLs. - */ -function safe_redir($url) { - $url = (string)$url; - // Must start with a single "/" but not "//" (protocol-relative) - if (preg_match('#^/[^/]#', $url) || $url === '/') { - // Strip newlines to prevent header injection - return preg_replace('/[\r\n]/', '', $url); - } - return '/'; -} +// safe_redir() is provided by _incl/tools.security.php. -if ($_GET["reload_user"] == "1") { +if (($_GET["reload_user"] ?? "") === "1") { $row = db_get_user($_SESSION["auth_user"] ?? ""); if (!$row) { header("Location: /"); die(); } $_SESSION['auth_data'] = db_build_auth_data($row); - init_active_centro($_SESSION['auth_data']); + init_active_org($_SESSION['auth_data']); $redir = safe_redir($_GET["redir"] ?? "/"); header("Location: $redir"); die(); } -if ($_GET["google_callback"] == "1") { +if (($_GET["google_callback"] ?? "") === "1") { if (!isset($AuthConfig["google_client_id"]) || !isset($AuthConfig["google_client_secret"])) { die("Error: La autenticación de Google no está configurada."); } @@ -110,7 +98,7 @@ if ($_GET["google_callback"] == "1") { $_SESSION['auth_user'] = $username; $_SESSION['auth_data'] = db_build_auth_data($user_row); $_SESSION['auth_ok'] = true; - init_active_centro($_SESSION['auth_data']); + init_active_org($_SESSION['auth_data']); $cookie_options = ["expires" => time() + (86400 * 30), "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"]; setcookie("auth_user", $username, $cookie_options); setcookie("auth_pass_b64", base64_encode($password), $cookie_options); @@ -120,7 +108,7 @@ if ($_GET["google_callback"] == "1") { header("Location: $redir"); die(); } -if ($_GET["google"] == "1") { +if (($_GET["google"] ?? "") === "1") { if (!isset($AuthConfig["google_client_id"]) || !isset($AuthConfig["google_client_secret"])) { die("Error: La autenticación de Google no está configurada."); } @@ -148,7 +136,7 @@ if ($_GET["google"] == "1") { header("Location: " . $request_to); die(); } -if ($_GET["logout"] == "1") { +if (($_GET["logout"] ?? "") === "1") { $redir = safe_redir($_GET["redir"] ?? "/"); $cookie_options_expired = ["expires" => time() - 3600, "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"]; setcookie("auth_user", "", $cookie_options_expired); @@ -157,7 +145,7 @@ if ($_GET["logout"] == "1") { header("Location: $redir"); die(); } -if ($_GET["clear_session"] == "1") { +if (($_GET["clear_session"] ?? "") === "1") { session_destroy(); $redir = safe_redir($_GET["redir"] ?? "/"); header("Location: $redir"); @@ -174,7 +162,7 @@ if (isset($_POST["user"])) { $_SESSION['auth_user'] = $user; $_SESSION['auth_data'] = db_build_auth_data($row); $_SESSION['auth_ok'] = true; - init_active_centro($_SESSION['auth_data']); + init_active_org($_SESSION['auth_data']); $cookie_options = ["expires" => time() + (86400 * 30), "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"]; setcookie("auth_user", $user, $cookie_options); setcookie("auth_pass_b64", base64_encode($password), $cookie_options); diff --git a/public_html/account/index.php b/public_html/account/index.php index aa9838b..726b237 100644 --- a/public_html/account/index.php +++ b/public_html/account/index.php @@ -9,12 +9,13 @@ $displayName = $authData["display_name"] ?? 'Invitado'; $email = $authData["email"] ?? ''; $permissions = $authData["permissions"] ?? []; -// Tenant / centro management -$userCentros = get_user_centros($authData); -$activeCentro = $_SESSION['active_centro'] ?? ($authData['entreaulas']['centro'] ?? ''); -$aularios = ($activeCentro !== '') ? db_get_aularios($activeCentro) : []; -$userAulas = $authData['entreaulas']['aulas'] ?? []; -$role = $authData['entreaulas']['role'] ?? ''; +// Tenant / organization management +$userOrganizations = get_user_organizations($authData); +$activeOrganization = $_SESSION['active_organization'] + ?? ($authData['aulatek']['organizacion'] ?? ($authData['aulatek']['centro'] ?? ($authData['entreaulas']['organizacion'] ?? ($authData['entreaulas']['centro'] ?? '')))); +$aularios = ($activeOrganization !== '') ? db_get_aularios($activeOrganization) : []; +$userAulas = $authData['aulatek']['aulas'] ?? ($authData['entreaulas']['aulas'] ?? []); +$role = $authData['aulatek']['role'] ?? ($authData['entreaulas']['role'] ?? ''); // Initials for avatar $parts = preg_split('/\s+/', trim($displayName)); @@ -65,19 +66,19 @@ if ($initials === '') {
    - +