getConnection(); if (!function_exists('e')) { function e($value): string { return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); } } function sa_slugify(string $s): string { $t = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); if ($t === false) { $t = $s; } $t = strtolower(preg_replace('/[^a-zA-Z0-9]+/', '-', $t)); return trim($t, '-'); } if (empty($_SESSION['csrf_sa'])) { $_SESSION['csrf_sa'] = bin2hex(random_bytes(16)); } if (empty($_SESSION['csrf_switch'])) { $_SESSION['csrf_switch'] = bin2hex(random_bytes(16)); } $csrf = $_SESSION['csrf_sa']; $fields = ['name', 'slug', 'email', 'phone', 'address', 'city', 'postcode', 'country', 'vat_number']; /* ---------------------------------------------------------------------- * AZIONI (POST -> redirect) * -------------------------------------------------------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!hash_equals($csrf, $_POST['token'] ?? '')) { http_response_code(400); die('Richiesta non valida.'); } $action = $_POST['action'] ?? ''; $id = (int) ($_POST['idschool'] ?? 0); try { if ($action === 'save') { $data = []; foreach ($fields as $f) { $v = trim((string) ($_POST[$f] ?? '')); $data[$f] = ($v === '') ? null : $v; } if ($data['name'] === null) { header('Location: sa-schools.php?error=name' . ($id ? '&edit=' . $id : '')); exit; } $data['slug'] = sa_slugify($data['slug'] ?? $data['name']); if ($data['slug'] === '') { header('Location: sa-schools.php?error=slug' . ($id ? '&edit=' . $id : '')); exit; } $data['country'] = strtoupper(substr($data['country'] ?? 'IT', 0, 2)); $chk = $pdo->prepare("SELECT COUNT(*) FROM schools WHERE slug = ? AND idschool <> ?"); $chk->execute([$data['slug'], $id]); if ((int) $chk->fetchColumn() > 0) { header('Location: sa-schools.php?error=slugdup' . ($id ? '&edit=' . $id : '')); exit; } if ($id > 0) { $set = implode(', ', array_map(fn($f) => "`$f` = :$f", $fields)); $data['idschool'] = $id; $pdo->prepare("UPDATE schools SET $set WHERE idschool = :idschool")->execute($data); } else { $cols = implode(', ', array_map(fn($f) => "`$f`", $fields)); $vals = implode(', ', array_map(fn($f) => ":$f", $fields)); $pdo->prepare("INSERT INTO schools ($cols) VALUES ($vals)")->execute($data); $id = (int) $pdo->lastInsertId(); } // Owner opzionale: associa per email $warn = ''; $ownerEmail = trim((string) ($_POST['owner_email'] ?? '')); if ($ownerEmail !== '') { $u = $pdo->prepare("SELECT id FROM auth_users WHERE email = ? LIMIT 1"); $u->execute([$ownerEmail]); $uid = (int) $u->fetchColumn(); if ($uid > 0) { $pdo->prepare( "INSERT INTO school_user (user_id, idschool, school_role, active) VALUES (?, ?, 'owner', 'Y') ON DUPLICATE KEY UPDATE school_role = 'owner', active = 'Y'" )->execute([$uid, $id]); } else { $warn = '&warn=ownernotfound'; } } header('Location: sa-schools.php?msg=saved' . $warn); exit; } if ($action === 'toggle_status' && $id > 0) { $pdo->prepare( "UPDATE schools SET status = IF(status = 'suspended', 'active', 'suspended') WHERE idschool = ?" )->execute([$id]); header('Location: sa-schools.php?msg=status'); exit; } } catch (PDOException $ex) { error_log('sa-schools: ' . $ex->getMessage()); header('Location: sa-schools.php?error=db'); exit; } header('Location: sa-schools.php'); exit; } /* ---------------------------------------------------------------------- * DATI * -------------------------------------------------------------------- */ $edit = null; if (isset($_GET['edit'])) { $st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ?"); $st->execute([(int) $_GET['edit']]); $edit = $st->fetch() ?: null; } $schools = $pdo->query( "SELECT s.*, (SELECT COUNT(*) FROM school_user su WHERE su.idschool = s.idschool AND su.school_role = 'student' AND su.active = 'Y') AS n_students, (SELECT COUNT(*) FROM school_user su WHERE su.idschool = s.idschool AND su.school_role IN ('admin','teacher') AND su.active = 'Y') AS n_staff, (SELECT GROUP_CONCAT(CONCAT(u.first_name, ' ', u.last_name) SEPARATOR ', ') FROM school_user su JOIN auth_users u ON u.id = su.user_id WHERE su.idschool = s.idschool AND su.school_role = 'owner') AS owners FROM schools s ORDER BY s.name" )->fetchAll(); $msgMap = [ 'saved' => ['success', 'Scuola salvata correttamente.'], 'status' => ['success', 'Stato della scuola aggiornato.'], ]; $errMap = [ 'name' => 'Il nome della scuola è obbligatorio.', 'slug' => 'Slug non valido.', 'slugdup' => 'Questo slug è già usato da un\'altra scuola.', 'db' => 'Errore database, operazione non eseguita.', ]; $currentId = SchoolContext::id(); ?>