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.
This commit is contained in:
Naiel
2026-03-07 12:30:08 +00:00
parent 6aaee59b3d
commit a8936e55a2
34 changed files with 1292 additions and 506 deletions

View File

@@ -1,6 +1,6 @@
# Axia4 # 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 ## Quick Start with Docker
@@ -13,7 +13,7 @@ cd Axia4
# 2. Create the data directory structure # 2. Create the data directory structure
mkdir -p DATA/entreaulas/Usuarios mkdir -p DATA/entreaulas/Usuarios
mkdir -p DATA/entreaulas/Centros mkdir -p DATA/entreaulas/Organizaciones
# 3. Start the application # 3. Start the application
docker compose up -d docker compose up -d
@@ -29,7 +29,7 @@ docker compose up -d
## Features ## Features
- **EntreAulas**: Management system for connected classrooms - **AulaTek**: Management system for connected classrooms
- **Aularios**: Centralized access to classroom resources - **Aularios**: Centralized access to classroom resources
- Integration with multiple external services - Integration with multiple external services

View File

@@ -126,39 +126,65 @@ function db_get_all_users(): array
/** /**
* Build the auth_data session array from a DB user row. * Build the auth_data session array from a DB user row.
* Preserves the same format existing code expects: * 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 function db_build_auth_data(array $row): array
{ {
$permissions = json_decode($row['permissions'] ?? '[]', true) ?: []; $permissions = json_decode($row['permissions'] ?? '[]', true) ?: [];
$meta = json_decode($row['meta'] ?? '{}', 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( $stmt = db()->prepare(
'SELECT centro_id, role, aulas 'SELECT org_id, role, ea_aulas
FROM user_centros FROM user_orgs
WHERE user_id = ? WHERE user_id = ?
ORDER BY centro_id' ORDER BY org_id'
); );
$stmt->execute([$row['id']]); $stmt->execute([$row['id']]);
$centro_rows = $stmt->fetchAll(); $org_rows = $stmt->fetchAll();
$orgs = [];
$ea = ['centro' => '', 'centros' => [], 'role' => '', 'aulas' => []]; if (!empty($org_rows)) {
if (!empty($centro_rows)) { $first = $org_rows[0];
$first = $centro_rows[0]; foreach ($org_rows as $r) {
$ea['centro'] = $first['centro_id']; // legacy compat $orgs[] = $r['org_id'];
}
$ea['organization'] = $first['org_id'];
$ea['role'] = $first['role']; $ea['role'] = $first['role'];
$ea['aulas'] = json_decode($first['aulas'] ?? '[]', true) ?: []; $ea['aulas'] = json_decode($first['ea_aulas'] ?? '[]', true) ?: [];
$ea['centros'] = array_column($centro_rows, 'centro_id'); $ea['organizations'] = $orgs;
$ea['centros_data'] = $centro_rows; $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, [ return array_merge($meta, [
'display_name' => $row['display_name'], 'display_name' => $row['display_name'],
'email' => $row['email'], 'email' => $row['email'],
'password_hash' => $row['password_hash'], 'password_hash' => $row['password_hash'],
'permissions' => $permissions, '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'], 'google_auth' => (bool) $row['google_auth'],
]); ]);
} }
@@ -166,7 +192,7 @@ function db_build_auth_data(array $row): array
/** /**
* Create or update a user. * Create or update a user.
* $data keys: username, display_name, email, password_hash, permissions[], * $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. * Returns the user ID.
*/ */
function db_upsert_user(array $data): int function db_upsert_user(array $data): int
@@ -180,7 +206,9 @@ function db_upsert_user(array $data): int
$permissions = json_encode($data['permissions'] ?? []); $permissions = json_encode($data['permissions'] ?? []);
$meta_skip = ['username', 'display_name', 'email', 'password_hash', $meta_skip = ['username', 'display_name', 'email', 'password_hash',
'permissions', 'entreaulas', 'google_auth']; 'permissions', 'entreaulas', 'google_auth',
'orgs', 'organizations', 'organization', 'organizacion',
'role', 'aulas'];
$meta = []; $meta = [];
foreach ($data as $k => $v) { foreach ($data as $k => $v) {
if (!in_array($k, $meta_skip, true)) { if (!in_array($k, $meta_skip, true)) {
@@ -228,53 +256,119 @@ function db_upsert_user(array $data): int
$user_id = (int) $pdo->lastInsertId(); $user_id = (int) $pdo->lastInsertId();
} }
// Update centro assignments when entreaulas data is provided // Update organization assignments if tenant data is provided.
if (array_key_exists('entreaulas', $data)) { $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'] ?? []; $ea = $data['entreaulas'] ?? [];
$pdo->prepare('DELETE FROM user_centros WHERE user_id = ?')->execute([$user_id]);
// Support both legacy single centro and new multi-centro $organizations = [];
$centros = []; $candidate_lists = [
if (!empty($ea['centros']) && is_array($ea['centros'])) { $data['organizations'] ?? null,
$centros = $ea['centros']; $data['orgs'] ?? null,
} elseif (!empty($ea['centro'])) { $ea['organizaciones'] ?? null,
$centros = [$ea['centro']]; $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 (?)'); $organizations = array_values(array_unique(array_filter(array_map(
$ins_uc = $pdo->prepare( static function ($value): string {
'INSERT OR REPLACE INTO user_centros (user_id, centro_id, role, aulas) VALUES (?, ?, ?, ?)' 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) { foreach ($organizations as $org_id) {
if ($cid === '') { if ($org_id === '') {
continue; continue;
} }
$ins_centro->execute([$cid]); $ins_org->execute([$org_id, $org_id]);
$ins_uc->execute([$user_id, $cid, $role, $aulas]); $ins_uo->execute([$user_id, $org_id, $role, $aulas]);
} }
} }
return $user_id; return $user_id;
} }
/** Delete a user and their centro assignments. */ /** Delete a user and their organization assignments. */
function db_delete_user(string $username): void function db_delete_user(string $username): void
{ {
db()->prepare('DELETE FROM users WHERE username = ?')->execute([strtolower($username)]); 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 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 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 ─────────────────────────────────────────────────────────── // ── Aulario helpers ───────────────────────────────────────────────────────────
@@ -283,7 +377,7 @@ function db_get_centro_ids(): array
function db_get_aulario(string $centro_id, string $aulario_id): ?array function db_get_aulario(string $centro_id, string $aulario_id): ?array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $aulario_id]);
$row = $stmt->fetch(); $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 function db_get_aularios(string $centro_id): array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id]);
$result = []; $result = [];
@@ -316,7 +410,7 @@ function db_get_aularios(string $centro_id): array
function db_get_supercafe_menu(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]); $stmt->execute([$centro_id]);
$row = $stmt->fetch(); $row = $stmt->fetch();
if ($row === false) { 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 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)]); ->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 function db_get_supercafe_orders(string $centro_id): array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id]);
return $stmt->fetchAll(); 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 function db_get_supercafe_order(string $centro_id, string $order_ref): ?array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $order_ref]);
$row = $stmt->fetch(); $row = $stmt->fetch();
@@ -363,9 +457,9 @@ function db_upsert_supercafe_order(
string $estado string $estado
): void { ): void {
db()->prepare( 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 (?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(centro_id, order_ref) DO UPDATE SET ON CONFLICT(org_id, order_ref) DO UPDATE SET
fecha = excluded.fecha, fecha = excluded.fecha,
persona = excluded.persona, persona = excluded.persona,
comanda = excluded.comanda, comanda = excluded.comanda,
@@ -378,7 +472,7 @@ function db_upsert_supercafe_order(
function db_next_supercafe_ref(string $centro_id): string function db_next_supercafe_ref(string $centro_id): string
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id]);
$last = $stmt->fetchColumn(); $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 function db_supercafe_count_debts(string $centro_id, string $persona_key): int
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $persona_key]);
return (int) $stmt->fetchColumn(); 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 function db_get_comedor_menu_types(string $centro_id, string $aulario_id): array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $aulario_id]);
$row = $stmt->fetch(); $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 function db_set_comedor_menu_types(string $centro_id, string $aulario_id, array $types): void
{ {
db()->prepare( 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)]); )->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 function db_get_comedor_entry(string $centro_id, string $aulario_id, string $ym, string $day): array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $aulario_id, $ym, $day]);
$row = $stmt->fetch(); $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 function db_set_comedor_entry(string $centro_id, string $aulario_id, string $ym, string $day, array $data): void
{ {
db()->prepare( 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)]); )->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 function db_get_diario_entry(string $centro_id, string $aulario_id, string $entry_date): array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $aulario_id, $entry_date]);
$row = $stmt->fetch(); $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 function db_set_diario_entry(string $centro_id, string $aulario_id, string $entry_date, array $data): void
{ {
db()->prepare( 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)]); )->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 function db_get_panel_alumno(string $centro_id, string $aulario_id, string $alumno): array
{ {
$stmt = db()->prepare( $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]); $stmt->execute([$centro_id, $aulario_id, $alumno]);
$row = $stmt->fetch(); $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 function db_set_panel_alumno(string $centro_id, string $aulario_id, string $alumno, array $data): void
{ {
db()->prepare( 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)]); )->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 ────────────────────────────────────────────────────── // ── Multi-tenant helpers ──────────────────────────────────────────────────────
/** Return all centro IDs the authenticated user belongs to. */ /** Return all organization IDs the authenticated user belongs to. */
function get_user_centros(?array $auth_data = null): array function get_user_organizations(?array $auth_data = null): array
{ {
$data = $auth_data ?? $_SESSION['auth_data'] ?? []; $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'])) { if (!empty($orgs) && is_array($orgs)) {
return array_values($ea['centros']); return array_values(array_unique(array_filter($orgs, static function ($value): bool {
return is_string($value) && $value !== '';
})));
} }
if (!empty($ea['centro'])) { if (!empty($orgs)) {
return [$ea['centro']]; 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 []; return [];
} }
/** Ensure $_SESSION['active_centro'] is set to a valid centro. */ /** Spanish alias used by pre-body.php menu rendering. */
function init_active_centro(?array $auth_data = null): void function get_user_organizaciones(?array $auth_data = null): array
{ {
$centros = get_user_centros($auth_data); $org_ids = get_user_organizations($auth_data);
if (empty($centros)) { 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; $_SESSION['active_centro'] = null;
return; 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);
} }

View File

@@ -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;

View File

@@ -27,11 +27,13 @@ if (!empty($displayName)) {
$initials = mb_strtoupper($first . $last); $initials = mb_strtoupper($first . $last);
} }
// Tenant (centro) management // Tenant (organización) management
$userCentros = get_user_centros($_SESSION["auth_data"] ?? []); $userOrganizaciones = get_user_organizaciones($_SESSION["auth_data"] ?? []);
$activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ''); $activeOrganizacionId = $_SESSION['active_organizacion']
?? ($_SESSION["auth_data"]["aulatek"]["organizacion"] ?? ($_SESSION["auth_data"]["entreaulas"]["organizacion"] ?? ''));
$activeOrganizacionName = $userOrganizaciones[$activeOrganizacionId] ?? '';
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es"> <html lang="es">
@@ -170,6 +172,7 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula
font-weight: 400; font-weight: 400;
white-space: nowrap; white-space: nowrap;
transition: background 0.15s ease; 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: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; } .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
<img src="/static/logo-club.png" alt=""> <img src="/static/logo-club.png" alt="">
<span>Club</span> <span>Club</span>
</a> </a>
<a class="menu-item" href="/entreaulas/"> <a class="menu-item" href="/aulatek/">
<img src="/static/logo-entreaulas.png" alt=""> <img src="/static/logo-entreaulas.png" alt="">
<span>EntreAulas</span> <span>AulaTek</span>
</a> </a>
<a class="menu-item" href="/account/"> <a class="menu-item" href="/account/">
<img src="/static/logo-account.png" alt=""> <img src="/static/logo-account.png" alt="">
@@ -530,22 +533,22 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula
<div class="account-name"><?php echo htmlspecialchars($displayName); ?></div> <div class="account-name"><?php echo htmlspecialchars($displayName); ?></div>
<div class="account-email"><?php echo htmlspecialchars($email); ?></div> <div class="account-email"><?php echo htmlspecialchars($email); ?></div>
</div> </div>
<?php if (!empty($userCentros) && $_SESSION["auth_ok"]): ?> <?php if (!empty($userOrganizaciones) && $_SESSION["auth_ok"]): ?>
<div style="padding: 8px 16px; border-top: 1px solid #e0e0e0;"> <div style="padding: 8px 16px;">
<div style="font-size:.75rem;font-weight:600;color:#5f6368;text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px;"> <div style="font-size:.75rem;font-weight:600;color:#5f6368;text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px;">
Organización activa Organización activa
</div> </div>
<div style="font-size:.9rem;font-weight:600;color:#1a73e8;margin-bottom:<?= count($userCentros) > 1 ? '8px' : '0' ?>;"> <div style="font-size:.9rem;font-weight:600;color:#1a73e8;margin-bottom:<?= count($userOrganizaciones) > 1 ? '8px' : '0' ?>;">
<?= htmlspecialchars($activeCentro ?: '') ?> <?= htmlspecialchars($activeOrganizacionName ?: '') ?>
</div> </div>
<?php if (count($userCentros) > 1): ?> <?php if (count($userOrganizaciones) > 1): ?>
<div style="font-size:.75rem;color:#5f6368;margin-bottom:4px;">Cambiar organización:</div> <div style="font-size:.75rem;color:#5f6368;margin-bottom:4px;">Cambiar organización:</div>
<?php foreach ($userCentros as $cid): if ($cid === $activeCentro) continue; ?> <?php foreach ($userOrganizaciones as $oid => $orgName): if ($oid === $activeOrganizacionId) continue; ?>
<form method="post" action="/_incl/switch_tenant.php" style="margin:0 0 4px;"> <form method="post" action="/_incl/switch_tenant.php" style="margin:0 0 4px;">
<input type="hidden" name="redir" value="<?= htmlspecialchars($_SERVER['REQUEST_URI'] ?? '/') ?>"> <input type="hidden" name="redir" value="<?= htmlspecialchars($_SERVER['REQUEST_URI'] ?? '/') ?>">
<button type="submit" name="centro" value="<?= htmlspecialchars($cid) ?>" <button type="submit" name="organization" value="<?= htmlspecialchars($oid) ?>"
style="display:block;width:100%;text-align:left;padding:5px 8px;border:1px solid #e0e0e0;border-radius:6px;background:#f8f9fa;font-size:.85rem;cursor:pointer;"> style="display:block;width:100%;text-align:left;padding:5px 8px;border:1px solid #e0e0e0;border-radius:6px;background:#f8f9fa;font-size:.85rem;cursor:pointer;">
<?= htmlspecialchars($cid) ?> <?= htmlspecialchars($orgName) ?>
</button> </button>
</form> </form>
<?php endforeach; ?> <?php endforeach; ?>
@@ -554,11 +557,11 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula
<?php endif; ?> <?php endif; ?>
<div class="account-actions"> <div class="account-actions">
<?php if ($_SESSION["auth_ok"]) { ?> <?php if ($_SESSION["auth_ok"]) { ?>
<a href="/account/" class="btn btn-outline-secondary w-100">Gestionar cuenta</a> <a href="/account/" class="btn btn-outline-dark w-100">Gestionar cuenta</a>
<a href="/_login.php?logout=1&redir=/" class="btn btn-outline-secondary w-100">Cerrar sesión</a> <a href="/_login.php?logout=1&redir=/" class="btn btn-outline-danger w-100">Cerrar sesión</a>
<?php } else { ?> <?php } else { ?>
<a href="/_login.php?redir=/" class="btn btn-primary w-100">Iniciar sesión</a> <a href="/_login.php?redir=/" class="btn btn-primary w-100">Iniciar sesión</a>
<a href="/account/register.php" class="btn btn-outline-primary w-100">Crear cuenta</a> <a href="/account/register.php" class="btn btn-outline-dark w-100">Crear cuenta</a>
<?php } ?> <?php } ?>
</div> </div>
</div> </div>
@@ -569,22 +572,11 @@ $activeCentro = $_SESSION['active_centro'] ?? ($_SESSION["auth_data"]["entreaula
<!-- ── App shell (sidebar + content) ──────────────────────── --> <!-- ── App shell (sidebar + content) ──────────────────────── -->
<div class="app-shell"> <div class="app-shell">
<aside class="sidebar"> <aside class="sidebar">
<div class="sidebar-section-label">Esta app</div> <?php
<nav class="sidebar-nav"> if (file_exists(__DIR__ . "/../$APP_CODE/__menu.php")) {
<?php include __DIR__ . "/../$APP_CODE/__menu.php";
if (file_exists(__DIR__ . "/../$APP_CODE/__menu.php")) { }
include __DIR__ . "/../$APP_CODE/__menu.php"; ?>
}
?>
</nav>
<div class="sidebar-divider"></div>
<div class="sidebar-section-label">Axia4</div>
<nav class="sidebar-nav">
<a class="sidebar-link" href="/">
<img src="/static/logo.png" alt="">
<span>Inicio</span>
</a>
</nav>
</aside> </aside>
<label for="sidebarToggle" class="sidebar-backdrop" aria-hidden="true"></label> <label for="sidebarToggle" class="sidebar-backdrop" aria-hidden="true"></label>
<div class="app-content"> <div class="app-content">

View File

@@ -1,8 +1,8 @@
<?php <?php
/** /**
* switch_tenant.php * switch_organization.php
* POST endpoint to switch the active tenant/centro for the current user session. * POST endpoint to switch the active organization for the current user session.
* Validates the requested centro against the user's allowed centros before applying. * Validates the requested organization against the user's allowed organizations before applying.
*/ */
require_once "tools.session.php"; require_once "tools.session.php";
require_once "tools.security.php"; require_once "tools.security.php";
@@ -13,14 +13,28 @@ if (!isset($_SESSION["auth_ok"]) || $_SESSION["auth_ok"] !== true) {
die("No autenticado."); die("No autenticado.");
} }
$requested = Sf($_POST['centro'] ?? ''); $requested = safe_organization_id(
$_POST['organization']
?? $_POST['organizacion']
?? $_POST['org']
?? $_POST['centro']
?? ''
);
$redir = safe_redir($_POST['redir'] ?? '/'); $redir = safe_redir($_POST['redir'] ?? '/');
$centros = get_user_centros($_SESSION['auth_data'] ?? []); $organizations = get_user_organizations($_SESSION['auth_data'] ?? []);
if ($requested !== '' && in_array($requested, $centros, true)) { if ($requested !== '' && in_array($requested, $organizations, true)) {
$_SESSION['active_organization'] = $requested;
$_SESSION['active_organizacion'] = $requested;
$_SESSION['active_centro'] = $requested; $_SESSION['active_centro'] = $requested;
// Also update session auth_data so it reflects immediately // Also update session auth_data so it reflects immediately
$_SESSION['auth_data']['active_organization'] = $requested;
$_SESSION['auth_data']['aulatek']['organizacion'] = $requested;
$_SESSION['auth_data']['aulatek']['organization'] = $requested;
$_SESSION['auth_data']['aulatek']['centro'] = $requested;
$_SESSION['auth_data']['entreaulas']['organizacion'] = $requested;
$_SESSION['auth_data']['entreaulas']['organization'] = $requested;
$_SESSION['auth_data']['entreaulas']['centro'] = $requested; $_SESSION['auth_data']['entreaulas']['centro'] = $requested;
} }

View File

@@ -25,7 +25,7 @@ if (str_starts_with($ua, "Axia4Auth/")) {
$_COOKIE["auth_user"] = $username; $_COOKIE["auth_user"] = $username;
$_COOKIE["auth_pass_b64"] = base64_encode($userpass); $_COOKIE["auth_pass_b64"] = base64_encode($userpass);
$_SESSION["auth_external_lock"] = "header"; $_SESSION["auth_external_lock"] = "header";
init_active_centro($_SESSION["auth_data"]); init_active_org($_SESSION["auth_data"]);
} }
// ── Cookie-based auto-login ─────────────────────────────────────────────────── // ── Cookie-based auto-login ───────────────────────────────────────────────────
@@ -39,7 +39,7 @@ if (($_SESSION["auth_ok"] ?? false) != true
$_SESSION["auth_user"] = $username; $_SESSION["auth_user"] = $username;
$_SESSION["auth_data"] = db_build_auth_data($row); $_SESSION["auth_data"] = db_build_auth_data($row);
$_SESSION["auth_ok"] = true; $_SESSION["auth_ok"] = true;
init_active_centro($_SESSION["auth_data"]); init_active_org($_SESSION["auth_data"]);
} }
} }
@@ -50,7 +50,7 @@ if (!empty($_SESSION["auth_ok"]) && !empty($_SESSION["auth_user"])) {
$row = db_get_user($_SESSION["auth_user"]); $row = db_get_user($_SESSION["auth_user"]);
if ($row) { if ($row) {
$_SESSION["auth_data"] = db_build_auth_data($row); $_SESSION["auth_data"] = db_build_auth_data($row);
init_active_centro($_SESSION["auth_data"]); init_active_org($_SESSION["auth_data"]);
} }
$_SESSION["last_reload_time"] = time(); $_SESSION["last_reload_time"] = time();
} elseif ($load_mode !== "never") { } elseif ($load_mode !== "never") {
@@ -59,7 +59,7 @@ if (!empty($_SESSION["auth_ok"]) && !empty($_SESSION["auth_user"])) {
$row = db_get_user($_SESSION["auth_user"]); $row = db_get_user($_SESSION["auth_user"]);
if ($row) { if ($row) {
$_SESSION["auth_data"] = db_build_auth_data($row); $_SESSION["auth_data"] = db_build_auth_data($row);
init_active_centro($_SESSION["auth_data"]); init_active_org($_SESSION["auth_data"]);
} }
$_SESSION["last_reload_time"] = time(); $_SESSION["last_reload_time"] = time();
} }

View File

@@ -108,12 +108,23 @@ function Sb($input) {
} }
function get_user_file_path($username) function get_user_file_path($username)
{ {
return USERS_DIR . $username . '.json'; $users_dir = defined('USERS_DIR') ? USERS_DIR : '/DATA/Usuarios/';
return rtrim($users_dir, '/') . '/' . $username . '.json';
}
function safe_organization_id($value)
{
return preg_replace('/[^a-zA-Z0-9._-]/', '', (string)$value);
}
function safe_organizacion_id($value)
{
return safe_organization_id($value);
} }
function safe_centro_id($value) function safe_centro_id($value)
{ {
return preg_replace('/[^a-zA-Z0-9._-]/', '', (string)$value); return safe_organization_id($value);
} }
function safe_aulario_id($value) function safe_aulario_id($value)
@@ -156,12 +167,42 @@ function path_is_within($real_base, $real_path)
return strpos($real_path, $base_prefix) === 0 || $real_path === rtrim($real_base, DIRECTORY_SEPARATOR); return strpos($real_path, $base_prefix) === 0 || $real_path === rtrim($real_base, DIRECTORY_SEPARATOR);
} }
function aulatek_orgs_base_path()
{
$orgs_path = '/DATA/entreaulas/Organizaciones';
$legacy_path = '/DATA/entreaulas/Centros';
if (is_dir($orgs_path)) {
return $orgs_path;
}
if (is_dir($legacy_path)) {
return $legacy_path;
}
return $orgs_path;
}
function entreaulas_orgs_base_path()
{
return aulatek_orgs_base_path();
}
function safe_aulario_config_path($centro_id, $aulario_id) function safe_aulario_config_path($centro_id, $aulario_id)
{ {
$centro = safe_centro_id($centro_id); $centro = safe_organization_id($centro_id);
$aulario = safe_id_segment($aulario_id); $aulario = safe_id_segment($aulario_id);
if ($centro === '' || $aulario === '') { if ($centro === '' || $aulario === '') {
return null; return null;
} }
return "/DATA/entreaulas/Centros/$centro/Aularios/$aulario.json"; return aulatek_orgs_base_path() . "/$centro/Aularios/$aulario.json";
}
function safe_redir($url, $default = "/")
{
if (empty($url) || !is_string($url)) {
return $default;
}
// Only allow relative URLs that start with /
if (str_starts_with($url, "/") && !str_contains($url, "\0")) {
return $url;
}
return $default;
} }

View File

@@ -16,7 +16,7 @@ switch ($_GET['form'] ?? '') {
'username' => $admin_user, 'username' => $admin_user,
'display_name' => 'Administrador', 'display_name' => 'Administrador',
'email' => "$admin_user@nomail.arpa", 'email' => "$admin_user@nomail.arpa",
'permissions' => ['*', 'sysadmin:access', 'entreaulas:access'], 'permissions' => ['*', 'sysadmin:access', 'aulatek:access'],
'password_hash' => password_hash($admin_password, PASSWORD_DEFAULT), 'password_hash' => password_hash($admin_password, PASSWORD_DEFAULT),
]); ]);
db_set_config('installed', '1'); db_set_config('installed', '1');

View File

@@ -7,33 +7,21 @@ if (!isset($AuthConfig)) {
} }
$DOMAIN = $_SERVER["HTTP_X_FORWARDED_HOST"] ?? $_SERVER["HTTP_HOST"]; $DOMAIN = $_SERVER["HTTP_X_FORWARDED_HOST"] ?? $_SERVER["HTTP_HOST"];
/** // safe_redir() is provided by _incl/tools.security.php.
* 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 '/';
}
if ($_GET["reload_user"] == "1") { if (($_GET["reload_user"] ?? "") === "1") {
$row = db_get_user($_SESSION["auth_user"] ?? ""); $row = db_get_user($_SESSION["auth_user"] ?? "");
if (!$row) { if (!$row) {
header("Location: /"); header("Location: /");
die(); die();
} }
$_SESSION['auth_data'] = db_build_auth_data($row); $_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"] ?? "/"); $redir = safe_redir($_GET["redir"] ?? "/");
header("Location: $redir"); header("Location: $redir");
die(); die();
} }
if ($_GET["google_callback"] == "1") { if (($_GET["google_callback"] ?? "") === "1") {
if (!isset($AuthConfig["google_client_id"]) || !isset($AuthConfig["google_client_secret"])) { if (!isset($AuthConfig["google_client_id"]) || !isset($AuthConfig["google_client_secret"])) {
die("Error: La autenticación de Google no está configurada."); 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_user'] = $username;
$_SESSION['auth_data'] = db_build_auth_data($user_row); $_SESSION['auth_data'] = db_build_auth_data($user_row);
$_SESSION['auth_ok'] = true; $_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"]; $cookie_options = ["expires" => time() + (86400 * 30), "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"];
setcookie("auth_user", $username, $cookie_options); setcookie("auth_user", $username, $cookie_options);
setcookie("auth_pass_b64", base64_encode($password), $cookie_options); setcookie("auth_pass_b64", base64_encode($password), $cookie_options);
@@ -120,7 +108,7 @@ if ($_GET["google_callback"] == "1") {
header("Location: $redir"); header("Location: $redir");
die(); die();
} }
if ($_GET["google"] == "1") { if (($_GET["google"] ?? "") === "1") {
if (!isset($AuthConfig["google_client_id"]) || !isset($AuthConfig["google_client_secret"])) { if (!isset($AuthConfig["google_client_id"]) || !isset($AuthConfig["google_client_secret"])) {
die("Error: La autenticación de Google no está configurada."); die("Error: La autenticación de Google no está configurada.");
} }
@@ -148,7 +136,7 @@ if ($_GET["google"] == "1") {
header("Location: " . $request_to); header("Location: " . $request_to);
die(); die();
} }
if ($_GET["logout"] == "1") { if (($_GET["logout"] ?? "") === "1") {
$redir = safe_redir($_GET["redir"] ?? "/"); $redir = safe_redir($_GET["redir"] ?? "/");
$cookie_options_expired = ["expires" => time() - 3600, "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"]; $cookie_options_expired = ["expires" => time() - 3600, "path" => "/", "httponly" => true, "secure" => true, "samesite" => "Lax"];
setcookie("auth_user", "", $cookie_options_expired); setcookie("auth_user", "", $cookie_options_expired);
@@ -157,7 +145,7 @@ if ($_GET["logout"] == "1") {
header("Location: $redir"); header("Location: $redir");
die(); die();
} }
if ($_GET["clear_session"] == "1") { if (($_GET["clear_session"] ?? "") === "1") {
session_destroy(); session_destroy();
$redir = safe_redir($_GET["redir"] ?? "/"); $redir = safe_redir($_GET["redir"] ?? "/");
header("Location: $redir"); header("Location: $redir");
@@ -174,7 +162,7 @@ if (isset($_POST["user"])) {
$_SESSION['auth_user'] = $user; $_SESSION['auth_user'] = $user;
$_SESSION['auth_data'] = db_build_auth_data($row); $_SESSION['auth_data'] = db_build_auth_data($row);
$_SESSION['auth_ok'] = true; $_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"]; $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); setcookie("auth_pass_b64", base64_encode($password), $cookie_options);

View File

@@ -9,12 +9,13 @@ $displayName = $authData["display_name"] ?? 'Invitado';
$email = $authData["email"] ?? ''; $email = $authData["email"] ?? '';
$permissions = $authData["permissions"] ?? []; $permissions = $authData["permissions"] ?? [];
// Tenant / centro management // Tenant / organization management
$userCentros = get_user_centros($authData); $userOrganizations = get_user_organizations($authData);
$activeCentro = $_SESSION['active_centro'] ?? ($authData['entreaulas']['centro'] ?? ''); $activeOrganization = $_SESSION['active_organization']
$aularios = ($activeCentro !== '') ? db_get_aularios($activeCentro) : []; ?? ($authData['aulatek']['organizacion'] ?? ($authData['aulatek']['centro'] ?? ($authData['entreaulas']['organizacion'] ?? ($authData['entreaulas']['centro'] ?? ''))));
$userAulas = $authData['entreaulas']['aulas'] ?? []; $aularios = ($activeOrganization !== '') ? db_get_aularios($activeOrganization) : [];
$role = $authData['entreaulas']['role'] ?? ''; $userAulas = $authData['aulatek']['aulas'] ?? ($authData['entreaulas']['aulas'] ?? []);
$role = $authData['aulatek']['role'] ?? ($authData['entreaulas']['role'] ?? '');
// Initials for avatar // Initials for avatar
$parts = preg_split('/\s+/', trim($displayName)); $parts = preg_split('/\s+/', trim($displayName));
@@ -65,19 +66,19 @@ if ($initials === '') {
</div> </div>
<!-- Tenant / Centro Card --> <!-- Tenant / Centro Card -->
<?php if (!empty($userCentros)): ?> <?php if (!empty($userOrganizations)): ?>
<div class="account-card"> <div class="account-card">
<h2>Organizaciones</h2> <h2>Organizaciones</h2>
<?php foreach ($userCentros as $cid): ?> <?php foreach ($userOrganizations as $orgId): ?>
<form method="post" action="/_incl/switch_tenant.php" style="margin:0;"> <form method="post" action="/_incl/switch_tenant.php" style="margin:0;">
<input type="hidden" name="redir" value="/account/"> <input type="hidden" name="redir" value="/account/">
<button type="submit" name="centro" value="<?= htmlspecialchars($cid) ?>" <button type="submit" name="organization" value="<?= htmlspecialchars($orgId) ?>"
class="tenant-btn <?= ($activeCentro === $cid) ? 'active-tenant' : '' ?>"> class="tenant-btn <?= ($activeOrganization === $orgId) ? 'active-tenant' : '' ?>">
<?php if ($activeCentro === $cid): ?> <?php if ($activeOrganization === $orgId): ?>
<span style="color:var(--gw-blue,#1a73e8);">✓ </span> <span style="color:var(--gw-blue,#1a73e8);">✓ </span>
<?php endif; ?> <?php endif; ?>
<?= htmlspecialchars($cid) ?> <?= htmlspecialchars($orgId) ?>
<?php if ($activeCentro === $cid): ?> <?php if ($activeOrganization === $orgId): ?>
<span class="badge-pill badge-active" style="float:right;">Activo</span> <span class="badge-pill badge-active" style="float:right;">Activo</span>
<?php endif; ?> <?php endif; ?>
</button> </button>
@@ -89,7 +90,7 @@ if ($initials === '') {
<!-- Aulas Card --> <!-- Aulas Card -->
<?php if (!empty($userAulas)): ?> <?php if (!empty($userAulas)): ?>
<div class="account-card"> <div class="account-card">
<h2>Mis Aulas (<?= htmlspecialchars($activeCentro) ?>)</h2> <h2>Mis Aulas (<?= htmlspecialchars($activeOrganization) ?>)</h2>
<?php foreach ($userAulas as $aula_id): ?> <?php foreach ($userAulas as $aula_id): ?>
<?php $aula = $aularios[$aula_id] ?? null; ?> <?php $aula = $aularios[$aula_id] ?? null; ?>
<div class="info-row"> <div class="info-row">
@@ -119,7 +120,7 @@ if ($initials === '') {
<div class="account-card"> <div class="account-card">
<h2>Sesión Activa</h2> <h2>Sesión Activa</h2>
<div class="info-row"><span class="label">ID Sesión</span><span style="font-family:monospace;font-size:.75rem;"><?= htmlspecialchars(substr(session_id(), 0, 12)) ?>…</span></div> <div class="info-row"><span class="label">ID Sesión</span><span style="font-family:monospace;font-size:.75rem;"><?= htmlspecialchars(substr(session_id(), 0, 12)) ?>…</span></div>
<div class="info-row"><span class="label">Org. activa</span><span><?= htmlspecialchars($activeCentro ?: '') ?></span></div> <div class="info-row"><span class="label">Org. activa</span><span><?= htmlspecialchars($activeOrganization ?: '') ?></span></div>
<div class="info-row"><span class="label">Autenticación</span><span><?= empty($authData['google_auth']) ? 'Contraseña' : 'Google' ?></span></div> <div class="info-row"><span class="label">Autenticación</span><span><?= empty($authData['google_auth']) ? 'Contraseña' : 'Google' ?></span></div>
<div style="margin-top:16px;"> <div style="margin-top:16px;">
<a href="/_incl/logout.php" class="btn btn-danger btn-sm">Cerrar sesión</a> <a href="/_incl/logout.php" class="btn btn-danger btn-sm">Cerrar sesión</a>

View File

@@ -2,10 +2,10 @@
<a href="/_login.php?logout=1" class="btn btn-secondary">Cerrar sesión</a> --> <a href="/_login.php?logout=1" class="btn btn-secondary">Cerrar sesión</a> -->
<a class="sidebar-link" href="/entreaulas/"> <a class="sidebar-link" href="/aulatek/">
<span>Mi aula</span> <span>Mi aula</span>
</a> </a>
<a class="sidebar-link" href="/entreaulas/supercafe.php"> <a class="sidebar-link" href="/aulatek/supercafe.php">
<img src="/static/iconexperience/purchase_order_cart.png" alt=""> <img src="/static/iconexperience/purchase_order_cart.png" alt="">
<span>SuperCafe</span> <span>SuperCafe</span>
</a> </a>

View File

@@ -10,9 +10,10 @@ header("Access-Control-Allow-Origin: *");
$type = $_GET["type"] ?? ""; $type = $_GET["type"] ?? "";
$orgs_base_dir = basename(aulatek_orgs_base_path());
switch ($type) { switch ($type) {
case "alumno_photo": case "alumno_photo":
$centro = safe_centro_id($_GET["centro"] ?? ''); $centro = safe_organization_id($_GET["organization"] ?? $_GET["organizacion"] ?? $_GET["org"] ?? $_GET["centro"] ?? '');
$aulario = safe_id_segment($_GET["aulario"] ?? ''); $aulario = safe_id_segment($_GET["aulario"] ?? '');
$alumno = safe_id_segment($_GET["alumno"] ?? ''); $alumno = safe_id_segment($_GET["alumno"] ?? '');
// Additional validation to prevent empty names // Additional validation to prevent empty names
@@ -20,19 +21,19 @@ switch ($type) {
header("HTTP/1.1 403 Forbidden"); header("HTTP/1.1 403 Forbidden");
die("Invalid parameters"); die("Invalid parameters");
} }
$relpath = "entreaulas/Centros/$centro/Aularios/$aulario/Alumnos/$alumno/photo.jpg"; $relpath = "entreaulas/$orgs_base_dir/$centro/Aularios/$aulario/Alumnos/$alumno/photo.jpg";
break; break;
case "panel_actividades": case "panel_actividades":
$centro = safe_centro_id($_GET["centro"] ?? ''); $centro = safe_organization_id($_GET["organization"] ?? $_GET["organizacion"] ?? $_GET["org"] ?? $_GET["centro"] ?? '');
$activity = safe_id_segment($_GET["activity"] ?? ''); $activity = safe_id_segment($_GET["activity"] ?? '');
if (empty($centro) || empty($activity)) { if (empty($centro) || empty($activity)) {
header("HTTP/1.1 400 Bad Request"); header("HTTP/1.1 400 Bad Request");
die("Invalid parameters"); die("Invalid parameters");
} }
$relpath = "entreaulas/Centros/$centro/Panel/Actividades/$activity/photo.jpg"; $relpath = "entreaulas/$orgs_base_dir/$centro/Panel/Actividades/$activity/photo.jpg";
break; break;
case "comedor_image": case "comedor_image":
$centro = safe_centro_id($_GET["centro"] ?? ''); $centro = safe_organization_id($_GET["organization"] ?? $_GET["organizacion"] ?? $_GET["org"] ?? $_GET["centro"] ?? '');
$aulario = safe_id_segment($_GET["aulario"] ?? ''); $aulario = safe_id_segment($_GET["aulario"] ?? '');
$date = preg_replace('/[^0-9-]/', '', $_GET["date"] ?? ''); $date = preg_replace('/[^0-9-]/', '', $_GET["date"] ?? '');
$file = safe_filename($_GET["file"] ?? ''); $file = safe_filename($_GET["file"] ?? '');
@@ -46,10 +47,10 @@ switch ($type) {
} }
$ym = substr($date, 0, 7); $ym = substr($date, 0, 7);
$day = substr($date, 8, 2); $day = substr($date, 8, 2);
$relpath = "entreaulas/Centros/$centro/Aularios/$aulario/Comedor/$ym/$day/$file"; $relpath = "entreaulas/$orgs_base_dir/$centro/Aularios/$aulario/Comedor/$ym/$day/$file";
break; break;
case "proyecto_file": case "proyecto_file":
$centro = safe_centro_id($_GET["centro"] ?? ''); $centro = safe_organization_id($_GET["organization"] ?? $_GET["organizacion"] ?? $_GET["org"] ?? $_GET["centro"] ?? '');
$project = safe_id_segment($_GET["project"] ?? ''); $project = safe_id_segment($_GET["project"] ?? '');
$file = safe_filename($_GET["file"] ?? ''); $file = safe_filename($_GET["file"] ?? '');
if (empty($centro) || empty($project) || empty($file)) { if (empty($centro) || empty($project) || empty($file)) {
@@ -61,7 +62,7 @@ switch ($type) {
header("HTTP/1.1 400 Bad Request"); header("HTTP/1.1 400 Bad Request");
die("Invalid file name"); die("Invalid file name");
} }
$projects_base = "/DATA/entreaulas/Centros/$centro/Proyectos"; $projects_base = aulatek_orgs_base_path() . "/$centro/Proyectos";
$project_dir = null; $project_dir = null;
if (is_dir($projects_base)) { if (is_dir($projects_base)) {
$iterator = new RecursiveIteratorIterator( $iterator = new RecursiveIteratorIterator(

View File

@@ -1,5 +1,5 @@
<?php <?php
$APP_CODE = "entreaulas"; $APP_CODE = "aulatek";
$APP_NAME = "EntreAulas"; $APP_NAME = "AulaTek";
$APP_TITLE = "EntreAulas"; $APP_TITLE = "AulaTek";
require_once __DIR__ . "/../../_incl/auth_redir.php"; require_once __DIR__ . "/../../_incl/auth_redir.php";

View File

@@ -1,5 +1,5 @@
<?php <?php
$APP_CODE = "entreaulas"; $APP_CODE = "aulatek";
$APP_NAME = "EntreAulas"; $APP_NAME = "AulaTek";
$APP_TITLE = "EntreAulas"; $APP_TITLE = "AulaTek";
require_once __DIR__ . "/../../_incl/pre-body.php"; require_once __DIR__ . "/../../_incl/pre-body.php";

View File

@@ -2,14 +2,16 @@
require_once "_incl/auth_redir.php"; require_once "_incl/auth_redir.php";
require_once "../_incl/tools.security.php"; require_once "../_incl/tools.security.php";
// Check if user has docente permission // Check if user has docente permission
if (!in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? [])) { $permissions = $_SESSION["auth_data"]["permissions"] ?? [];
if (!in_array("aulatek:docente", $permissions, true) && !in_array("entreaulas:docente", $permissions, true)) {
header("HTTP/1.1 403 Forbidden"); header("HTTP/1.1 403 Forbidden");
die("Access denied"); die("Access denied");
} }
$aulario_id = safe_id_segment($_GET["aulario"] ?? ""); $aulario_id = safe_id_segment($_GET["aulario"] ?? "");
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
$centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
if (empty($aulario_id) || empty($centro_id)) { if (empty($aulario_id) || empty($centro_id)) {
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
@@ -24,7 +26,7 @@ if (empty($aulario_id) || empty($centro_id)) {
} }
// Validate paths with realpath // Validate paths with realpath
$base_path = "/DATA/entreaulas/Centros"; $base_path = aulatek_orgs_base_path();
$real_base = realpath($base_path); $real_base = realpath($base_path);
$alumnos_base_path = "$base_path/$centro_id/Aularios/$aulario_id/Alumnos"; $alumnos_base_path = "$base_path/$centro_id/Aularios/$aulario_id/Alumnos";
@@ -250,7 +252,7 @@ switch ($_GET["action"] ?? '') {
<label class="form-label">Foto actual:</label> <label class="form-label">Foto actual:</label>
<?php if ($photo_exists): ?> <?php if ($photo_exists): ?>
<div class="mb-2"> <div class="mb-2">
<img src="_filefetch.php?type=alumno_photo&alumno=<?= urlencode($nombre) ?>&centro=<?= urlencode($centro_id) ?>&aulario=<?= urlencode($aulario_id) ?>" <img src="_filefetch.php?type=alumno_photo&alumno=<?= urlencode($nombre) ?>&org=<?= urlencode($centro_id) ?>&aulario=<?= urlencode($aulario_id) ?>"
alt="Foto de <?= htmlspecialchars($nombre) ?>" alt="Foto de <?= htmlspecialchars($nombre) ?>"
style="max-width: 200px; max-height: 200px; border: 2px solid #ddd; border-radius: 10px;"> style="max-width: 200px; max-height: 200px; border: 2px solid #ddd; border-radius: 10px;">
</div> </div>
@@ -351,7 +353,7 @@ switch ($_GET["action"] ?? '') {
<tr> <tr>
<td> <td>
<?php if ($photo_exists): ?> <?php if ($photo_exists): ?>
<img src="_filefetch.php?type=alumno_photo&alumno=<?= urlencode($nombre) ?>&centro=<?= urlencode($centro_id) ?>&aulario=<?= urlencode($aulario_id) ?>" <img src="_filefetch.php?type=alumno_photo&alumno=<?= urlencode($nombre) ?>&org=<?= urlencode($centro_id) ?>&aulario=<?= urlencode($aulario_id) ?>"
alt="Foto de <?= htmlspecialchars($nombre) ?>" alt="Foto de <?= htmlspecialchars($nombre) ?>"
style="width: 50px; height: 50px; object-fit: cover; border-radius: 5px;"> style="width: 50px; height: 50px; object-fit: cover; border-radius: 5px;">
<?php else: ?> <?php else: ?>
@@ -379,7 +381,7 @@ switch ($_GET["action"] ?? '') {
</table> </table>
<?php endif; ?> <?php endif; ?>
<a href="/entreaulas/aulario.php?id=<?= urlencode($aulario_id) ?>" class="btn btn-secondary mt-3">Volver al Aulario</a> <a href="/aulatek/aulario.php?id=<?= urlencode($aulario_id) ?>" class="btn btn-secondary mt-3">Volver al Aulario</a>
</div> </div>
<?php <?php
require_once "_incl/post-body.php"; require_once "_incl/post-body.php";

View File

@@ -15,7 +15,7 @@ La API utiliza el mismo sistema de autenticación que el resto de la aplicación
### 1. Obtener tipos de menú ### 1. Obtener tipos de menú
**GET** `/entreaulas/api/comedor.php?action=get_menu_types&aulario={aulario_id}` **GET** `/aulatek/api/comedor.php?action=get_menu_types&aulario={aulario_id}`
Devuelve todos los tipos de menú disponibles para un aulario. Devuelve todos los tipos de menú disponibles para un aulario.
@@ -89,7 +89,7 @@ Obtiene el menú de un día específico y tipo de menú.
### 3. Guardar menú ### 3. Guardar menú
**POST** `/entreaulas/api/comedor.php?action=save_menu&aulario={aulario_id}` **POST** `/aulatek/api/comedor.php?action=save_menu&aulario={aulario_id}`
Guarda o actualiza un menú para un día específico. Guarda o actualiza un menú para un día específico.
@@ -114,7 +114,7 @@ Guarda o actualiza un menú para un día específico.
**Ejemplo de uso con curl:** **Ejemplo de uso con curl:**
```bash ```bash
curl -X POST "http://localhost/entreaulas/api/comedor.php?action=save_menu&aulario=aulario_id" \ curl -X POST "http://localhost/aulatek/api/comedor.php?action=save_menu&aulario=aulario_id" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"date": "2026-02-18", "date": "2026-02-18",
@@ -131,7 +131,7 @@ curl -X POST "http://localhost/entreaulas/api/comedor.php?action=save_menu&aular
### 4. Añadir nuevo tipo de menú ### 4. Añadir nuevo tipo de menú
**POST** `/entreaulas/api/comedor.php?action=add_menu_type&aulario={aulario_id}` **POST** `/aulatek/api/comedor.php?action=add_menu_type&aulario={aulario_id}`
Crea un nuevo tipo de menú. Crea un nuevo tipo de menú.
@@ -146,7 +146,7 @@ Crea un nuevo tipo de menú.
**Ejemplo de uso con curl:** **Ejemplo de uso con curl:**
```bash ```bash
curl -X POST "http://localhost/entreaulas/api/comedor.php?action=add_menu_type&aulario=aulario_id" \ curl -X POST "http://localhost/aulatek/api/comedor.php?action=add_menu_type&aulario=aulario_id" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"id": "celiaco", "id": "celiaco",
@@ -159,7 +159,7 @@ curl -X POST "http://localhost/entreaulas/api/comedor.php?action=add_menu_type&a
### 5. Renombrar tipo de menú ### 5. Renombrar tipo de menú
**POST** `/entreaulas/api/comedor.php?action=rename_menu_type&aulario={aulario_id}` **POST** `/aulatek/api/comedor.php?action=rename_menu_type&aulario={aulario_id}`
Cambia el nombre o color de un tipo de menú existente. Cambia el nombre o color de un tipo de menú existente.
@@ -176,7 +176,7 @@ Cambia el nombre o color de un tipo de menú existente.
### 6. Eliminar tipo de menú ### 6. Eliminar tipo de menú
**POST** `/entreaulas/api/comedor.php?action=delete_menu_type&aulario={aulario_id}` **POST** `/aulatek/api/comedor.php?action=delete_menu_type&aulario={aulario_id}`
Elimina un tipo de menú. Elimina un tipo de menú.
@@ -211,7 +211,7 @@ Elimina un tipo de menú.
```javascript ```javascript
async function obtenerMenu(aularioId) { async function obtenerMenu(aularioId) {
const response = await fetch( const response = await fetch(
`/entreaulas/api/comedor.php?action=get_menu&aulario=${aularioId}` `/aulatek/api/comedor.php?action=get_menu&aulario=${aularioId}`
); );
const data = await response.json(); const data = await response.json();
return data.menu; return data.menu;
@@ -223,7 +223,7 @@ async function obtenerMenu(aularioId) {
```javascript ```javascript
async function guardarMenu(aularioId, fecha, tipoMenu, platos) { async function guardarMenu(aularioId, fecha, tipoMenu, platos) {
const response = await fetch( const response = await fetch(
`/entreaulas/api/comedor.php?action=save_menu&aulario=${aularioId}`, `/aulatek/api/comedor.php?action=save_menu&aulario=${aularioId}`,
{ {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
@@ -243,7 +243,7 @@ async function guardarMenu(aularioId, fecha, tipoMenu, platos) {
```javascript ```javascript
async function obtenerTiposMenu(aularioId) { async function obtenerTiposMenu(aularioId) {
const response = await fetch( const response = await fetch(
`/entreaulas/api/comedor.php?action=get_menu_types&aulario=${aularioId}` `/aulatek/api/comedor.php?action=get_menu_types&aulario=${aularioId}`
); );
const data = await response.json(); const data = await response.json();
return data.menu_types; return data.menu_types;

View File

@@ -5,15 +5,17 @@ require_once "../_incl/tools.security.php";
require_once "../../_incl/db.php"; require_once "../../_incl/db.php";
// Check permissions // Check permissions
if (!in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? [])) { $permissions = $_SESSION["auth_data"]["permissions"] ?? [];
if (!in_array("aulatek:docente", $permissions, true) && !in_array("entreaulas:docente", $permissions, true)) {
http_response_code(403); http_response_code(403);
die(json_encode(["error" => "Access denied", "code" => "FORBIDDEN"])); die(json_encode(["error" => "Access denied", "code" => "FORBIDDEN"]));
} }
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
$centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
if ($centro_id === "") { if ($centro_id === "") {
http_response_code(400); http_response_code(400);
die(json_encode(["error" => "Centro not found in session", "code" => "INVALID_SESSION"])); die(json_encode(["error" => "Organizacion not found in session", "code" => "INVALID_SESSION"]));
} }
$action = $_GET["action"] ?? ($_POST["action"] ?? ""); $action = $_GET["action"] ?? ($_POST["action"] ?? "");
@@ -24,7 +26,7 @@ if ($aulario_id === "") {
die(json_encode(["error" => "aulario parameter is required", "code" => "MISSING_PARAM"])); die(json_encode(["error" => "aulario parameter is required", "code" => "MISSING_PARAM"]));
} }
$userAulas = array_values(array_filter(array_map('safe_id_segment', $_SESSION["auth_data"]["entreaulas"]["aulas"] ?? []))); $userAulas = array_values(array_filter(array_map('safe_id_segment', $tenant_data["aulas"] ?? [])));
if (!in_array($aulario_id, $userAulas, true)) { if (!in_array($aulario_id, $userAulas, true)) {
http_response_code(403); http_response_code(403);
die(json_encode(["error" => "Access denied to this aulario", "code" => "FORBIDDEN"])); die(json_encode(["error" => "Access denied to this aulario", "code" => "FORBIDDEN"]));

View File

@@ -5,7 +5,8 @@ require_once "../_incl/tools.security.php";
require_once "../_incl/db.php"; require_once "../_incl/db.php";
$aulario_id = safe_id_segment($_GET["id"] ?? ""); $aulario_id = safe_id_segment($_GET["id"] ?? "");
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
$centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
$aulario = db_get_aulario($centro_id, $aulario_id); $aulario = db_get_aulario($centro_id, $aulario_id);
if (!$aulario || !is_array($aulario)) { if (!$aulario || !is_array($aulario)) {
@@ -26,13 +27,14 @@ if (!$aulario || !is_array($aulario)) {
</div> </div>
<div id="grid"> <div id="grid">
<a href="/entreaulas/paneldiario.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-primary grid-item"> <a href="/aulatek/paneldiario.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-primary grid-item">
<img src="/static/arasaac/pdi.png" height="125" style="background: white; padding: 5px; border-radius: 10px;"> <img src="/static/arasaac/pdi.png" height="125" style="background: white; padding: 5px; border-radius: 10px;">
</br> </br>
Panel Diario Panel Diario
</a> </a>
<?php if (in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? [])): ?> <?php $permissions = $_SESSION["auth_data"]["permissions"] ?? []; ?>
<a href="/entreaulas/alumnos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-info grid-item"> <?php if (in_array("aulatek:docente", $permissions, true) || in_array("entreaulas:docente", $permissions, true)): ?>
<a href="/aulatek/alumnos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-info grid-item">
<img src="/static/arasaac/alumnos.png" height="125" style="background: white; padding: 5px; border-radius: 10px;" alt="Icono de gestión de alumnos"> <img src="/static/arasaac/alumnos.png" height="125" style="background: white; padding: 5px; border-radius: 10px;" alt="Icono de gestión de alumnos">
<br> <br>
Gestión de Alumnos Gestión de Alumnos
@@ -46,13 +48,13 @@ if (!$aulario || !is_array($aulario)) {
</a> </a>
<?php endif; ?> <?php endif; ?>
<!-- Menú del comedor --> <!-- Menú del comedor -->
<a href="/entreaulas/comedor.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-success grid-item"> <a href="/aulatek/comedor.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-success grid-item">
<img src="/static/arasaac/comedor.png" height="125" style="background: white; padding: 5px; border-radius: 10px;"> <img src="/static/arasaac/comedor.png" height="125" style="background: white; padding: 5px; border-radius: 10px;">
<br> <br>
Menú del Comedor Menú del Comedor
</a> </a>
<!-- Proyectos --> <!-- Proyectos -->
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-warning grid-item"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-warning grid-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="125" fill="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="125" fill="currentColor">
<title>folder-multiple</title> <title>folder-multiple</title>
<path d="M22,4H14L12,2H6A2,2 0 0,0 4,4V16A2,2 0 0,0 6,18H22A2,2 0 0,0 24,16V6A2,2 0 0,0 22,4M2,6H0V11H0V20A2,2 0 0,0 2,22H20V20H2V6Z" /> <path d="M22,4H14L12,2H6A2,2 0 0,0 4,4V16A2,2 0 0,0 6,18H22A2,2 0 0,0 24,16V6A2,2 0 0,0 22,4M2,6H0V11H0V20A2,2 0 0,0 2,22H20V20H2V6Z" />

View File

@@ -3,13 +3,15 @@ require_once "_incl/auth_redir.php";
require_once "../_incl/tools.security.php"; require_once "../_incl/tools.security.php";
require_once "../_incl/db.php"; require_once "../_incl/db.php";
if (in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? []) === false) { $permissions = $_SESSION["auth_data"]["permissions"] ?? [];
if (!in_array("aulatek:docente", $permissions, true) && !in_array("entreaulas:docente", $permissions, true)) {
header("HTTP/1.1 403 Forbidden"); header("HTTP/1.1 403 Forbidden");
die("Access denied"); die("Access denied");
} }
$aulario_id = safe_id_segment($_GET["aulario"] ?? ""); $aulario_id = safe_id_segment($_GET["aulario"] ?? "");
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
$centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
if ($aulario_id === "" || $centro_id === "") { if ($aulario_id === "" || $centro_id === "") {
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
@@ -247,7 +249,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) {
if (!$exists) { if (!$exists) {
$menuTypes[] = ["id" => $newId, "label" => $newLabel, "color" => $newColor]; $menuTypes[] = ["id" => $newId, "label" => $newLabel, "color" => $newColor];
db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); 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)); header("Location: /aulatek/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($newId));
exit; exit;
} }
} }
@@ -261,7 +263,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) {
$menuTypes = $newMenuTypes; $menuTypes = $newMenuTypes;
db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes);
$redirectMenuId = !empty($menuTypes) ? $menuTypes[0]["id"] : "basal"; $redirectMenuId = !empty($menuTypes) ? $menuTypes[0]["id"] : "basal";
header("Location: /entreaulas/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($redirectMenuId)); header("Location: /aulatek/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($redirectMenuId));
exit; exit;
} }
} }
@@ -281,7 +283,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) {
} }
unset($t); unset($t);
db_set_comedor_menu_types($centro_id, $source_aulario_id, $menuTypes); 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)); header("Location: /aulatek/comedor.php?aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&menu=" . urlencode($renameId));
exit; exit;
} }
} }
@@ -293,7 +295,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $canEdit) {
} }
// Pictogram images still stored on filesystem in Comedor dir // Pictogram images still stored on filesystem in Comedor dir
$baseDir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$source_aulario_id/Comedor/$ym/$day"; $baseDir = aulatek_orgs_base_path() . "/$centro_id/Aularios/$source_aulario_id/Comedor/$ym/$day";
$plates = ["primero", "segundo", "postre"]; $plates = ["primero", "segundo", "postre"];
foreach ($plates as $plate) { foreach ($plates as $plate) {
$name = trim($_POST["name_" . $plate] ?? ""); $name = trim($_POST["name_" . $plate] ?? "");
@@ -318,13 +320,13 @@ function image_src($value, $centro_id, $source_aulario_id, $date)
if (filter_var($value, FILTER_VALIDATE_URL)) { if (filter_var($value, FILTER_VALIDATE_URL)) {
return $value; return $value;
} }
return "/entreaulas/_filefetch.php?type=comedor_image&centro=" . urlencode($centro_id) . "&aulario=" . urlencode($source_aulario_id) . "&date=" . urlencode($date) . "&file=" . urlencode($value); return "/aulatek/_filefetch.php?type=comedor_image&org=" . urlencode($centro_id) . "&aulario=" . urlencode($source_aulario_id) . "&date=" . urlencode($date) . "&file=" . urlencode($value);
} }
$prevDate = (clone $dateObj)->modify("-1 day")->format("Y-m-d"); $prevDate = (clone $dateObj)->modify("-1 day")->format("Y-m-d");
$nextDate = (clone $dateObj)->modify("+1 day")->format("Y-m-d"); $nextDate = (clone $dateObj)->modify("+1 day")->format("Y-m-d");
$userAulas = $_SESSION["auth_data"]["entreaulas"]["aulas"] ?? []; $userAulas = $tenant_data["aulas"] ?? [];
$aulaOptions = []; $aulaOptions = [];
foreach ($userAulas as $aulaId) { foreach ($userAulas as $aulaId) {
$aulaIdSafe = safe_id_segment($aulaId); $aulaIdSafe = safe_id_segment($aulaId);
@@ -365,9 +367,9 @@ require_once "_incl/pre-body.php";
<!-- Navigation Buttons - Single row --> <!-- Navigation Buttons - Single row -->
<div class="card pad"> <div class="card pad">
<div style="display: flex; gap: 10px; flex-wrap: wrap; align-items: center; justify-content: center; flex-direction: row;"> <div style="display: flex; gap: 10px; flex-wrap: wrap; align-items: center; justify-content: center; flex-direction: row;">
<a class="btn btn-outline-dark" href="/entreaulas/comedor.php?aulario=<?= urlencode($aulario_id) ?>&date=<?= urlencode($prevDate) ?>&menu=<?= urlencode($menuTypeId) ?>">⟵ Día anterior</a> <a class="btn btn-outline-dark" href="/aulatek/comedor.php?aulario=<?= urlencode($aulario_id) ?>&date=<?= urlencode($prevDate) ?>&menu=<?= urlencode($menuTypeId) ?>">⟵ Día anterior</a>
<input type="date" id="datePicker" class="form-control form-control-lg" value="<?= htmlspecialchars($date) ?>" style="max-width: 200px;"> <input type="date" id="datePicker" class="form-control form-control-lg" value="<?= htmlspecialchars($date) ?>" style="max-width: 200px;">
<a class="btn btn-outline-dark" href="/entreaulas/comedor.php?aulario=<?= urlencode($aulario_id) ?>&date=<?= urlencode($nextDate) ?>&menu=<?= urlencode($menuTypeId) ?>">Día siguiente ⟶</a> <a class="btn btn-outline-dark" href="/aulatek/comedor.php?aulario=<?= urlencode($aulario_id) ?>&date=<?= urlencode($nextDate) ?>&menu=<?= urlencode($menuTypeId) ?>">Día siguiente ⟶</a>
</div> </div>
<div style="margin-top: 10px; text-align: center;"> <div style="margin-top: 10px; text-align: center;">
<label for="aularioPicker" class="form-label" style="margin-right: 10px;">Aulario:</label> <label for="aularioPicker" class="form-label" style="margin-right: 10px;">Aulario:</label>
@@ -390,7 +392,7 @@ require_once "_incl/pre-body.php";
$isActive = ($type["id"] ?? "") === $menuTypeId; $isActive = ($type["id"] ?? "") === $menuTypeId;
$color = $type["color"] ?? "#0d6efd"; $color = $type["color"] ?? "#0d6efd";
?> ?>
<a href="/entreaulas/comedor.php?aulario=<?= urlencode($aulario_id) ?>&date=<?= urlencode($date) ?>&menu=<?= urlencode($type["id"]) ?>" <a href="/aulatek/comedor.php?aulario=<?= urlencode($aulario_id) ?>&date=<?= urlencode($date) ?>&menu=<?= urlencode($type["id"]) ?>"
class="btn btn-lg" style="background: <?= htmlspecialchars($color) ?>; color: white; border: 3px solid <?= $isActive ? "#000" : "transparent" ?>;"> class="btn btn-lg" style="background: <?= htmlspecialchars($color) ?>; color: white; border: 3px solid <?= $isActive ? "#000" : "transparent" ?>;">
<?= htmlspecialchars($type["label"] ?? $type["id"]) ?> <?= htmlspecialchars($type["label"] ?? $type["id"]) ?>
</a> </a>
@@ -615,7 +617,7 @@ require_once "_incl/pre-body.php";
params.set("date", dateValue); params.set("date", dateValue);
params.set("aulario", aularioValue); params.set("aulario", aularioValue);
params.set("menu", "<?= htmlspecialchars($menuTypeId) ?>"); params.set("menu", "<?= htmlspecialchars($menuTypeId) ?>");
window.location.href = "/entreaulas/comedor.php?" + params.toString(); window.location.href = "/aulatek/comedor.php?" + params.toString();
} }
if (datePicker) { if (datePicker) {
datePicker.addEventListener("change", goToSelection); datePicker.addEventListener("change", goToSelection);

View File

@@ -3,13 +3,15 @@ require_once "_incl/auth_redir.php";
require_once "../_incl/tools.security.php"; require_once "../_incl/tools.security.php";
// Check if user has docente permission // Check if user has docente permission
if (!in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? [])) { $permissions = $_SESSION["auth_data"]["permissions"] ?? [];
if (!in_array("aulatek:docente", $permissions, true) && !in_array("entreaulas:docente", $permissions, true)) {
header("HTTP/1.1 403 Forbidden"); header("HTTP/1.1 403 Forbidden");
die("Acceso denegado"); die("Acceso denegado");
} }
$aulario_id = safe_id_segment($_GET["aulario"] ?? ""); $aulario_id = safe_id_segment($_GET["aulario"] ?? "");
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
$centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
$alumno = safe_id_segment($_GET["alumno"] ?? ""); $alumno = safe_id_segment($_GET["alumno"] ?? "");
if (empty($aulario_id) || empty($centro_id)) { if (empty($aulario_id) || empty($centro_id)) {
@@ -25,7 +27,7 @@ if (empty($aulario_id) || empty($centro_id)) {
} }
// Validate paths with realpath // Validate paths with realpath
$base_path = "/DATA/entreaulas/Centros"; $base_path = aulatek_orgs_base_path();
$real_base = realpath($base_path); $real_base = realpath($base_path);
if ($real_base === false) { if ($real_base === false) {
@@ -77,7 +79,7 @@ if (empty($alumno)) {
<div class="card" style="padding: 0; overflow: hidden;"> <div class="card" style="padding: 0; overflow: hidden;">
<div style="background: #f8f9fa; padding: 15px; text-align: center;"> <div style="background: #f8f9fa; padding: 15px; text-align: center;">
<?php if ($photo_exists): ?> <?php if ($photo_exists): ?>
<img src="_filefetch.php?type=alumno_photo&alumno=<?= urlencode($alumno_name) ?>&centro=<?= urlencode($centro_id) ?>&aulario=<?= urlencode($aulario_id) ?>" <img src="_filefetch.php?type=alumno_photo&alumno=<?= urlencode($alumno_name) ?>&org=<?= urlencode($centro_id) ?>&aulario=<?= urlencode($aulario_id) ?>"
alt="Foto de <?= htmlspecialchars($alumno_name) ?>" alt="Foto de <?= htmlspecialchars($alumno_name) ?>"
style="width: 120px; height: 120px; object-fit: cover; border-radius: 10px; border: 3px solid #ddd;"> style="width: 120px; height: 120px; object-fit: cover; border-radius: 10px; border: 3px solid #ddd;">
<?php else: ?> <?php else: ?>

View File

@@ -16,8 +16,9 @@ require_once "../_incl/db.php";
<div id="grid"> <div id="grid">
<?php <?php
$user_data = $_SESSION["auth_data"]; $user_data = $_SESSION["auth_data"];
$centro_id = safe_centro_id($user_data["entreaulas"]["centro"] ?? ""); $tenant_data = $user_data["aulatek"] ?? ($user_data["entreaulas"] ?? []);
$user_aulas = $user_data["entreaulas"]["aulas"] ?? []; $centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
$user_aulas = $tenant_data["aulas"] ?? [];
foreach ($user_aulas as $aulario_id) { foreach ($user_aulas as $aulario_id) {
$aulario_id = safe_id_segment($aulario_id); $aulario_id = safe_id_segment($aulario_id);
if ($aulario_id === "") { if ($aulario_id === "") {
@@ -29,14 +30,14 @@ require_once "../_incl/db.php";
} }
$aulario_name = $aulario["name"] ?? $aulario_id; $aulario_name = $aulario["name"] ?? $aulario_id;
$aulario_icon = $aulario["icon"] ?? "/static/arasaac/aulario.png"; $aulario_icon = $aulario["icon"] ?? "/static/arasaac/aulario.png";
echo '<a href="/entreaulas/aulario.php?id=' . urlencode($aulario_id) . '" class="btn btn-primary grid-item"> echo '<a href="/aulatek/aulario.php?id=' . urlencode($aulario_id) . '" class="btn btn-primary grid-item">
<img style="height: 125px;" src="' . htmlspecialchars($aulario_icon, ENT_QUOTES) . '" alt="' . htmlspecialchars($aulario_name) . ' Icono"> <img style="height: 125px;" src="' . htmlspecialchars($aulario_icon, ENT_QUOTES) . '" alt="' . htmlspecialchars($aulario_name) . ' Icono">
<br> <br>
' . htmlspecialchars($aulario_name) . ' ' . htmlspecialchars($aulario_name) . '
</a>'; </a>';
} ?> } ?>
<?php if (in_array('supercafe:access', $_SESSION['auth_data']['permissions'] ?? [])): ?> <?php if (in_array('supercafe:access', $_SESSION['auth_data']['permissions'] ?? [])): ?>
<a href="/entreaulas/supercafe.php" class="btn btn-warning grid-item"> <a href="/aulatek/supercafe.php" class="btn btn-warning grid-item">
<img src="/static/iconexperience/purchase_order_cart.png" height="125" <img src="/static/iconexperience/purchase_order_cart.png" height="125"
style="background: white; padding: 5px; border-radius: 10px;" style="background: white; padding: 5px; border-radius: 10px;"
alt="Icono SuperCafe"> alt="Icono SuperCafe">

View File

@@ -9,8 +9,8 @@ function getDiarioPath($alumno, $centro_id, $aulario_id) {
// Validate path components to avoid directory traversal or illegal characters // Validate path components to avoid directory traversal or illegal characters
// Allow only alphanumeric, underscore and dash for alumno and aulario_id // Allow only alphanumeric, underscore and dash for alumno and aulario_id
$idPattern = '/^[A-Za-z0-9_-]+$/'; $idPattern = '/^[A-Za-z0-9_-]+$/';
// Typically centro_id is numeric; restrict it accordingly // Organization id may include letters, numbers, dots, underscores and dashes.
$centroPattern = '/^[0-9]+$/'; $centroPattern = '/^[A-Za-z0-9._-]+$/';
if (!preg_match($idPattern, (string)$alumno) || if (!preg_match($idPattern, (string)$alumno) ||
!preg_match($idPattern, (string)$aulario_id) || !preg_match($idPattern, (string)$aulario_id) ||
@@ -24,10 +24,12 @@ function getDiarioPath($alumno, $centro_id, $aulario_id) {
$centro_safe = basename($centro_id); $centro_safe = basename($centro_id);
$aulario_safe = basename($aulario_id); $aulario_safe = basename($aulario_id);
$base_path = "/DATA/entreaulas/Centros/$centro_safe/Aularios/$aulario_safe/Alumnos/$alumno_safe"; $base_path = aulatek_orgs_base_path() . "/$centro_safe/Aularios/$aulario_safe/Alumnos/$alumno_safe";
return $base_path . "/Diario/" . date("Y-m-d"); return $base_path . "/Diario/" . date("Y-m-d");
} }
$tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
function initDiario($alumno, $centro_id, $aulario_id) { function initDiario($alumno, $centro_id, $aulario_id) {
$diario_path = getDiarioPath($alumno, $centro_id, $aulario_id); $diario_path = getDiarioPath($alumno, $centro_id, $aulario_id);
if ($diario_path) { if ($diario_path) {
@@ -73,14 +75,14 @@ function guardarPanelDiario($panel_name, $data, $alumno, $centro_id, $aulario_id
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_GET['api'])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_GET['api'])) {
header('Content-Type: application/json'); header('Content-Type: application/json');
$api_action = $_GET['api']; $api_action = $_GET['api'];
$alumno = $_SESSION["entreaulas_selected_alumno"] ?? ''; $alumno = $_SESSION["aulatek_selected_alumno"] ?? ($_SESSION["entreaulas_selected_alumno"] ?? '');
$centro_id = $_SESSION["auth_data"]["entreaulas"]["centro"] ?? ''; $centro_id = $tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? '');
if ($api_action === 'guardar_panel' && $alumno && $centro_id) { if ($api_action === 'guardar_panel' && $alumno && $centro_id) {
$input = json_decode(file_get_contents('php://input'), true); $input = json_decode(file_get_contents('php://input'), true);
$panel_name = $input['panel'] ?? ''; $panel_name = $input['panel'] ?? '';
$panel_data = $input['data'] ?? []; $panel_data = $input['data'] ?? [];
$aulario_id = $_SESSION["entreaulas_selected_aulario"] ?? ''; $aulario_id = $_SESSION["aulatek_selected_aulario"] ?? ($_SESSION["entreaulas_selected_aulario"] ?? '');
guardarPanelDiario($panel_name, $panel_data, $alumno, $centro_id, $aulario_id); guardarPanelDiario($panel_name, $panel_data, $alumno, $centro_id, $aulario_id);
echo json_encode(['success' => true]); echo json_encode(['success' => true]);
die(); die();
@@ -91,10 +93,12 @@ $form_action = $_GET["form"] ?? "";
switch ($form_action) { switch ($form_action) {
case "alumno_selected": case "alumno_selected":
$alumno = safe_id_segment($_GET["alumno"] ?? ""); $alumno = safe_id_segment($_GET["alumno"] ?? "");
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
$aulario_id = safe_id_segment($_GET["aulario"] ?? ''); $aulario_id = safe_id_segment($_GET["aulario"] ?? '');
$photo_url = $_GET["photo"] ?? ''; $photo_url = $_GET["photo"] ?? '';
if ($alumno !== "" && $centro_id !== "" && $aulario_id !== "") { if ($alumno !== "" && $centro_id !== "" && $aulario_id !== "") {
$_SESSION["aulatek_selected_alumno"] = $alumno;
$_SESSION["aulatek_selected_aulario"] = $aulario_id;
$_SESSION["entreaulas_selected_alumno"] = $alumno; $_SESSION["entreaulas_selected_alumno"] = $alumno;
$_SESSION["entreaulas_selected_aulario"] = $aulario_id; $_SESSION["entreaulas_selected_aulario"] = $aulario_id;
initDiario($alumno, $centro_id, $aulario_id); initDiario($alumno, $centro_id, $aulario_id);
@@ -209,8 +213,8 @@ ini_set("display_errors", "0");
</script> </script>
<?php <?php
// Verificar si hay un alumno seleccionado y cargar su progreso // Verificar si hay un alumno seleccionado y cargar su progreso
$alumno_actual = $_SESSION["entreaulas_selected_alumno"] ?? ''; $alumno_actual = $_SESSION["aulatek_selected_alumno"] ?? ($_SESSION["entreaulas_selected_alumno"] ?? '');
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ''); $centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ''));
$aulario_id = safe_id_segment($_GET["aulario"] ?? ''); $aulario_id = safe_id_segment($_GET["aulario"] ?? '');
$diario_data = null; $diario_data = null;
@@ -604,7 +608,7 @@ switch ($view_action) {
case "quien_soy": case "quien_soy":
// ¿Quién soy? - Identificación del alumno // ¿Quién soy? - Identificación del alumno
$aulario_id = safe_id_segment($_GET["aulario"] ?? ''); $aulario_id = safe_id_segment($_GET["aulario"] ?? '');
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ''); $centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ''));
// Validate parameters // Validate parameters
if (empty($aulario_id) || empty($centro_id)) { if (empty($aulario_id) || empty($centro_id)) {
@@ -612,7 +616,7 @@ switch ($view_action) {
break; break;
} }
$base_path = "/DATA/entreaulas/Centros"; $base_path = aulatek_orgs_base_path();
$alumnos_path = "$base_path/$centro_id/Aularios/$aulario_id/Alumnos"; $alumnos_path = "$base_path/$centro_id/Aularios/$aulario_id/Alumnos";
// Validate the path is within the expected directory // Validate the path is within the expected directory
@@ -629,12 +633,12 @@ switch ($view_action) {
element.style.backgroundColor = "#9cff9f"; // Verde element.style.backgroundColor = "#9cff9f"; // Verde
let photoUrl = ''; let photoUrl = '';
if (hasPhoto) { if (hasPhoto) {
photoUrl = '/entreaulas/_filefetch.php?type=alumno_photo&alumno=' + encodeURIComponent(nombre) + photoUrl = '/aulatek/_filefetch.php?type=alumno_photo&alumno=' + encodeURIComponent(nombre) +
'&centro=' + encodeURIComponent(centro) + '&aulario=' + encodeURIComponent(aulario); '&centro=' + encodeURIComponent(centro) + '&aulario=' + encodeURIComponent(aulario);
} }
announceAndMaybeRedirect( announceAndMaybeRedirect(
"¡Hola " + nombre + "!", "¡Hola " + nombre + "!",
"/entreaulas/paneldiario.php?aulario=" + encodeURIComponent(aulario) + "&form=alumno_selected&alumno=" + encodeURIComponent(nombre) + "/aulatek/paneldiario.php?aulario=" + encodeURIComponent(aulario) + "&form=alumno_selected&alumno=" + encodeURIComponent(nombre) +
(photoUrl ? "&photo=" + encodeURIComponent(photoUrl) : ''), (photoUrl ? "&photo=" + encodeURIComponent(photoUrl) : ''),
true true
); );
@@ -662,7 +666,7 @@ switch ($view_action) {
?> ?>
<a href="#" class="card grid-item" style="color: black;" onclick='seleccionarAlumno(this, "<?php echo htmlspecialchars($alumno_name, ENT_QUOTES); ?>", <?php echo $photo_exists ? 'true' : 'false'; ?>, "<?php echo htmlspecialchars($centro_id, ENT_QUOTES); ?>", "<?php echo htmlspecialchars($aulario_id, ENT_QUOTES); ?>");' aria-label="Seleccionar alumno <?php echo htmlspecialchars($alumno_name); ?>"> <a href="#" class="card grid-item" style="color: black;" onclick='seleccionarAlumno(this, "<?php echo htmlspecialchars($alumno_name, ENT_QUOTES); ?>", <?php echo $photo_exists ? 'true' : 'false'; ?>, "<?php echo htmlspecialchars($centro_id, ENT_QUOTES); ?>", "<?php echo htmlspecialchars($aulario_id, ENT_QUOTES); ?>");' aria-label="Seleccionar alumno <?php echo htmlspecialchars($alumno_name); ?>">
<?php if ($photo_exists): ?> <?php if ($photo_exists): ?>
<img src="_filefetch.php?type=alumno_photo&alumno=<?php echo urlencode($alumno_name); ?>&centro=<?php echo urlencode($centro_id); ?>&aulario=<?php echo urlencode($aulario_id); ?>" height="150" class="bg-white" alt="Foto de <?php echo htmlspecialchars($alumno_name); ?>"> <img src="_filefetch.php?type=alumno_photo&alumno=<?php echo urlencode($alumno_name); ?>&org=<?php echo urlencode($centro_id); ?>&aulario=<?php echo urlencode($aulario_id); ?>" height="150" class="bg-white" alt="Foto de <?php echo htmlspecialchars($alumno_name); ?>">
<?php else: ?> <?php else: ?>
<div style="width: 150px; height: 150px; background: #f0f0f0; display: flex; align-items: center; justify-content: center; border-radius: 10px; border: 2px dashed #ccc;"> <div style="width: 150px; height: 150px; background: #f0f0f0; display: flex; align-items: center; justify-content: center; border-radius: 10px; border: 2px dashed #ccc;">
<span style="font-size: 48px;">?</span> <span style="font-size: 48px;">?</span>
@@ -705,10 +709,10 @@ switch ($view_action) {
<?php <?php
break; break;
case "actividades": case "actividades":
$centro_actividades = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ''); $centro_actividades = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ''));
$actividades = []; $actividades = [];
if ($centro_actividades !== '') { if ($centro_actividades !== '') {
$actividades_path = "/DATA/entreaulas/Centros/$centro_actividades/Panel/Actividades"; $actividades_path = aulatek_orgs_base_path() . "/$centro_actividades/Panel/Actividades";
if (is_dir($actividades_path)) { if (is_dir($actividades_path)) {
$actividades = glob($actividades_path . "/*", GLOB_ONLYDIR) ?: []; $actividades = glob($actividades_path . "/*", GLOB_ONLYDIR) ?: [];
} }
@@ -719,7 +723,7 @@ switch ($view_action) {
element.style.backgroundColor = "#9cff9f"; // Verde element.style.backgroundColor = "#9cff9f"; // Verde
// Guardar al diario antes de redirigir // Guardar al diario antes de redirigir
fetch('/entreaulas/paneldiario.php?api=guardar_panel', { fetch('/aulatek/paneldiario.php?api=guardar_panel', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -732,7 +736,7 @@ switch ($view_action) {
}).finally(() => { }).finally(() => {
announceAndMaybeRedirect( announceAndMaybeRedirect(
actividad + ", Actividad seleccionada", actividad + ", Actividad seleccionada",
"/entreaulas/paneldiario.php?aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>", "/aulatek/paneldiario.php?aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>",
true true
); );
}); });
@@ -746,7 +750,7 @@ switch ($view_action) {
<div class="grid"> <div class="grid">
<?php foreach ($actividades as $actividad_path) { <?php foreach ($actividades as $actividad_path) {
$actividad_name = basename($actividad_path); $actividad_name = basename($actividad_path);
$pictogram_url = '/entreaulas/_filefetch.php?type=panel_actividades&activity=' . urlencode($actividad_name) . '&centro=' . urlencode($centro_actividades); $pictogram_url = '/aulatek/_filefetch.php?type=panel_actividades&activity=' . urlencode($actividad_name) . '&org=' . urlencode($centro_actividades);
?> ?>
<a class="card grid-item" style="color: black;" onclick="seleccionarActividad(this, '<?php echo htmlspecialchars($actividad_name); ?>', '<?php echo htmlspecialchars($pictogram_url); ?>');"> <a class="card grid-item" style="color: black;" onclick="seleccionarActividad(this, '<?php echo htmlspecialchars($actividad_name); ?>', '<?php echo htmlspecialchars($pictogram_url); ?>');">
<img src="<?php echo htmlspecialchars($pictogram_url); ?>" height="125" class="bg-white"> <img src="<?php echo htmlspecialchars($pictogram_url); ?>" height="125" class="bg-white">
@@ -780,7 +784,7 @@ switch ($view_action) {
case "menu": case "menu":
// Menú del comedor (nuevo sistema, vista simplificada) // Menú del comedor (nuevo sistema, vista simplificada)
$aulario_id = safe_id_segment($_GET["aulario"] ?? ''); $aulario_id = safe_id_segment($_GET["aulario"] ?? '');
$centro_id = safe_centro_id($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $centro_id = safe_organization_id($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
$source_aulario_id = $aulario_id; $source_aulario_id = $aulario_id;
$is_shared = false; $is_shared = false;
@@ -837,7 +841,7 @@ switch ($view_action) {
if (!$value) { if (!$value) {
return ""; return "";
} }
return "/entreaulas/_filefetch.php?type=comedor_image&centro=" . urlencode($centro_id) . "&aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&file=" . urlencode($value); return "/aulatek/_filefetch.php?type=comedor_image&org=" . urlencode($centro_id) . "&aulario=" . urlencode($aulario_id) . "&date=" . urlencode($date) . "&file=" . urlencode($value);
} }
?> ?>
<script> <script>
@@ -845,7 +849,7 @@ switch ($view_action) {
element.style.backgroundColor = "#9cff9f"; // Verde element.style.backgroundColor = "#9cff9f"; // Verde
// Guardar al diario antes de redirigir // Guardar al diario antes de redirigir
fetch('/entreaulas/paneldiario.php?api=guardar_panel', { fetch('/aulatek/paneldiario.php?api=guardar_panel', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -855,7 +859,7 @@ switch ($view_action) {
}).finally(() => { }).finally(() => {
announceAndMaybeRedirect( announceAndMaybeRedirect(
menu_ty + ", Menú seleccionado", menu_ty + ", Menú seleccionado",
"/entreaulas/paneldiario.php?aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>", "/aulatek/paneldiario.php?aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>",
true true
); );
}); });
@@ -1028,7 +1032,7 @@ switch ($view_action) {
element.style.backgroundColor = "#9cff9f"; // Verde element.style.backgroundColor = "#9cff9f"; // Verde
// Guardar al diario antes de redirigir // Guardar al diario antes de redirigir
fetch('/entreaulas/paneldiario.php?api=guardar_panel', { fetch('/aulatek/paneldiario.php?api=guardar_panel', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -1136,7 +1140,7 @@ switch ($view_action) {
element.style.backgroundColor = "#9cff9f"; // Verde element.style.backgroundColor = "#9cff9f"; // Verde
// Guardar al diario antes de redirigir // Guardar al diario antes de redirigir
fetch('/entreaulas/paneldiario.php?api=guardar_panel', { fetch('/aulatek/paneldiario.php?api=guardar_panel', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -1146,7 +1150,7 @@ switch ($view_action) {
}).finally(() => { }).finally(() => {
announceAndMaybeRedirect( announceAndMaybeRedirect(
dow[ds] + ", Correcto", dow[ds] + ", Correcto",
"/entreaulas/paneldiario.php?action=calendario_mes&aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>", "/aulatek/paneldiario.php?action=calendario_mes&aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>",
true true
); );
}); });
@@ -1254,7 +1258,7 @@ switch ($view_action) {
element.style.backgroundColor = "#9cff9f"; // Verde element.style.backgroundColor = "#9cff9f"; // Verde
// Guardar al diario antes de redirigir // Guardar al diario antes de redirigir
fetch('/entreaulas/paneldiario.php?api=guardar_panel', { fetch('/aulatek/paneldiario.php?api=guardar_panel', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -1264,7 +1268,7 @@ switch ($view_action) {
}).finally(() => { }).finally(() => {
announceAndMaybeRedirect( announceAndMaybeRedirect(
meses[mes] + ", Correcto", meses[mes] + ", Correcto",
"/entreaulas/paneldiario.php?aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>", "/aulatek/paneldiario.php?aulario=<?php echo urlencode($_GET['aulario'] ?? ''); ?>",
true true
); );
}); });

View File

@@ -8,7 +8,7 @@ $is_valid = false;
if ($file !== "") { if ($file !== "") {
$parsed = parse_url($file); $parsed = parse_url($file);
if (!isset($parsed["scheme"]) && !isset($parsed["host"])) { if (!isset($parsed["scheme"]) && !isset($parsed["host"])) {
if (strpos($file, "/entreaulas/_filefetch.php") === 0) { if (strpos($file, "/aulatek/_filefetch.php") === 0) {
$is_valid = true; $is_valid = true;
} }
} }

View File

@@ -3,13 +3,15 @@ require_once "_incl/auth_redir.php";
require_once "../_incl/tools.security.php"; require_once "../_incl/tools.security.php";
require_once "../_incl/db.php"; require_once "../_incl/db.php";
if (in_array("entreaulas:docente", $_SESSION["auth_data"]["permissions"] ?? []) === false) { $permissions = $_SESSION["auth_data"]["permissions"] ?? [];
if (!in_array("aulatek:docente", $permissions, true) && !in_array("entreaulas:docente", $permissions, true)) {
header("HTTP/1.1 403 Forbidden"); header("HTTP/1.1 403 Forbidden");
die("Access denied"); die("Access denied");
} }
$aulario_id = safe_path_segment($_GET["aulario"] ?? ""); $aulario_id = safe_path_segment($_GET["aulario"] ?? "");
$centro_id = safe_path_segment($_SESSION["auth_data"]["entreaulas"]["centro"] ?? ""); $tenant_data = $_SESSION["auth_data"]["aulatek"] ?? ($_SESSION["auth_data"]["entreaulas"] ?? []);
$centro_id = safe_path_segment($tenant_data["organizacion"] ?? ($tenant_data["centro"] ?? ""));
// Validate centro_id and aulario_id to prevent directory traversal // Validate centro_id and aulario_id to prevent directory traversal
if ($aulario_id === "" || $centro_id === "") { if ($aulario_id === "" || $centro_id === "") {
@@ -26,7 +28,7 @@ if ($aulario_id === "" || $centro_id === "") {
$aulario = db_get_aulario($centro_id, $aulario_id); $aulario = db_get_aulario($centro_id, $aulario_id);
$proyectos_dir = "/DATA/entreaulas/Centros/$centro_id/Proyectos"; $proyectos_dir = aulatek_orgs_base_path() . "/$centro_id/Proyectos";
if (!is_dir($proyectos_dir)) { if (!is_dir($proyectos_dir)) {
mkdir($proyectos_dir, 0755, true); mkdir($proyectos_dir, 0755, true);
} }
@@ -357,7 +359,7 @@ function get_linked_projects($aulario, $centro_id)
continue; continue;
} }
$projects_base = "/DATA/entreaulas/Centros/$centro_id/Proyectos"; $projects_base = aulatek_orgs_base_path() . "/$centro_id/Proyectos";
$project = load_project($projects_base, $project_id); $project = load_project($projects_base, $project_id);
if ($project && ($project["parent_id"] ?? null) === null) { if ($project && ($project["parent_id"] ?? null) === null) {
// Mark as linked and add source info // Mark as linked and add source info
@@ -440,7 +442,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
} }
} }
header("Location: /entreaulas/proyectos.php?aulario=" . urlencode($aulario_id) . "&project=" . urlencode($project_id)); header("Location: /aulatek/proyectos.php?aulario=" . urlencode($aulario_id) . "&project=" . urlencode($project_id));
exit; exit;
} }
} else { } else {
@@ -494,7 +496,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
} }
} }
db()->prepare( db()->prepare(
"UPDATE aularios SET extra = ? WHERE centro_id = ? AND aulario_id = ?" "UPDATE aularios SET extra = ? WHERE org_id = ? AND aulario_id = ?"
)->execute([json_encode($extra, JSON_UNESCAPED_UNICODE), $centro_id, $target_aulario]); )->execute([json_encode($extra, JSON_UNESCAPED_UNICODE), $centro_id, $target_aulario]);
} }
} }
@@ -502,7 +504,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
} }
if ($action === "delete_project") { if ($action === "delete_project") {
if (in_array("entreaulas:proyectos:delete", $_SESSION["auth_data"]["permissions"] ?? []) === false) { if (!in_array("aulatek:proyectos:delete", $permissions, true) && !in_array("entreaulas:proyectos:delete", $permissions, true)) {
$error = "No tienes permisos para borrar proyectos."; $error = "No tienes permisos para borrar proyectos.";
} else { } else {
$project_id = safe_path_segment($_POST["project_id"] ?? ""); $project_id = safe_path_segment($_POST["project_id"] ?? "");
@@ -761,7 +763,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (!empty($source_aulario_param)) { if (!empty($source_aulario_param)) {
$redirect_params .= "&source=" . urlencode($source_aulario_param); $redirect_params .= "&source=" . urlencode($source_aulario_param);
} }
header("Location: /entreaulas/proyectos.php?" . $redirect_params); header("Location: /aulatek/proyectos.php?" . $redirect_params);
exit; exit;
} }
} }
@@ -1025,7 +1027,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (!empty($source_aulario_param)) { if (!empty($source_aulario_param)) {
$redirect_params .= "&source=" . urlencode($source_aulario_param); $redirect_params .= "&source=" . urlencode($source_aulario_param);
} }
header("Location: /entreaulas/proyectos.php?" . $redirect_params); header("Location: /aulatek/proyectos.php?" . $redirect_params);
exit; exit;
} }
} }
@@ -1055,7 +1057,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (!empty($source_aulario_param)) { if (!empty($source_aulario_param)) {
$redirect_params .= "&source=" . urlencode($source_aulario_param); $redirect_params .= "&source=" . urlencode($source_aulario_param);
} }
header("Location: /entreaulas/proyectos.php?" . $redirect_params); header("Location: /aulatek/proyectos.php?" . $redirect_params);
exit; exit;
} }
} }
@@ -1175,7 +1177,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (!empty($source_aulario_param)) { if (!empty($source_aulario_param)) {
$redirect_params .= "&source=" . urlencode($source_aulario_param); $redirect_params .= "&source=" . urlencode($source_aulario_param);
} }
header("Location: /entreaulas/proyectos.php?" . $redirect_params); header("Location: /aulatek/proyectos.php?" . $redirect_params);
exit; exit;
} }
} }
@@ -1377,11 +1379,11 @@ $view = $current_project ? "project" : "list";
</p> </p>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<?php if ($is_linked): ?> <?php if ($is_linked): ?>
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($project["id"]) ?>&source=<?= urlencode($source_aulario) ?>" class="btn btn-primary"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($project["id"]) ?>&source=<?= urlencode($source_aulario) ?>" class="btn btn-primary">
Abrir Abrir
</a> </a>
<?php else: ?> <?php else: ?>
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($project["id"]) ?>" class="btn btn-primary"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($project["id"]) ?>" class="btn btn-primary">
Abrir Abrir
</a> </a>
<!-- Delete --> <!-- Delete -->
@@ -1471,7 +1473,7 @@ $view = $current_project ? "project" : "list";
$linked_permission = $link["permission"] ?? "read_only"; $linked_permission = $link["permission"] ?? "read_only";
break; break;
} }
$project_source_dir = "/DATA/entreaulas/Centros/$centro_id/Proyectos"; $project_source_dir = aulatek_orgs_base_path() . "/$centro_id/Proyectos";
$breadcrumb_check = get_project_breadcrumb($project_source_dir, $current_project); $breadcrumb_check = get_project_breadcrumb($project_source_dir, $current_project);
foreach ($breadcrumb_check as $crumb) { foreach ($breadcrumb_check as $crumb) {
if (($crumb["id"] ?? "") === $link_root_id) { if (($crumb["id"] ?? "") === $link_root_id) {
@@ -1484,7 +1486,7 @@ $view = $current_project ? "project" : "list";
if ($valid_link) { if ($valid_link) {
$is_linked_project = true; $is_linked_project = true;
$project_source_dir = "/DATA/entreaulas/Centros/$centro_id/Proyectos"; $project_source_dir = aulatek_orgs_base_path() . "/$centro_id/Proyectos";
$project = load_project($project_source_dir, $current_project); $project = load_project($project_source_dir, $current_project);
} else { } else {
// Invalid link configuration, treat as local project // Invalid link configuration, treat as local project
@@ -1508,7 +1510,7 @@ $view = $current_project ? "project" : "list";
<div class="card pad"> <div class="card pad">
<h1>Error</h1> <h1>Error</h1>
<p>Proyecto no encontrado.</p> <p>Proyecto no encontrado.</p>
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-primary">Volver a Proyectos</a> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-primary">Volver a Proyectos</a>
</div> </div>
<?php <?php
require_once "_incl/post-body.php"; require_once "_incl/post-body.php";
@@ -1528,12 +1530,12 @@ $view = $current_project ? "project" : "list";
<div class="card pad"> <div class="card pad">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>">Proyectos</a> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>">Proyectos</a>
</li> </li>
<?php foreach ($breadcrumb as $idx => $crumb): ?> <?php foreach ($breadcrumb as $idx => $crumb): ?>
<?php if ($idx < count($breadcrumb) - 1): ?> <?php if ($idx < count($breadcrumb) - 1): ?>
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($crumb["id"]) ?><?= $is_linked_project ? "&source=" . urlencode($source_aulario_for_project) : "" ?>"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($crumb["id"]) ?><?= $is_linked_project ? "&source=" . urlencode($source_aulario_for_project) : "" ?>">
<?= htmlspecialchars($crumb["name"]) ?> <?= htmlspecialchars($crumb["name"]) ?>
</a> </a>
</li> </li>
@@ -1581,11 +1583,11 @@ $view = $current_project ? "project" : "list";
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<?php if (!empty($project["parent_id"])): ?> <?php if (!empty($project["parent_id"])): ?>
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($project["parent_id"]) ?><?= $is_linked_project ? "&source=" . urlencode($source_aulario_for_project) : "" ?>" class="btn btn-secondary"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($project["parent_id"]) ?><?= $is_linked_project ? "&source=" . urlencode($source_aulario_for_project) : "" ?>" class="btn btn-secondary">
← Volver al Proyecto ← Volver al Proyecto
</a> </a>
<?php else: ?> <?php else: ?>
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-secondary"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>" class="btn btn-secondary">
← Volver al Listado ← Volver al Listado
</a> </a>
<?php endif; ?> <?php endif; ?>
@@ -1709,7 +1711,7 @@ $view = $current_project ? "project" : "list";
</small> </small>
</p> </p>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="/entreaulas/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($subproject["id"]) ?><?= $is_linked_project ? "&source=" . urlencode($source_aulario_for_project) : "" ?>" class="btn btn-primary"> <a href="/aulatek/proyectos.php?aulario=<?= urlencode($aulario_id) ?>&project=<?= urlencode($subproject["id"]) ?><?= $is_linked_project ? "&source=" . urlencode($source_aulario_for_project) : "" ?>" class="btn btn-primary">
Abrir Abrir
</a> </a>
<?php if (!$is_linked_project || ($is_linked_project && $linked_permission === "full_edit")): ?> <?php if (!$is_linked_project || ($is_linked_project && $linked_permission === "full_edit")): ?>
@@ -1814,7 +1816,7 @@ $view = $current_project ? "project" : "list";
<?php elseif ($item["type"] === "pdf_secure"): ?> <?php elseif ($item["type"] === "pdf_secure"): ?>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#viewPdfSecureModal" <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#viewPdfSecureModal"
data-item-name="<?= htmlspecialchars($item["name"], ENT_QUOTES) ?>" data-item-name="<?= htmlspecialchars($item["name"], ENT_QUOTES) ?>"
data-file-url="/entreaulas/_filefetch.php?type=proyecto_file&centro=<?= urlencode($centro_id) ?>&project=<?= urlencode($current_project) ?>&file=<?= urlencode($item["filename"]) ?>"> data-file-url="/aulatek/_filefetch.php?type=proyecto_file&org=<?= urlencode($centro_id) ?>&project=<?= urlencode($current_project) ?>&file=<?= urlencode($item["filename"]) ?>">
Abrir Abrir
</button> </button>
<?php elseif ($item["type"] === "videocall"): ?> <?php elseif ($item["type"] === "videocall"): ?>
@@ -1828,7 +1830,7 @@ $view = $current_project ? "project" : "list";
Abrir Abrir
</button> </button>
<?php else: ?> <?php else: ?>
<a href="/entreaulas/_filefetch.php?type=proyecto_file&centro=<?= urlencode($centro_id) ?>&project=<?= urlencode($current_project) ?>&file=<?= urlencode($item["filename"]) ?>" target="_blank" class="btn btn-primary"> <a href="/aulatek/_filefetch.php?type=proyecto_file&org=<?= urlencode($centro_id) ?>&project=<?= urlencode($current_project) ?>&file=<?= urlencode($item["filename"]) ?>" target="_blank" class="btn btn-primary">
Abrir Abrir
</a> </a>
<?php endif; ?> <?php endif; ?>
@@ -2558,7 +2560,7 @@ $view = $current_project ? "project" : "list";
var title = button.getAttribute('data-item-name') || 'PDF Seguro'; var title = button.getAttribute('data-item-name') || 'PDF Seguro';
var url = button.getAttribute('data-file-url') || ''; var url = button.getAttribute('data-file-url') || '';
document.getElementById('viewPdfSecureModalLabel').textContent = title; document.getElementById('viewPdfSecureModalLabel').textContent = title;
document.getElementById('pdf_secure_frame').src = url ? ('/entreaulas/pdf_secure_viewer.php?file=' + encodeURIComponent(url)) : ''; document.getElementById('pdf_secure_frame').src = url ? ('/aulatek/pdf_secure_viewer.php?file=' + encodeURIComponent(url)) : '';
}); });
viewPdfSecureModal.addEventListener('hidden.bs.modal', function() { viewPdfSecureModal.addEventListener('hidden.bs.modal', function() {
document.getElementById('pdf_secure_frame').src = ''; document.getElementById('pdf_secure_frame').src = '';

View File

@@ -16,7 +16,7 @@ function sc_load_personas_from_alumnos($centro_id)
{ {
$aularios = db_get_aularios($centro_id); $aularios = db_get_aularios($centro_id);
$personas = []; $personas = [];
$aularios_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios"; $aularios_dir = aulatek_orgs_base_path() . "/$centro_id/Aularios";
foreach ($aularios as $aulario_id => $aulario_data) { foreach ($aularios as $aulario_id => $aulario_data) {
$aulario_name = $aulario_data['name'] ?? $aulario_id; $aulario_name = $aulario_data['name'] ?? $aulario_id;
$alumnos_path = "$aularios_dir/$aulario_id/Alumnos"; $alumnos_path = "$aularios_dir/$aulario_id/Alumnos";
@@ -50,10 +50,11 @@ function sc_persona_label($persona_key, $personas)
return $persona_key; return $persona_key;
} }
$centro_id = safe_centro_id($_SESSION['auth_data']['entreaulas']['centro'] ?? ''); $tenant_data = $_SESSION['auth_data']['aulatek'] ?? ($_SESSION['auth_data']['entreaulas'] ?? []);
$centro_id = safe_organization_id($tenant_data['organizacion'] ?? ($tenant_data['centro'] ?? ''));
if ($centro_id === '') { if ($centro_id === '') {
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
echo '<div class="card pad"><h1>SuperCafe</h1><p>No tienes un centro asignado.</p></div>'; echo '<div class="card pad"><h1>SuperCafe</h1><p>No tienes una organizacion asignada.</p></div>';
require_once "_incl/post-body.php"; require_once "_incl/post-body.php";
exit; exit;
} }
@@ -87,17 +88,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $can_edit) {
); );
} }
} }
header('Location: /entreaulas/supercafe.php'); header('Location: /aulatek/supercafe.php');
exit; exit;
} }
if ($action === 'delete') { if ($action === 'delete') {
$order_id = safe_id($_POST['order_id'] ?? ''); $order_id = safe_id($_POST['order_id'] ?? '');
if ($order_id !== '') { if ($order_id !== '') {
db()->prepare('DELETE FROM supercafe_orders WHERE centro_id = ? AND order_ref = ?') db()->prepare('DELETE FROM supercafe_orders WHERE org_id = ? AND order_ref = ?')
->execute([$centro_id, $order_id]); ->execute([$centro_id, $order_id]);
} }
header('Location: /entreaulas/supercafe.php'); header('Location: /aulatek/supercafe.php');
exit; exit;
} }
} }
@@ -130,7 +131,7 @@ require_once "_incl/pre-body.php";
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;"> <div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;">
<h1 style="margin: 0;">SuperCafe Cafetería</h1> <h1 style="margin: 0;">SuperCafe Cafetería</h1>
<?php if ($can_edit): ?> <?php if ($can_edit): ?>
<a href="/entreaulas/supercafe_edit.php" class="btn btn-success">+ Nueva comanda</a> <a href="/aulatek/supercafe_edit.php" class="btn btn-success">+ Nueva comanda</a>
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>
@@ -170,7 +171,7 @@ require_once "_incl/pre-body.php";
<td><strong><?= htmlspecialchars($estado) ?></strong></td> <td><strong><?= htmlspecialchars($estado) ?></strong></td>
<?php if ($can_edit): ?> <?php if ($can_edit): ?>
<td style="white-space: nowrap;"> <td style="white-space: nowrap;">
<a href="/entreaulas/supercafe_edit.php?id=<?= urlencode($order['_id']) ?>" <a href="/aulatek/supercafe_edit.php?id=<?= urlencode($order['_id']) ?>"
class="btn btn-sm btn-primary">Editar</a> class="btn btn-sm btn-primary">Editar</a>
<form method="post" style="display: inline;"> <form method="post" style="display: inline;">
<input type="hidden" name="action" value="change_status"> <input type="hidden" name="action" value="change_status">
@@ -233,7 +234,7 @@ require_once "_incl/pre-body.php";
<td><?= htmlspecialchars($order['Notas'] ?? '') ?></td> <td><?= htmlspecialchars($order['Notas'] ?? '') ?></td>
<?php if ($can_edit): ?> <?php if ($can_edit): ?>
<td style="white-space: nowrap;"> <td style="white-space: nowrap;">
<a href="/entreaulas/supercafe_edit.php?id=<?= urlencode($order['_id']) ?>" <a href="/aulatek/supercafe_edit.php?id=<?= urlencode($order['_id']) ?>"
class="btn btn-sm btn-primary">Editar</a> class="btn btn-sm btn-primary">Editar</a>
<form method="post" style="display: inline;"> <form method="post" style="display: inline;">
<input type="hidden" name="action" value="change_status"> <input type="hidden" name="action" value="change_status">

View File

@@ -8,10 +8,11 @@ if (!in_array('supercafe:edit', $_SESSION['auth_data']['permissions'] ?? [])) {
die('Acceso denegado'); die('Acceso denegado');
} }
$centro_id = safe_centro_id($_SESSION['auth_data']['entreaulas']['centro'] ?? ''); $tenant_data = $_SESSION['auth_data']['aulatek'] ?? ($_SESSION['auth_data']['entreaulas'] ?? []);
$centro_id = safe_organization_id($tenant_data['organizacion'] ?? ($tenant_data['centro'] ?? ''));
if ($centro_id === '') { if ($centro_id === '') {
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
echo '<div class="card pad"><h1>SuperCafe</h1><p>No tienes un centro asignado.</p></div>'; echo '<div class="card pad"><h1>SuperCafe</h1><p>No tienes una organizacion asignada.</p></div>';
require_once "_incl/post-body.php"; require_once "_incl/post-body.php";
exit; exit;
} }
@@ -28,7 +29,7 @@ function sc_load_personas_from_alumnos($centro_id)
{ {
$aularios = db_get_aularios($centro_id); $aularios = db_get_aularios($centro_id);
$personas = []; $personas = [];
$aularios_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios"; $aularios_dir = aulatek_orgs_base_path() . "/$centro_id/Aularios";
foreach ($aularios as $aulario_id => $aulario_data) { foreach ($aularios as $aulario_id => $aulario_data) {
$aulario_name = $aulario_data['name'] ?? $aulario_id; $aulario_name = $aulario_data['name'] ?? $aulario_id;
$alumnos_path = "$aularios_dir/$aulario_id/Alumnos"; $alumnos_path = "$aularios_dir/$aulario_id/Alumnos";
@@ -130,7 +131,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
date('Y-m-d'), $persona_key, $comanda_str, $notas, date('Y-m-d'), $persona_key, $comanda_str, $notas,
$is_new ? 'Pedido' : $estado $is_new ? 'Pedido' : $estado
); );
header('Location: /entreaulas/supercafe.php'); header('Location: /aulatek/supercafe.php');
exit; exit;
} }
} }
@@ -139,9 +140,208 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
?> ?>
<style>
.sc-legacy-wrap {
max-width: 320px;
}
.sc-legacy-title {
font-size: 1.9rem;
margin: 0 0 0.2rem;
font-weight: 700;
}
.sc-legacy-subtitle {
font-size: 0.85rem;
font-weight: 600;
margin-bottom: 0.35rem;
}
.sc-legacy-exit {
padding: 2px 8px;
border: 1px solid #111;
border-radius: 2px;
background: #fff;
color: #111;
text-decoration: none;
display: inline-block;
margin-bottom: 0.35rem;
font-size: 0.82rem;
}
.sc-legacy-fieldset {
border: 1px solid #bcbcbc;
border-radius: 0;
padding: 6px;
background: #fff;
}
.sc-legacy-fieldset legend {
font-size: 0.95rem;
font-weight: 700;
margin-bottom: 0;
}
.sc-legacy-persona-photo img {
height: 64px;
border-radius: 10px;
border: 2px solid #777;
background: #fff;
}
.sc-persona-current {
display: flex;
align-items: center;
gap: 7px;
margin-top: 5px;
min-height: 36px;
font-size: 0.8rem;
}
.sc-persona-current img {
width: 32px;
height: 32px;
border-radius: 8px;
border: 1px solid #666;
background: #fff;
object-fit: cover;
}
.sc-persona-group {
margin-top: 5px;
padding-top: 3px;
border-top: 1px dashed #ddd;
}
.sc-persona-group-label {
font-size: 0.72rem;
color: #555;
margin-bottom: 3px;
font-weight: 700;
}
.sc-person-btn {
border: 5px solid transparent;
outline: 2px solid black;
border-radius: 10px;
background: #fff;
color: #111;
min-width: 86px;
max-width: 125px;
min-height: 54px;
padding: 4px 6px;
font-size: 0.75rem;
line-height: 1.05;
text-align: center;
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
}
.sc-person-btn img {
width: 24px;
height: 24px;
border-radius: 7px;
border: 1px solid #777;
object-fit: cover;
background: #fff;
}
.sc-person-btn.active {
background: #d9ff1f;
border: 5px dashed #000;
outline: 2px solid black;
}
.sc-details {
margin: 4px 0;
border: 1px solid #444;
border-radius: 3px;
background: #fff;
width: 100%;
}
.sc-details summary {
list-style: none;
cursor: pointer;
font-size: 0.86rem;
padding: 4px 6px;
background: #f3f3f3;
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
}
.sc-details summary::-webkit-details-marker {
display: none;
}
.sc-summary-left {
display: flex;
align-items: center;
gap: 5px;
min-width: 0;
}
.sc-summary-left img {
height: 18px;
width: 18px;
object-fit: contain;
}
.sc-summary-right {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}
.sc-selected-val {
max-width: 95px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.78rem;
color: #444;
}
.sc-check {
height: 15px;
}
.sc-category-body {
padding: 4px;
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.sc-cat-btn {
border: 5px solid transparent;
outline: 2px solid black;
border-radius: 9px;
background: #d9ff1f;
color: #111;
min-width: 90px;
min-height: 44px;
padding: 3px 6px;
font-size: 0.78rem;
line-height: 1.1;
text-align: center;
}
.sc-cat-btn small {
font-size: 0.68rem;
}
.sc-cat-btn.active {
outline: 2px solid black;
border: 5px dashed #000;
}
.sc-cat-btn.sc-size-btn {
background: #ff3030;
color: #fff;
}
.sc-notes {
width: 100%;
min-height: 78px;
font-size: 0.85rem;
}
.sc-actions {
display: flex;
gap: 6px;
justify-content: flex-start;
margin-top: 6px;
}
.sc-actions .btn {
border-radius: 2px;
padding: 3px 9px;
font-size: 0.82rem;
}
</style>
<h1>Comanda <code><?= htmlspecialchars($order_id) ?></code></h1> <div class="sc-legacy-wrap">
<a href="/entreaulas/supercafe.php" class="btn btn-secondary">Salir</a> <h1 class="sc-legacy-title">Comanda <small style="font-size:.72rem;color:#666;"><?= htmlspecialchars($order_id) ?></small></h1>
<a href="/aulatek/supercafe.php" class="sc-legacy-exit">Salir</a>
<?php if ($error !== ''): ?> <?php if ($error !== ''): ?>
<div class="card pad" style="background: #f8d7da; color: #842029;"> <div class="card pad" style="background: #f8d7da; color: #842029;">
@@ -150,56 +350,84 @@ require_once "_incl/pre-body.php";
<?php endif; ?> <?php endif; ?>
<form method="post"> <form method="post">
<fieldset class="card pad" style="text-align: center;"> <fieldset class="sc-legacy-fieldset">
<legend>Rellenar comanda</legend> <legend>Rellenar comanda</legend>
<label style="display: none;"> <label style="display: none;">
Fecha<br> Fecha<br>
<input readonly disabled type="text" value="<?= htmlspecialchars($order_data['Fecha']) ?>"><br><br> <input readonly disabled type="text" value="<?= htmlspecialchars($order_data['Fecha']) ?>"><br><br>
</label> </label>
<label> <label style="display:block; margin-bottom:6px;">
Persona<br> Persona<br>
<?php if (!empty($personas_by_aulario)): ?> <?php if (!empty($personas_by_aulario)): ?>
<select name="Persona" class="form-select" required>
<option value="">-- Selecciona una persona --</option>
<?php foreach ($personas_by_aulario as $region_name => $group): ?>
<optgroup label="<?= htmlspecialchars($region_name) ?>">
<?php foreach ($group as $pkey => $pinfo): ?>
<option value="<?= htmlspecialchars($pkey) ?>"
<?= ($order_data['Persona'] === $pkey) ? 'selected' : '' ?>>
<?= htmlspecialchars($pinfo['Nombre']) ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?>
</select>
<?php <?php
$sel_key = $order_data['Persona']; $sel_key = $order_data['Persona'];
$sel_info = $personas[$sel_key] ?? null; $sel_info = $personas[$sel_key] ?? null;
if ($sel_info && $sel_info['HasPhoto']):
?> ?>
<div id="sc-persona-photo" style="margin-top: 8px;"> <details class="sc-details" open>
<?php $photo_url = '/entreaulas/_filefetch.php?type=alumno_photo' <summary>
. '&centro=' . urlencode($centro_id) <span class="sc-summary-left">
<span>Persona</span>
</span>
<span class="sc-summary-right">
<span class="sc-selected-val" id="sc-persona-selected-label"><?= htmlspecialchars($sel_info['Nombre'] ?? '') ?></span>
<img class="sc-check" src="static/ico/<?= $sel_info ? 'checkbox.png' : 'checkbox_unchecked.png' ?>" id="sc-persona-check" alt="">
</span>
</summary>
<div class="sc-category-body" id="sc-persona-panel">
<?php foreach ($personas_by_aulario as $region_name => $group): ?>
<div class="sc-persona-group" style="width:100%;">
<div class="sc-persona-group-label"><?= htmlspecialchars($region_name) ?></div>
<div style="display:flex; flex-wrap:wrap; gap:4px;">
<?php foreach ($group as $pkey => $pinfo): ?>
<?php
$p_photo_url = '/aulatek/_filefetch.php?type=alumno_photo'
. '&org=' . urlencode($centro_id)
. '&aulario=' . urlencode($pinfo['AularioID'])
. '&alumno=' . urlencode($pinfo['Nombre']);
$is_person_active = ($order_data['Persona'] === $pkey);
?>
<button type="button"
class="sc-person-btn<?= $is_person_active ? ' active' : '' ?>"
data-person-key="<?= htmlspecialchars($pkey, ENT_QUOTES) ?>"
data-person-name="<?= htmlspecialchars($pinfo['Nombre'], ENT_QUOTES) ?>"
data-person-region="<?= htmlspecialchars($region_name, ENT_QUOTES) ?>"
data-person-photo="<?= htmlspecialchars($pinfo['HasPhoto'] ? $p_photo_url : '/static/arasaac/alumnos.png', ENT_QUOTES) ?>"
onclick="scSelectPersona(this)">
<img src="<?= htmlspecialchars($pinfo['HasPhoto'] ? $p_photo_url : '/static/arasaac/alumnos.png') ?>" alt="">
<span><?= htmlspecialchars($pinfo['Nombre']) ?></span>
</button>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</details>
<input type="hidden" name="Persona" id="sc-persona-input" value="<?= htmlspecialchars($order_data['Persona']) ?>">
<div class="sc-persona-current" id="sc-persona-current" style="display: none;">
<?php if ($sel_info): ?>
<?php $photo_url = '/aulatek/_filefetch.php?type=alumno_photo'
. '&org=' . urlencode($centro_id)
. '&aulario=' . urlencode($sel_info['AularioID']) . '&aulario=' . urlencode($sel_info['AularioID'])
. '&alumno=' . urlencode($sel_info['Nombre']); ?> . '&alumno=' . urlencode($sel_info['Nombre']); ?>
<img src="<?= htmlspecialchars($photo_url) ?>" <img src="<?= htmlspecialchars($sel_info['HasPhoto'] ? $photo_url : '/static/arasaac/alumnos.png') ?>" alt="Foto">
alt="Foto de <?= htmlspecialchars($sel_info['Nombre']) ?>" <span><strong><?= htmlspecialchars($sel_info['Nombre']) ?></strong> (<?= htmlspecialchars($sel_info['Region']) ?>)</span>
style="height: 80px; border-radius: 8px; border: 2px solid #dee2e6;"> <?php else: ?>
</div> <span style="color:#666;">No hay persona seleccionada.</span>
<?php endif; ?> <?php endif; ?>
</div>
<?php else: ?> <?php else: ?>
<input type="text" name="Persona" class="form-control" <input type="text" name="Persona" class="form-control"
value="<?= htmlspecialchars($order_data['Persona']) ?>" value="<?= htmlspecialchars($order_data['Persona']) ?>"
placeholder="Nombre de la persona" required> placeholder="Nombre de la persona" required>
<small class="text-muted"> <small class="text-muted">
No hay alumnos registrados en los aularios de este centro. No hay alumnos registrados en los aularios de esta organizacion.
Añade alumnos desde Añade alumnos desde
<a href="/entreaulas/">EntreAulas</a>. <a href="/aulatek/">AulaTek</a>.
</small> </small>
<?php endif; ?> <?php endif; ?>
<br><br> <br>
</label> </label>
<label style="display: none;"> <label style="display: none;">
@@ -209,15 +437,6 @@ require_once "_incl/pre-body.php";
<div> <div>
<?php if (!empty($menu)): ?> <?php if (!empty($menu)): ?>
<style>
.sc-details { text-align: center; margin: 5px; padding: 5px; border: 2px solid black; border-radius: 5px; background: white; cursor: pointer; width: calc(100% - 25px); display: inline-block; }
.sc-details summary { padding: 10px; background-size: contain; background-position: left; background-repeat: no-repeat; text-align: left; padding-left: 55px; font-size: 1.1em; }
.sc-cat-btn { border-radius: 20px; font-size: 1.1em; margin: 6px; padding: 10px 18px; border: 2px solid #bbb; background: #f8f9fa; display: inline-block; min-width: 90px; min-height: 60px; vertical-align: top; transition: background 0.2s, border 0.2s; }
.sc-cat-btn.active { background: #ffe066; border: 2px solid #222; }
.sc-cat-btn img { height: 50px; padding: 5px; background: white; border-radius: 8px; }
.sc-details .sc-summary-right { float: right; display: flex; align-items: center; gap: 6px; }
.sc-details .sc-check { height: 30px; }
</style>
<?php <?php
// Iconos por categoría (puedes ampliar este array según tus iconos) // Iconos por categoría (puedes ampliar este array según tus iconos)
$sc_actions_icons = [ $sc_actions_icons = [
@@ -240,8 +459,13 @@ require_once "_incl/pre-body.php";
?> ?>
<?php foreach ($menu as $category => $items): ?> <?php foreach ($menu as $category => $items): ?>
<details class="sc-details"> <details class="sc-details">
<summary style="background-image: url('<?= isset($sc_actions_icons[$category]) ? $sc_actions_icons[$category] : '' ?>');"> <summary>
<?= htmlspecialchars($category) ?> <span class="sc-summary-left">
<?php if (isset($sc_actions_icons[$category])): ?>
<img src="<?= htmlspecialchars($sc_actions_icons[$category]) ?>" alt="">
<?php endif; ?>
<span><?= htmlspecialchars($category) ?></span>
</span>
<span class="sc-summary-right"> <span class="sc-summary-right">
<span class="sc-selected-val" id="sc-val-<?= md5($category) ?>"> <span class="sc-selected-val" id="sc-val-<?= md5($category) ?>">
<?= htmlspecialchars($selected[$category] ?? '') ?> <?= htmlspecialchars($selected[$category] ?? '') ?>
@@ -249,12 +473,13 @@ require_once "_incl/pre-body.php";
<img class="sc-check" src="static/ico/checkbox_unchecked.png" id="sc-check-<?= md5($category) ?>"> <img class="sc-check" src="static/ico/checkbox_unchecked.png" id="sc-check-<?= md5($category) ?>">
</span> </span>
</summary> </summary>
<div> <div class="sc-category-body">
<?php foreach ($items as $item_name => $item_price): <?php foreach ($items as $item_name => $item_price):
$btn_id = 'sc-btn-' . md5($category . '_' . $item_name); $btn_id = 'sc-btn-' . md5($category . '_' . $item_name);
$is_active = ($selected[$category] ?? '') === $item_name; $is_active = ($selected[$category] ?? '') === $item_name;
$btn_extra_class = ($category === 'Tamaño') ? ' sc-size-btn' : '';
?> ?>
<button type="button" class="sc-cat-btn<?= $is_active ? ' active' : '' ?>" id="<?= $btn_id ?>" onclick=" <button type="button" class="sc-cat-btn<?= $btn_extra_class ?><?= $is_active ? ' active' : '' ?>" id="<?= $btn_id ?>" onclick="
document.getElementById('sc-val-<?= md5($category) ?>').innerText = '<?= htmlspecialchars($item_name) ?>'; document.getElementById('sc-val-<?= md5($category) ?>').innerText = '<?= htmlspecialchars($item_name) ?>';
document.getElementById('sc-check-<?= md5($category) ?>').src = 'static/ico/checkbox.png'; document.getElementById('sc-check-<?= md5($category) ?>').src = 'static/ico/checkbox.png';
var btns = this.parentNode.querySelectorAll('.sc-cat-btn'); var btns = this.parentNode.querySelectorAll('.sc-cat-btn');
@@ -266,7 +491,6 @@ require_once "_incl/pre-body.php";
<?php if ($item_price > 0): ?> <?php if ($item_price > 0): ?>
<br><small style="color: #6c757d;">(<?= number_format((float)$item_price, 2) ?>c)</small> <br><small style="color: #6c757d;">(<?= number_format((float)$item_price, 2) ?>c)</small>
<?php endif; ?> <?php endif; ?>
<!-- Aquí podrías poner una imagen si tienes -->
</button> </button>
<?php endforeach; ?> <?php endforeach; ?>
<input type="hidden" name="<?= htmlspecialchars($category) ?>" id="input-<?= md5($category) ?>" value="<?= htmlspecialchars($selected[$category] ?? '') ?>"> <input type="hidden" name="<?= htmlspecialchars($category) ?>" id="input-<?= md5($category) ?>" value="<?= htmlspecialchars($selected[$category] ?? '') ?>">
@@ -281,15 +505,15 @@ require_once "_incl/pre-body.php";
placeholder="Ej. 1x Café, 1x Bocadillo"> placeholder="Ej. 1x Café, 1x Bocadillo">
<small class="text-muted"> <small class="text-muted">
No hay menú configurado en No hay menú configurado en
<code>/DATA/entreaulas/Centros/<?= htmlspecialchars($centro_id) ?>/SuperCafe/Menu.json</code>. <code><?= htmlspecialchars(aulatek_orgs_base_path() . "/" . $centro_id . "/SuperCafe/Menu.json") ?></code>.
</small> </small>
</div> </div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<label> <label style="display:block; margin-top:6px;">
Notas<br> Notas<br>
<textarea name="Notas" class="form-control" rows="2"><?= htmlspecialchars($order_data['Notas']) ?></textarea><br><br> <textarea name="Notas" class="form-control sc-notes" rows="2"><?= htmlspecialchars($order_data['Notas']) ?></textarea>
</label> </label>
<?php if (!$is_new): ?> <?php if (!$is_new): ?>
@@ -303,14 +527,53 @@ require_once "_incl/pre-body.php";
</option> </option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<br>Modificar en el listado de comandas<br> <br><small>Modificar en el listado de comandas</small><br>
</label> </label>
<?php endif; ?> <?php endif; ?>
<button type="submit" class="btn btn-success">Guardar</button> <div class="sc-actions">
<a href="/entreaulas/supercafe.php" class="btn btn-secondary">Cancelar</a> <button type="submit" class="btn btn-success">Guardar</button>
<a href="/aulatek/supercafe.php" class="btn btn-danger">Cancelar</a>
</div>
</fieldset> </fieldset>
</form> </form>
</div>
<script>
function scSelectPersona(button) {
var key = button.getAttribute('data-person-key') || '';
var name = button.getAttribute('data-person-name') || '';
var region = button.getAttribute('data-person-region') || '';
var photo = button.getAttribute('data-person-photo') || '/static/arasaac/alumnos.png';
var hiddenInput = document.getElementById('sc-persona-input');
if (hiddenInput) {
hiddenInput.value = key;
}
var allButtons = document.querySelectorAll('.sc-person-btn');
allButtons.forEach(function(btn) {
btn.classList.remove('active');
});
button.classList.add('active');
var label = document.getElementById('sc-persona-selected-label');
if (label) {
label.innerText = name;
}
var check = document.getElementById('sc-persona-check');
if (check) {
check.src = 'static/ico/checkbox.png';
}
var current = document.getElementById('sc-persona-current');
if (current) {
current.innerHTML = '<img src="' + photo + '" alt="Foto">' +
'<span><strong>' + name + '</strong>' + (region ? ' (' + region + ')' : '') + '</span>';
}
}
</script>
<?php require_once "_incl/post-body.php"; ?> <?php require_once "_incl/post-body.php"; ?>

View File

@@ -1,11 +1,4 @@
<?php <?php
ini_set("display_errors", 0); ini_set("display_errors", 0);
$PAGE_TITLE = "EntreAulas - Inicio"; header('Location: /aulatek/');
require_once "_incl/pre-body.php"; ?> exit;
<div class="card pad">
<h2>Recursos:</h2>
<ul>
<li><a class="btn btn-secondary" href="/entreaulas/recursos/letras-a4.php">Generador de Letras A4 con varios estilos para imprimir</a></li>
</ul>
</div>
<?php require_once "_incl/post-body.php"; ?>

View File

@@ -121,8 +121,8 @@
<h1>Bienvenidx a Axia4</h1> <h1>Bienvenidx a Axia4</h1>
<p>La plataforma unificada de EuskadiTech y Sketaria.</p> <p>La plataforma unificada de EuskadiTech y Sketaria.</p>
<hr> <hr>
<h3>Versión 2.0.0</h3> <h3>Versión 2.1.0</h3>
<p>Con esta versión, cambiamos la interfaz a una más sencilla.</p> <p>Con esta versión, hacemos muchos cambios.</p>
<br> <br>
<a class="btn btn-primary" href="/account/">Accede a tu cuenta</a> <a class="btn btn-primary" href="/account/">Accede a tu cuenta</a>
</section> </section>
@@ -160,11 +160,11 @@
</div> </div>
</div> </div>
<div class="app-card"> <div class="app-card">
<img src="/static/logo-entreaulas.png" alt="Logo EntreAulas"> <img src="/static/logo-aulatek.png" alt="Logo AulaTek">
<div class="app-title">EntreAulas</div> <div class="app-title">AulaTek</div>
<div class="app-desc">Recursos educativos digitales.</div> <div class="app-desc">Tu aula, digital.</div>
<div class="app-actions"> <div class="app-actions">
<a href="/entreaulas/" target="_blank" class="btn btn-primary">Acceso público</a> <a href="/aulatek/" target="_blank" class="btn btn-primary">Acceso público</a>
</div> </div>
</div> </div>
<div class="app-card"> <div class="app-card">

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,7 @@
<div class="sidebar-section-label">Atajos</div>
<nav class="sidebar-nav">
<a class="sidebar-link" href="/sysadmin/users.php?action=add">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="24" width="24"><title>account-plus</title><path d="M15,14C12.33,14 7,15.33 7,18V20H23V18C23,15.33 17.67,14 15,14M6,10V7H4V10H1V12H4V15H6V12H9V10M15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12Z" /></svg>
<span>Nuevo usuario</span>
</a>
</nav>

View File

@@ -24,19 +24,19 @@ switch ($form_action) {
die("Parámetros inválidos."); die("Parámetros inválidos.");
} }
// Remove from DB // Remove from DB
db()->prepare("DELETE FROM aularios WHERE centro_id = ? AND aulario_id = ?") db()->prepare("DELETE FROM aularios WHERE org_id = ? AND aulario_id = ?")
->execute([$centro_id, $aulario_id]); ->execute([$centro_id, $aulario_id]);
// Remove comedor, diario, panel data // Remove comedor, diario, panel data
db()->prepare("DELETE FROM comedor_menu_types WHERE centro_id = ? AND aulario_id = ?") db()->prepare("DELETE FROM comedor_menu_types WHERE org_id = ? AND aulario_id = ?")
->execute([$centro_id, $aulario_id]); ->execute([$centro_id, $aulario_id]);
db()->prepare("DELETE FROM comedor_entries WHERE centro_id = ? AND aulario_id = ?") db()->prepare("DELETE FROM comedor_entries WHERE org_id = ? AND aulario_id = ?")
->execute([$centro_id, $aulario_id]); ->execute([$centro_id, $aulario_id]);
db()->prepare("DELETE FROM diario_entries WHERE centro_id = ? AND aulario_id = ?") db()->prepare("DELETE FROM diario_entries WHERE org_id = ? AND aulario_id = ?")
->execute([$centro_id, $aulario_id]); ->execute([$centro_id, $aulario_id]);
db()->prepare("DELETE FROM panel_alumno WHERE centro_id = ? AND aulario_id = ?") db()->prepare("DELETE FROM panel_alumno WHERE org_id = ? AND aulario_id = ?")
->execute([$centro_id, $aulario_id]); ->execute([$centro_id, $aulario_id]);
// Remove filesystem directory with student photos // Remove filesystem directory with student photos
$aulario_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id"; $aulario_dir = aulatek_orgs_base_path() . "/$centro_id/Aularios/$aulario_id";
function rrmdir($dir) function rrmdir($dir)
{ {
if (is_dir($dir)) { if (is_dir($dir)) {
@@ -54,26 +54,26 @@ switch ($form_action) {
exit(); exit();
break; break;
case "create": case "create":
$centro_id = safe_path_segment(Sf($_POST["centro"] ?? "")); $centro_id = safe_path_segment(Sf($_POST["centro"] ?? ($_POST["org"] ?? "")));
$aulario_id = strtolower(preg_replace("/[^a-zA-Z0-9_-]/", "_", Sf($_POST["name"] ?? ""))); $aulario_id = strtolower(preg_replace("/[^a-zA-Z0-9_-]/", "_", Sf($_POST["name"] ?? "")));
if (empty($centro_id) || empty($aulario_id)) { if (empty($centro_id) || empty($aulario_id)) {
die("Datos incompletos."); die("Datos incompletos.");
} }
// Ensure centro exists in DB // Ensure centro exists in DB
$stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); $stmt = db()->prepare("SELECT id FROM organizaciones WHERE org_id = ?");
$stmt->execute([$centro_id]); $stmt->execute([$centro_id]);
if (!$stmt->fetch()) { if (!$stmt->fetch()) {
die("Centro no válido."); die("Centro no válido.");
} }
db()->prepare( db()->prepare(
"INSERT OR IGNORE INTO aularios (centro_id, aulario_id, name, icon) VALUES (?, ?, ?, ?)" "INSERT OR IGNORE INTO aularios (org_id, aulario_id, name, icon) VALUES (?, ?, ?, ?)"
)->execute([ )->execute([
$centro_id, $aulario_id, $centro_id, $aulario_id,
Sf($_POST["name"] ?? ""), Sf($_POST["name"] ?? ""),
Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"), Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"),
]); ]);
// Create Proyectos directory for project file storage // Create Proyectos directory for project file storage
$proyectos_dir = "/DATA/entreaulas/Centros/$centro_id/Aularios/$aulario_id/Proyectos/"; $proyectos_dir = aulatek_orgs_base_path() . "/$centro_id/Aularios/$aulario_id/Proyectos/";
if (!is_dir($proyectos_dir)) { if (!is_dir($proyectos_dir)) {
mkdir($proyectos_dir, 0755, true); mkdir($proyectos_dir, 0755, true);
} }
@@ -104,7 +104,7 @@ switch ($form_action) {
$extra['shared_comedor_from'] = Sf($_POST['shared_comedor_from']); $extra['shared_comedor_from'] = Sf($_POST['shared_comedor_from']);
} }
db()->prepare( db()->prepare(
"UPDATE aularios SET name = ?, icon = ?, extra = ? WHERE centro_id = ? AND aulario_id = ?" "UPDATE aularios SET name = ?, icon = ?, extra = ? WHERE org_id = ? AND aulario_id = ?"
)->execute([ )->execute([
Sf($_POST["name"] ?? ""), Sf($_POST["name"] ?? ""),
Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"), Sf($_POST["icon"] ?? "/static/logo-entreaulas.png"),
@@ -121,7 +121,7 @@ $view_action = $_GET["action"] ?? "index";
switch ($view_action) { switch ($view_action) {
case "new": case "new":
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
$centro_id = safe_path_segment(Sf($_GET["centro"] ?? "")); $centro_id = safe_path_segment(Sf($_GET["centro"] ?? ($_GET["org"] ?? "")));
$all_centros = db_get_centro_ids(); $all_centros = db_get_centro_ids();
?> ?>
<div class="card pad"> <div class="card pad">
@@ -129,9 +129,9 @@ switch ($view_action) {
<h1>Nuevo Aulario</h1> <h1>Nuevo Aulario</h1>
<form method="post" action="?form=create"> <form method="post" action="?form=create">
<div class="mb-3"> <div class="mb-3">
<label for="centro" class="form-label">Centro:</label> <label for="centro" class="form-label">Organizacion:</label>
<select id="centro" name="centro" class="form-select" required> <select id="centro" name="centro" class="form-select" required>
<option value="">-- Selecciona un centro --</option> <option value="">-- Selecciona una organizacion --</option>
<?php foreach ($all_centros as $cid): ?> <?php foreach ($all_centros as $cid): ?>
<option value="<?= htmlspecialchars($cid) ?>" <?= $cid === $centro_id ? 'selected' : '' ?>><?= htmlspecialchars($cid) ?></option> <option value="<?= htmlspecialchars($cid) ?>" <?= $cid === $centro_id ? 'selected' : '' ?>><?= htmlspecialchars($cid) ?></option>
<?php endforeach; ?> <?php endforeach; ?>
@@ -143,7 +143,7 @@ switch ($view_action) {
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="icon" class="form-label">URL del icono:</label> <label for="icon" class="form-label">URL del icono:</label>
<input type="url" id="icon" name="icon" class="form-control" value="/static/logo-entreaulas.png"> <input type="text" id="icon" name="icon" class="form-control" value="/static/logo-entreaulas.png">
</div> </div>
<button type="submit" class="btn btn-primary">Crear Aulario</button> <button type="submit" class="btn btn-primary">Crear Aulario</button>
</form> </form>
@@ -155,7 +155,7 @@ switch ($view_action) {
case "edit": case "edit":
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
$aulario_id = safe_path_segment(Sf($_GET["aulario"] ?? "")); $aulario_id = safe_path_segment(Sf($_GET["aulario"] ?? ""));
$centro_id = safe_path_segment(Sf($_GET["centro"] ?? "")); $centro_id = safe_path_segment(Sf($_GET["centro"] ?? ($_GET["org"] ?? "")));
$aulario = db_get_aulario($centro_id, $aulario_id); $aulario = db_get_aulario($centro_id, $aulario_id);
if (!$aulario) { if (!$aulario) {
die("Aulario no encontrado."); die("Aulario no encontrado.");

View File

@@ -7,9 +7,9 @@ require_once "_incl/pre-body.php"; ?>
</div> </div>
<div id="grid"> <div id="grid">
<div class="card grid-item"> <div class="card grid-item">
<img src="/static/logo-entreaulas.png" alt="Logo EntreAulas"> <img src="/static/logo-entreaulas.png" alt="Logo AulaTek">
<b>EntreAulas</b> <b>AulaTek</b>
<a href="/sysadmin/centros.php" class="btn btn-primary">Gestionar Centros</a> <a href="/sysadmin/orgs.php" class="btn btn-primary">Gestionar Organizaciones</a>
<a href="/sysadmin/aularios.php" class="btn btn-primary">Gestionar Aularios</a> <a href="/sysadmin/aularios.php" class="btn btn-primary">Gestionar Aularios</a>
</div> </div>
<div class="card grid-item"> <div class="card grid-item">

View File

@@ -18,36 +18,47 @@ function safe_path_segment($value)
$form_action = $_GET["form"] ?? ""; $form_action = $_GET["form"] ?? "";
switch ($form_action) { switch ($form_action) {
case "create": case "create":
$centro_id = safe_path_segment(Sf($_POST["name"] ?? "")); $org_id = safe_path_segment(Sf($_POST["org_id"] ?? ""));
if (empty($centro_id)) { $org_name = Sf($_POST["org_name"] ?? "");
die("Nombre del centro no proporcionado."); if (empty($org_id)) {
die("Nombre de la organización no proporcionado.");
} }
// Check uniqueness in DB // Check uniqueness in DB
$existing = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); $existing = db()->prepare("SELECT id FROM organizaciones WHERE org_id = ?");
$existing->execute([$centro_id]); $existing->execute([$org_id]);
if ($existing->fetch()) { if ($existing->fetch()) {
die("El centro ya existe."); die("La organización ya existe.");
} }
// Create DB record // Create DB record
db()->prepare("INSERT INTO centros (centro_id) VALUES (?)")->execute([$centro_id]); db()->prepare("INSERT INTO organizaciones (org_id, org_name) VALUES (?, ?)")->execute([$org_id, $org_name !== '' ? $org_name : $org_id]);
// Keep filesystem directory for activity photos (Panel/Actividades) // Keep filesystem directory for activity photos (Panel/Actividades)
$centro_path = "/DATA/entreaulas/Centros/$centro_id"; $org_path = aulatek_orgs_base_path() . "/$org_id";
if (!is_dir($centro_path) && !mkdir($centro_path, 0755, true) && !is_dir($centro_path)) { if (!is_dir($org_path) && !mkdir($org_path, 0755, true) && !is_dir($org_path)) {
error_log("centros.php: failed to create directory $centro_path"); error_log("orgs.php: failed to create directory $org_path");
} }
header("Location: ?action=index"); header("Location: ?action=index");
exit(); exit();
break; break;
case "edit":
$org_id = safe_path_segment(Sf($_GET['org'] ?? ''));
$org_name = Sf($_POST['org_name'] ?? '');
if ($org_id === '' || $org_name === '') {
die("Datos inválidos para actualizar la organización.");
}
db()->prepare("UPDATE organizaciones SET org_name = ? WHERE org_id = ?")->execute([$org_name, $org_id]);
header("Location: ?action=edit&org=" . urlencode($org_id) . "&_result=" . urlencode("Cambios guardados."));
exit();
break;
case "create_activity": case "create_activity":
ini_set('memory_limit', '512M'); ini_set('memory_limit', '512M');
ini_set('upload_max_filesize', '256M'); ini_set('upload_max_filesize', '256M');
ini_set('post_max_size', '256M'); ini_set('post_max_size', '256M');
$centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $org_id = safe_path_segment(Sf($_GET['org'] ?? ''));
// Validate centro exists in DB // Validate organization exists in DB
$stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); $stmt = db()->prepare("SELECT id FROM organizaciones WHERE org_id = ?");
$stmt->execute([$centro_id]); $stmt->execute([$org_id]);
if (!$stmt->fetch()) { if (!$stmt->fetch()) {
die("Centro no válido."); die("Organización no válida.");
} }
$activity_name = safe_path_segment(Sf($_POST["name"] ?? '')); $activity_name = safe_path_segment(Sf($_POST["name"] ?? ''));
if (empty($activity_name)) { if (empty($activity_name)) {
@@ -57,22 +68,22 @@ switch ($form_action) {
if ($activity_photo === null || $activity_photo["error"] !== UPLOAD_ERR_OK) { if ($activity_photo === null || $activity_photo["error"] !== UPLOAD_ERR_OK) {
die("Error al subir la foto."); die("Error al subir la foto.");
} }
$activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$activity_name"; $activity_path = aulatek_orgs_base_path() . "/$org_id/Panel/Actividades/$activity_name";
if (is_dir($activity_path)) { if (is_dir($activity_path)) {
die("La actividad ya existe."); die("La actividad ya existe.");
} }
mkdir($activity_path, 0755, true); mkdir($activity_path, 0755, true);
move_uploaded_file($activity_photo["tmp_name"], "$activity_path/photo.jpg"); move_uploaded_file($activity_photo["tmp_name"], "$activity_path/photo.jpg");
header("Location: ?action=edit&centro=" . urlencode($centro_id)); header("Location: ?action=edit&org=" . urlencode($org_id));
exit(); exit();
break; break;
case "edit_activity": case "edit_activity":
ini_set('memory_limit', '512M'); ini_set('memory_limit', '512M');
ini_set('upload_max_filesize', '256M'); ini_set('upload_max_filesize', '256M');
ini_set('post_max_size', '256M'); ini_set('post_max_size', '256M');
$centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $org_id = safe_path_segment(Sf($_GET['org'] ?? ''));
$activity_name = safe_path_segment(Sf($_GET['activity'] ?? '')); $activity_name = safe_path_segment(Sf($_GET['activity'] ?? ''));
$activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$activity_name"; $activity_path = aulatek_orgs_base_path() . "/$org_id/Panel/Actividades/$activity_name";
if (!is_dir($activity_path)) { if (!is_dir($activity_path)) {
die("Actividad no válida."); die("Actividad no válida.");
} }
@@ -82,13 +93,13 @@ switch ($form_action) {
} }
$new_name = safe_path_segment(Sf($_POST['nombre'] ?? '')); $new_name = safe_path_segment(Sf($_POST['nombre'] ?? ''));
if ($new_name !== $activity_name && $new_name !== '') { if ($new_name !== $activity_name && $new_name !== '') {
$new_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$new_name"; $new_path = aulatek_orgs_base_path() . "/$org_id/Panel/Actividades/$new_name";
if (is_dir($new_path)) { if (is_dir($new_path)) {
die("Ya existe una actividad con ese nombre."); die("Ya existe una actividad con ese nombre.");
} }
rename($activity_path, $new_path); rename($activity_path, $new_path);
} }
header("Location: ?action=edit&centro=" . urlencode($centro_id)); header("Location: ?action=edit&org=" . urlencode($org_id));
exit(); exit();
break; break;
} }
@@ -97,9 +108,9 @@ require_once "_incl/pre-body.php";
$view_action = $_GET["action"] ?? "index"; $view_action = $_GET["action"] ?? "index";
switch ($view_action) { switch ($view_action) {
case "edit_activity": case "edit_activity":
$centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $org_id = safe_path_segment(Sf($_GET['org'] ?? ''));
$activity_name = safe_path_segment(Sf($_GET['activity'] ?? '')); $activity_name = safe_path_segment(Sf($_GET['activity'] ?? ''));
$activity_path = "/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/$activity_name"; $activity_path = aulatek_orgs_base_path() . "/$org_id/Panel/Actividades/$activity_name";
if (!is_dir($activity_path)) { if (!is_dir($activity_path)) {
die("Actividad no válida."); die("Actividad no válida.");
} }
@@ -107,7 +118,7 @@ switch ($view_action) {
<div class="card pad"> <div class="card pad">
<div> <div>
<h1 class="card-title">Gestión de la Actividad: <?= htmlspecialchars($activity_name) ?></h1> <h1 class="card-title">Gestión de la Actividad: <?= htmlspecialchars($activity_name) ?></h1>
<form method="post" action="?form=edit_activity&centro=<?= urlencode($centro_id) ?>&activity=<?= urlencode($activity_name) ?>" enctype="multipart/form-data"> <form method="post" action="?form=edit_activity&org=<?= urlencode($org_id) ?>&activity=<?= urlencode($activity_name) ?>" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label for="nombre" class="form-label">Nombre de la actividad:</label> <label for="nombre" class="form-label">Nombre de la actividad:</label>
<input required type="text" id="nombre" name="nombre" class="form-control" value="<?= htmlspecialchars($activity_name) ?>"> <input required type="text" id="nombre" name="nombre" class="form-control" value="<?= htmlspecialchars($activity_name) ?>">
@@ -117,7 +128,7 @@ switch ($view_action) {
<div style="width: 200px;"> <div style="width: 200px;">
<label class="dropimage" style="background-image: url('<?php <label class="dropimage" style="background-image: url('<?php
$img = file_exists("$activity_path/photo.jpg") $img = file_exists("$activity_path/photo.jpg")
? "/entreaulas/_filefetch.php?type=panel_actividades&centro=" . urlencode($centro_id) . "&activity=" . urlencode($activity_name) ? "/aulatek/_filefetch.php?type=panel_actividades&org=" . urlencode($org_id) . "&activity=" . urlencode($activity_name)
: '/static/logo-entreaulas.png'; : '/static/logo-entreaulas.png';
echo htmlspecialchars($img); echo htmlspecialchars($img);
?>');"> ?>');">
@@ -132,17 +143,17 @@ switch ($view_action) {
<?php <?php
break; break;
case "new_activity": case "new_activity":
$centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $org_id = safe_path_segment(Sf($_GET['org'] ?? ''));
$stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); $stmt = db()->prepare("SELECT id FROM organizaciones WHERE org_id = ?");
$stmt->execute([$centro_id]); $stmt->execute([$org_id]);
if (!$stmt->fetch()) { if (!$stmt->fetch()) {
die("Centro no válido."); die("Organización no válida.");
} }
?> ?>
<div class="card pad"> <div class="card pad">
<div> <div>
<h1 class="card-title">Nueva Actividad del Panel</h1> <h1 class="card-title">Nueva Actividad del Panel</h1>
<form method="post" action="?form=create_activity&centro=<?= urlencode($centro_id) ?>" enctype="multipart/form-data"> <form method="post" action="?form=create_activity&org=<?= urlencode($org_id) ?>" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label for="name" class="form-label">Nombre de la actividad:</label> <label for="name" class="form-label">Nombre de la actividad:</label>
<input required type="text" id="name" name="name" class="form-control" placeholder="Ej: Biblioteca"> <input required type="text" id="name" name="name" class="form-control" placeholder="Ej: Biblioteca">
@@ -161,32 +172,45 @@ switch ($view_action) {
?> ?>
<div class="card pad"> <div class="card pad">
<div> <div>
<h1 class="card-title">Nuevo Centro</h1> <h1 class="card-title">Nueva Organización</h1>
<form method="post" action="?form=create"> <form method="post" action="?form=create">
<div class="mb-3"> <div class="mb-3">
<label for="name" class="form-label">ID del centro:</label> <label for="org_id" class="form-label">ID de la organización:</label>
<input required type="text" id="name" name="name" class="form-control" placeholder="Ej: Centro-Principal-001"> <input required type="text" id="org_id" name="org_id" class="form-control" placeholder="Ej: Organizacion-Principal-001">
</div> </div>
<button type="submit" class="btn btn-primary">Crear Centro</button> <div class="mb-3">
<label for="org_name" class="form-label">Nombre de la organización:</label>
<input required type="text" id="org_name" name="org_name" class="form-control" placeholder="Ej: Organización Principal">
</div>
<button type="submit" class="btn btn-primary">Crear Organización</button>
</form> </form>
</div> </div>
</div> </div>
<?php <?php
break; break;
case "edit": case "edit":
$centro_id = safe_path_segment(Sf($_GET['centro'] ?? '')); $org_id = safe_path_segment(Sf($_GET['org'] ?? ''));
$stmt = db()->prepare("SELECT id FROM centros WHERE centro_id = ?"); $stmt = db()->prepare("SELECT org_name FROM organizaciones WHERE org_id = ?");
$stmt->execute([$centro_id]); $stmt->execute([$org_id]);
if (!$stmt->fetch()) { $org_row = $stmt->fetch();
die("Centro no válido."); if (!$org_row) {
die("Organización no válida.");
} }
$aularios = db_get_aularios($centro_id); $org_name = $org_row['org_name'] ?? $org_id;
$activities = glob("/DATA/entreaulas/Centros/$centro_id/Panel/Actividades/*", GLOB_ONLYDIR) ?: []; $aularios = db_get_aularios($org_id);
$activities = glob(aulatek_orgs_base_path() . "/$org_id/Panel/Actividades/*", GLOB_ONLYDIR) ?: [];
?> ?>
<div class="card pad"> <div class="card pad">
<div> <div>
<h1 class="card-title">Gestión del Centro: <?= htmlspecialchars($centro_id) ?></h1> <h1 class="card-title">Gestión de la Organización: <?= htmlspecialchars($org_name) ?></h1>
</div> </div>
<form method="post" action="?form=edit&org=<?= urlencode($org_id) ?>">
<div class="mb-3">
<label for="org_name" class="form-label">Nombre de la organización:</label>
<input required type="text" id="org_name" name="org_name" class="form-control" value="<?= htmlspecialchars($org_name) ?>">
</div>
<button type="submit" class="btn btn-primary">Guardar Cambios</button>
</form>
</div> </div>
<div class="card pad"> <div class="card pad">
<div> <div>
@@ -195,7 +219,7 @@ switch ($view_action) {
<thead class="table-dark"> <thead class="table-dark">
<tr> <tr>
<th>Icono</th><th>Nombre</th> <th>Icono</th><th>Nombre</th>
<th><a href="/sysadmin/aularios.php?action=new&centro=<?= urlencode($centro_id) ?>" class="btn btn-success">+ Nuevo</a></th> <th><a href="/sysadmin/aularios.php?action=new&org=<?= urlencode($org_id) ?>" class="btn btn-success">+ Nuevo</a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -203,7 +227,7 @@ switch ($view_action) {
<tr> <tr>
<td><img src="<?= htmlspecialchars($aula['icon'] ?: '/static/logo-entreaulas.png') ?>" alt="Icono" style="height: 50px;"></td> <td><img src="<?= htmlspecialchars($aula['icon'] ?: '/static/logo-entreaulas.png') ?>" alt="Icono" style="height: 50px;"></td>
<td><?= htmlspecialchars($aula['name'] ?: $aula_id) ?></td> <td><?= htmlspecialchars($aula['name'] ?: $aula_id) ?></td>
<td><a href="/sysadmin/aularios.php?action=edit&aulario=<?= urlencode($aula_id) ?>&centro=<?= urlencode($centro_id) ?>" class="btn btn-primary">Gestionar</a></td> <td><a href="/sysadmin/aularios.php?action=edit&aulario=<?= urlencode($aula_id) ?>&org=<?= urlencode($org_id) ?>" class="btn btn-primary">Gestionar</a></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
@@ -217,16 +241,16 @@ switch ($view_action) {
<thead class="table-dark"> <thead class="table-dark">
<tr> <tr>
<th>Foto</th><th>Nombre</th> <th>Foto</th><th>Nombre</th>
<th><a href="?action=new_activity&centro=<?= urlencode($centro_id) ?>" class="btn btn-success">+ Nuevo</a></th> <th><a href="?action=new_activity&org=<?= urlencode($org_id) ?>" class="btn btn-success">+ Nuevo</a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach ($activities as $ap): ?> <?php foreach ($activities as $ap): ?>
<?php $an = basename($ap); $img_path = "$ap/photo.jpg"; ?> <?php $an = basename($ap); $img_path = "$ap/photo.jpg"; ?>
<tr> <tr>
<td><img src="<?= file_exists($img_path) ? htmlspecialchars("/entreaulas/_filefetch.php?type=panel_actividades&centro=" . urlencode($centro_id) . "&activity=" . urlencode($an)) : '/static/logo-entreaulas.png' ?>" style="height: 50px;"></td> <td><img src="<?= file_exists($img_path) ? htmlspecialchars("/aulatek/_filefetch.php?type=panel_actividades&org=" . urlencode($org_id) . "&activity=" . urlencode($an)) : '/static/logo-entreaulas.png' ?>" style="height: 50px;"></td>
<td><?= htmlspecialchars($an) ?></td> <td><?= htmlspecialchars($an) ?></td>
<td><a href="?action=edit_activity&centro=<?= urlencode($centro_id) ?>&activity=<?= urlencode($an) ?>" class="btn btn-primary">Gestionar</a></td> <td><a href="?action=edit_activity&org=<?= urlencode($org_id) ?>&activity=<?= urlencode($an) ?>" class="btn btn-primary">Gestionar</a></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
@@ -237,23 +261,23 @@ switch ($view_action) {
break; break;
case "index": case "index":
default: default:
$all_centros = db_get_centros(); $all_organizaciones = db_get_organizaciones();
?> ?>
<div class="card pad"> <div class="card pad">
<div> <div>
<h1 class="card-title">Gestión de Centros</h1> <h1 class="card-title">Gestión de Organizaciones</h1>
<table class="table table-striped table-hover"> <table class="table table-striped table-hover">
<thead class="table-dark"> <thead class="table-dark">
<tr> <tr>
<th>Centro</th> <th>Organización</th>
<th><a href="?action=new" class="btn btn-success">+ Nuevo</a></th> <th style="text-align: right;"><a href="?action=new" class="btn btn-success">+ Nuevo</a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach ($all_centros as $c): ?> <?php foreach ($all_organizaciones as $o): ?>
<tr> <tr>
<td><?= htmlspecialchars($c['centro_id']) ?></td> <td><?= htmlspecialchars($o['org_name']) ?><br><small><?= htmlspecialchars($o['org_id']) ?></small></td>
<td><a href="?action=edit&centro=<?= urlencode($c['centro_id']) ?>" class="btn btn-primary">Gestionar</a></td> <td><a href="?action=edit&org=<?= urlencode($o['org_id']) ?>" class="btn btn-primary">Gestionar</a></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>

View File

@@ -13,6 +13,53 @@ function safe_username($value)
return $value; return $value;
} }
function render_users_mobile_styles()
{
?>
<style>
.users-mobile-stack .btn {
width: 100%;
}
.tenant-list {
max-height: 210px;
overflow: auto;
border: 1px solid #dee2e6;
border-radius: 0.5rem;
padding: 0.5rem 0.75rem;
}
.tenant-list .form-check {
margin-bottom: 0.45rem;
}
.aulas-list {
max-height: 220px;
overflow: auto;
border: 1px solid #dee2e6;
border-radius: 0.5rem;
padding: 0.5rem 0.75rem;
}
.aulas-list .form-check {
margin-right: 0.6rem;
margin-bottom: 0.5rem;
}
@media (max-width: 767.98px) {
.card.pad {
padding: 1rem !important;
}
.users-mobile-stack h1 {
font-size: 1.4rem;
}
.users-mobile-stack .accordion-button {
padding-top: 0.7rem;
padding-bottom: 0.7rem;
}
.users-mobile-stack .btn {
width: 100%;
}
}
</style>
<?php
}
switch ($_GET['form'] ?? '') { switch ($_GET['form'] ?? '') {
case 'save_edit': case 'save_edit':
$username = safe_username($_POST['username'] ?? ''); $username = safe_username($_POST['username'] ?? '');
@@ -29,16 +76,20 @@ switch ($_GET['form'] ?? '') {
} }
$aulas = array_values(array_filter(array_map('safe_aulario_id', $aulas))); $aulas = array_values(array_filter(array_map('safe_aulario_id', $aulas)));
$organization_input = $_POST['organization'] ?? [];
if (!is_array($organization_input)) {
$organization_input = [$organization_input];
}
$organizations = array_values(array_unique(array_filter(array_map('safe_organization_id', $organization_input))));
db_upsert_user([ db_upsert_user([
'username' => $username, 'username' => $username,
'display_name' => $_POST['display_name'] ?? '', 'display_name' => $_POST['display_name'] ?? '',
'email' => $_POST['email'] ?? '', 'email' => $_POST['email'] ?? '',
'permissions' => $permissions, 'permissions' => $permissions,
'entreaulas' => [ 'orgs' => $organizations,
'centro' => safe_centro_id($_POST['centro'] ?? ''), 'role' => $_POST['role'] ?? '',
'role' => $_POST['role'] ?? '', 'aulas' => $aulas,
'aulas' => $aulas,
],
]); ]);
header("Location: ?action=edit&user=" . urlencode($username) . "&_result=" . urlencode("Cambios guardados correctamente a las " . date("H:i:s") . " (hora servidor).")); header("Location: ?action=edit&user=" . urlencode($username) . "&_result=" . urlencode("Cambios guardados correctamente a las " . date("H:i:s") . " (hora servidor)."));
exit; exit;
@@ -48,9 +99,10 @@ switch ($_GET['form'] ?? '') {
switch ($_GET['action'] ?? '') { switch ($_GET['action'] ?? '') {
case 'add': case 'add':
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
$all_centros = db_get_centro_ids(); render_users_mobile_styles();
$all_organizations = db_get_organizations();
?> ?>
<form method="post" action="?form=save_edit"> <form method="post" action="?form=save_edit" class="users-mobile-stack">
<div class="card pad"> <div class="card pad">
<div> <div>
<h1 class="card-title">Agregar Nuevo Usuario</h1> <h1 class="card-title">Agregar Nuevo Usuario</h1>
@@ -83,21 +135,21 @@ switch ($_GET['action'] ?? '') {
</div> </div>
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header"> <h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseEntreaulas">EntreAulas</button> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAulatek">AulaTek</button>
</h2> </h2>
<div id="collapseEntreaulas" class="accordion-collapse collapse" data-bs-parent="#permissionsAccordion"> <div id="collapseAulatek" class="accordion-collapse collapse" data-bs-parent="#permissionsAccordion">
<div class="accordion-body"> <div class="accordion-body">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="entreaulas:access" id="entreaulas-access"> <input class="form-check-input" type="checkbox" name="permissions[]" value="aulatek:access" id="aulatek-access">
<label class="form-check-label" for="entreaulas-access">Acceso</label> <label class="form-check-label" for="aulatek-access">Acceso</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="entreaulas:docente" id="entreaulas-docente"> <input class="form-check-input" type="checkbox" name="permissions[]" value="aulatek:docente" id="aulatek-docente">
<label class="form-check-label" for="entreaulas-docente">Docente</label> <label class="form-check-label" for="aulatek-docente">Docente</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="entreaulas:proyectos:delete" id="entreaulas-proyectos-delete"> <input class="form-check-input" type="checkbox" name="permissions[]" value="aulatek:proyectos:delete" id="aulatek-proyectos-delete">
<label class="form-check-label" for="entreaulas-proyectos-delete">Eliminar Proyectos</label> <label class="form-check-label" for="aulatek-proyectos-delete">Eliminar Proyectos</label>
</div> </div>
</div> </div>
</div> </div>
@@ -125,18 +177,21 @@ switch ($_GET['action'] ?? '') {
</div> </div>
<div class="card pad"> <div class="card pad">
<div> <div>
<h2>EntreAulas: Configuración</h2> <h2>AulaTek: Configuración</h2>
<div class="mb-3"> <div class="mb-3">
<label for="centro" class="form-label">Centro asociado:</label> <label class="form-label">Tenant asociado:</label>
<select id="centro" name="centro" class="form-select"> <div class="tenant-list">
<option value="">-- Selecciona un centro --</option> <?php foreach ($all_organizations as $orgRow): $cid = $orgRow['org_id']; ?>
<?php foreach ($all_centros as $cid): ?> <div class="form-check">
<option value="<?= htmlspecialchars($cid) ?>"><?= htmlspecialchars($cid) ?></option> <input class="form-check-input" type="checkbox" name="organization[]" value="<?= htmlspecialchars($cid) ?>" id="tenant-<?= htmlspecialchars($cid) ?>">
<label class="form-check-label" for="tenant-<?= htmlspecialchars($cid) ?>"><?= htmlspecialchars($cid) ?></label>
</div>
<?php endforeach; ?> <?php endforeach; ?>
</select> </div>
<small class="text-muted">Marca uno o varios tenants.</small>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="role" class="form-label">Rol en EntreAulas:</label> <label for="role" class="form-label">Rol en AulaTek:</label>
<select id="role" name="role" class="form-select"> <select id="role" name="role" class="form-select">
<option value="">-- Selecciona un rol --</option> <option value="">-- Selecciona un rol --</option>
<option value="teacher">Profesor</option> <option value="teacher">Profesor</option>
@@ -153,6 +208,7 @@ switch ($_GET['action'] ?? '') {
case 'edit': case 'edit':
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
render_users_mobile_styles();
$username = safe_username($_GET['user'] ?? ''); $username = safe_username($_GET['user'] ?? '');
if (empty($username)) { if (empty($username)) {
die("Nombre de usuario inválido."); die("Nombre de usuario inválido.");
@@ -162,11 +218,26 @@ switch ($_GET['action'] ?? '') {
die("Usuario no encontrado."); die("Usuario no encontrado.");
} }
$userdata = db_build_auth_data($row); $userdata = db_build_auth_data($row);
$all_centros = db_get_centro_ids(); $all_organizations = db_get_organizations();
$user_centro = safe_centro_id($userdata['entreaulas']['centro'] ?? ''); $user_organizations = $userdata['orgs'] ?? [];
$aularios = $user_centro !== '' ? db_get_aularios($user_centro) : []; if (!is_array($user_organizations)) {
$user_organizations = [];
}
$user_organizations = array_values(array_unique(array_filter(array_map('safe_organization_id', $user_organizations))));
if (empty($user_organizations)) {
$legacy_organization = safe_organization_id($userdata['orgs'] ?? '');
if ($legacy_organization !== '') {
$user_organizations = [$legacy_organization];
}
}
$aularios_by_organization = [];
foreach ($user_organizations as $org_id) {
$aularios_by_organization[$org_id] = db_get_aularios($org_id);
}
$assigned_aulas = $userdata['aulatek']['aulas'] ?? ($userdata['entreaulas']['aulas'] ?? []);
?> ?>
<form method="post" action="?form=save_edit"> <form method="post" action="?form=save_edit" class="users-mobile-stack">
<div class="card pad"> <div class="card pad">
<div> <div>
<h1>Editar Usuario: <?= htmlspecialchars($username) ?></h1> <h1>Editar Usuario: <?= htmlspecialchars($username) ?></h1>
@@ -178,6 +249,18 @@ switch ($_GET['action'] ?? '') {
<label for="email" class="form-label">Correo electrónico:</label> <label for="email" class="form-label">Correo electrónico:</label>
<input type="email" id="email" name="email" value="<?= htmlspecialchars($userdata['email'] ?? '') ?>" class="form-control" required> <input type="email" id="email" name="email" value="<?= htmlspecialchars($userdata['email'] ?? '') ?>" class="form-control" required>
</div> </div>
<div class="mb-3">
<label class="form-label">Organizaciones asociadas:</label>
<div class="organization-list">
<?php foreach ($all_organizations as $orgRow): $org_id = $orgRow['org_id']; $org_name = $orgRow['org_name']; ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="organization[]" value="<?= htmlspecialchars($org_id) ?>" id="organization-<?= htmlspecialchars($org_id) ?>" <?= in_array($org_id, $user_organizations, true) ? 'checked' : '' ?>>
<label class="form-check-label" for="organization-<?= htmlspecialchars($org_id) ?>"><?= htmlspecialchars($org_name) ?></label>
</div>
<?php endforeach; ?>
</div>
<small class="text-muted">Marca una o varias organizaciones.</small>
</div>
<b>Permisos:</b> <b>Permisos:</b>
<div class="accordion mt-3" id="permissionsAccordion"> <div class="accordion mt-3" id="permissionsAccordion">
<div class="accordion-item"> <div class="accordion-item">
@@ -195,21 +278,21 @@ switch ($_GET['action'] ?? '') {
</div> </div>
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header"> <h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseEntreaulas">EntreAulas</button> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAulatek">AulaTek</button>
</h2> </h2>
<div id="collapseEntreaulas" class="accordion-collapse collapse" data-bs-parent="#permissionsAccordion"> <div id="collapseAulatek" class="accordion-collapse collapse" data-bs-parent="#permissionsAccordion">
<div class="accordion-body"> <div class="accordion-body">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="entreaulas:access" id="entreaulas-access" <?= in_array('entreaulas:access', $userdata['permissions'] ?? []) ? 'checked' : '' ?>> <input class="form-check-input" type="checkbox" name="permissions[]" value="aulatek:access" id="aulatek-access" <?= in_array('aulatek:access', $userdata['permissions'] ?? []) ? 'checked' : '' ?>>
<label class="form-check-label" for="entreaulas-access">Acceso</label> <label class="form-check-label" for="aulatek-access">Acceso</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="entreaulas:docente" id="entreaulas-docente" <?= in_array('entreaulas:docente', $userdata['permissions'] ?? []) ? 'checked' : '' ?>> <input class="form-check-input" type="checkbox" name="permissions[]" value="aulatek:docente" id="aulatek-docente" <?= in_array('aulatek:docente', $userdata['permissions'] ?? []) ? 'checked' : '' ?>>
<label class="form-check-label" for="entreaulas-docente">Docente</label> <label class="form-check-label" for="aulatek-docente">Docente</label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="entreaulas:proyectos:delete" id="entreaulas-proyectos-delete" <?= in_array('entreaulas:proyectos:delete', $userdata['permissions'] ?? []) ? 'checked' : '' ?>> <input class="form-check-input" type="checkbox" name="permissions[]" value="aulatek:proyectos:delete" id="aulatek-proyectos-delete" <?= in_array('aulatek:proyectos:delete', $userdata['permissions'] ?? []) ? 'checked' : '' ?>>
<label class="form-check-label" for="entreaulas-proyectos-delete">Eliminar Proyectos</label> <label class="form-check-label" for="aulatek-proyectos-delete">Eliminar Proyectos</label>
</div> </div>
</div> </div>
</div> </div>
@@ -238,37 +321,43 @@ switch ($_GET['action'] ?? '') {
</div> </div>
<div class="card pad"> <div class="card pad">
<div> <div>
<h2>EntreAulas: Configuración</h2> <h2>AulaTek: Configuración</h2>
<div class="mb-3"> <div class="mb-3">
<label for="centro" class="form-label">Centro asociado:</label> <label for="role" class="form-label">Rol en AulaTek:</label>
<select id="centro" name="centro" class="form-select" required>
<option value="" <?= empty($user_centro) ? 'selected' : '' ?>>-- Selecciona un centro --</option>
<?php foreach ($all_centros as $cid): ?>
<option value="<?= htmlspecialchars($cid) ?>" <?= $user_centro === $cid ? 'selected' : '' ?>><?= htmlspecialchars($cid) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="role" class="form-label">Rol en EntreAulas:</label>
<select id="role" name="role" class="form-select" required> <select id="role" name="role" class="form-select" required>
<option value="" <?= empty($userdata['entreaulas']['role'] ?? '') ? 'selected' : '' ?>>-- Selecciona un rol --</option> <option value="" <?= empty($userdata['aulatek']['role'] ?? '') ? 'selected' : '' ?>>-- Selecciona un rol --</option>
<option value="teacher" <?= ($userdata['entreaulas']['role'] ?? '') === 'teacher' ? 'selected' : '' ?>>Profesor</option> <option value="teacher" <?= ($userdata['aulatek']['role'] ?? '') === 'teacher' ? 'selected' : '' ?>>Profesor</option>
<option value="student" <?= ($userdata['entreaulas']['role'] ?? '') === 'student' ? 'selected' : '' ?>>Estudiante</option> <option value="student" <?= ($userdata['aulatek']['role'] ?? '') === 'student' ? 'selected' : '' ?>>Estudiante</option>
</select> </select>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Aulas asignadas: <small>(Guarda primero para actualizar la lista)</small></label><br> <label class="form-label">Aulas asignadas: <small>(Guarda primero para actualizar la lista)</small></label><br>
<?php foreach ($aularios as $aula_id => $aula_data): ?> <div class="aulas-list">
<div class="form-check form-check-inline"> <?php if (empty($aularios_by_organization)): ?>
<input class="form-check-input" type="checkbox" name="aulas[]" <small class="text-muted">No hay organizaciones asociadas para mostrar aulas.</small>
value="<?= htmlspecialchars($aula_id) ?>" <?php endif; ?>
id="aula-<?= htmlspecialchars($aula_id) ?>" <?php foreach ($aularios_by_organization as $org_id => $org_aularios): ?>
<?= in_array($aula_id, $userdata['entreaulas']['aulas'] ?? []) ? 'checked' : '' ?>> <div style="margin-bottom: 0.75rem; padding-bottom: 0.5rem; border-bottom: 1px solid #e9ecef;">
<label class="form-check-label" for="aula-<?= htmlspecialchars($aula_id) ?>"> <div style="font-weight: 600; margin-bottom: 0.4rem;"><?= htmlspecialchars($org_id) ?></div>
<?= htmlspecialchars($aula_data['name'] ?? $aula_id) ?> <?php if (empty($org_aularios)): ?>
</label> <small class="text-muted">Sin aulas en esta organización.</small>
</div> <?php else: ?>
<?php endforeach; ?> <?php foreach ($org_aularios as $aula_id => $aula_data): ?>
<?php $checkbox_id = 'aula-' . md5($org_id . '-' . $aula_id); ?>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="aulas[]"
value="<?= htmlspecialchars($aula_id) ?>"
id="<?= htmlspecialchars($checkbox_id) ?>"
<?= in_array($aula_id, $assigned_aulas, true) ? 'checked' : '' ?>>
<label class="form-check-label" for="<?= htmlspecialchars($checkbox_id) ?>">
<?= htmlspecialchars($aula_data['name'] ?? $aula_id) ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -286,34 +375,50 @@ switch ($_GET['action'] ?? '') {
case 'index': case 'index':
default: default:
require_once "_incl/pre-body.php"; require_once "_incl/pre-body.php";
render_users_mobile_styles();
$all_users = db_get_all_users(); $all_users = db_get_all_users();
?> ?>
<div class="card pad"> <div class="card pad users-mobile-stack">
<div> <div>
<h1>Gestión de Usuarios</h1> <div class="d-flex flex-column flex-md-row align-items-md-center justify-content-md-between gap-2 mb-2">
<h1 class="mb-0">Gestión de Usuarios</h1>
<a href="?action=add" class="btn btn-success">+ Nuevo</a>
</div>
<p>Desde esta sección puedes gestionar los usuarios del sistema.</p> <p>Desde esta sección puedes gestionar los usuarios del sistema.</p>
<table class="table table-striped table-hover"> <div class="d-none d-md-block table-responsive">
<thead class="table-dark"> <table class="table table-striped table-hover">
<tr> <thead class="table-dark">
<th>Usuario</th>
<th>Nombre</th>
<th>Correo</th>
<th><a href="?action=add" class="btn btn-success">+ Nuevo</a></th>
</tr>
</thead>
<tbody>
<?php foreach ($all_users as $u): ?>
<tr> <tr>
<td><?= htmlspecialchars($u['username']) ?></td> <th>Usuario</th>
<td><?= htmlspecialchars($u['display_name'] ?: 'N/A') ?></td> <th>Nombre</th>
<td><?= htmlspecialchars($u['email'] ?: 'N/A') ?></td> <th>Correo</th>
<td> <th></th>
<a href="?action=edit&user=<?= urlencode($u['username']) ?>" class="btn btn-primary">Editar</a>
</td>
</tr> </tr>
<?php endforeach; ?> </thead>
</tbody> <tbody>
</table> <?php foreach ($all_users as $u): ?>
<tr>
<td><?= htmlspecialchars($u['username']) ?></td>
<td><?= htmlspecialchars($u['display_name'] ?: 'N/A') ?></td>
<td><?= htmlspecialchars($u['email'] ?: 'N/A') ?></td>
<td>
<a href="?action=edit&user=<?= urlencode($u['username']) ?>" class="btn btn-primary btn-sm">Editar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="d-md-none">
<?php foreach ($all_users as $u): ?>
<div class="border rounded p-3 mb-2 bg-white">
<div><strong><?= htmlspecialchars($u['display_name'] ?: 'N/A') ?></strong></div>
<div class="text-muted small"><?= htmlspecialchars($u['username']) ?></div>
<div class="small"><?= htmlspecialchars($u['email'] ?: 'N/A') ?></div>
<a href="?action=edit&user=<?= urlencode($u['username']) ?>" class="btn btn-primary btn-sm mt-2">Editar</a>
</div>
<?php endforeach; ?>
</div>
</div> </div>
</div> </div>
<?php <?php