131 lines
4.7 KiB
PHP
131 lines
4.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* SchoolScope
|
|
* Verifica che record e utenti appartengano alla scuola corrente.
|
|
* Da usare in ogni pagina/endpoint che riceve un ID dall'esterno.
|
|
*
|
|
* Uso:
|
|
* SchoolScope::assert('bookingclass', $idbookingclass); // blocca con 403 se non è della scuola
|
|
* if (!SchoolScope::belongs('service', $id)) { ... }
|
|
* SchoolScope::assertMember($userid); // utente iscritto alla scuola
|
|
* SchoolScope::addMember($newUserId); // iscrive un nuovo utente come allievo
|
|
*/
|
|
|
|
if (!class_exists('DBHandlerSelect')) {
|
|
require_once __DIR__ . '/db-functions.php';
|
|
}
|
|
|
|
class SchoolScope
|
|
{
|
|
/**
|
|
* Tabelle ammesse e relativa chiave primaria.
|
|
* (whitelist: i nomi non arrivano mai dall'esterno nella query)
|
|
*/
|
|
const TABLES = [
|
|
'bookingclass' => 'idbookingclass',
|
|
'serviceschedule' => 'idserviceschedule',
|
|
'service' => 'idservice',
|
|
'servicecategory' => 'idservicecategory',
|
|
'associateclass' => 'idassociateclass',
|
|
'propagation' => 'idpropagation',
|
|
'orderbook' => 'idorderbook',
|
|
'employee' => 'idemployee',
|
|
'dayoff' => 'iddayoff',
|
|
'certificateuserprofile' => 'idcertificateuserprofile',
|
|
'events' => 'id',
|
|
'event_bookings' => 'id',
|
|
'event_locations' => 'id',
|
|
'school_images' => 'idimage',
|
|
'products' => 'idproduct',
|
|
'product_variants' => 'idvariant',
|
|
'product_services' => 'idproductservice',
|
|
'product_images' => 'idimage',
|
|
'orderbook_services' => 'idorderbookservice',
|
|
'memberships' => 'idmembership',
|
|
'gift_vouchers' => 'idvoucher',
|
|
'coupons' => 'idcoupon',
|
|
'coupon_products' => 'idcouponproduct',
|
|
'coupon_redemptions' => 'idredemption',
|
|
];
|
|
|
|
/** Il record $id della tabella appartiene alla scuola corrente? */
|
|
public static function belongs(string $table, int $id, ?int $idschool = null): bool
|
|
{
|
|
if ($id <= 0 || !isset(self::TABLES[$table])) {
|
|
return false;
|
|
}
|
|
$pk = self::TABLES[$table];
|
|
$st = self::pdo()->prepare("SELECT 1 FROM `$table` WHERE `$pk` = ? AND idschool = ? LIMIT 1");
|
|
$st->execute([$id, $idschool ?? SchoolContext::id()]);
|
|
return (bool) $st->fetchColumn();
|
|
}
|
|
|
|
/** Come belongs(), ma blocca la richiesta (403) se il record non è della scuola */
|
|
public static function assert(string $table, int $id): void
|
|
{
|
|
if (!self::belongs($table, $id)) {
|
|
self::deny('Elemento non trovato in questa scuola.');
|
|
}
|
|
}
|
|
|
|
/** L'utente è membro attivo della scuola corrente? */
|
|
public static function isMember(int $userId, ?int $idschool = null): bool
|
|
{
|
|
if ($userId <= 0) {
|
|
return false;
|
|
}
|
|
$st = self::pdo()->prepare(
|
|
"SELECT 1 FROM school_user WHERE user_id = ? AND idschool = ? AND active = 'Y' LIMIT 1"
|
|
);
|
|
$st->execute([$userId, $idschool ?? SchoolContext::id()]);
|
|
return (bool) $st->fetchColumn();
|
|
}
|
|
|
|
public static function assertMember(int $userId): void
|
|
{
|
|
if (!self::isMember($userId)) {
|
|
self::deny('Utente non iscritto a questa scuola.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Iscrive un utente alla scuola corrente (default: allievo).
|
|
* Se è già membro non cambia il ruolo, lo riattiva soltanto.
|
|
*/
|
|
public static function addMember(int $userId, string $role = 'student', ?int $idschool = null): void
|
|
{
|
|
if ($userId <= 0) {
|
|
return;
|
|
}
|
|
self::pdo()->prepare(
|
|
"INSERT INTO school_user (user_id, idschool, school_role, active)
|
|
VALUES (?, ?, ?, 'Y')
|
|
ON DUPLICATE KEY UPDATE active = 'Y'"
|
|
)->execute([$userId, $idschool ?? SchoolContext::id(), $role]);
|
|
}
|
|
|
|
/**
|
|
* Risposta 403. Per le chiamate AJAX restituisce JSON,
|
|
* così il .fail() di jQuery scatta e il messaggio è leggibile.
|
|
*/
|
|
private static function deny(string $msg): void
|
|
{
|
|
http_response_code(403);
|
|
$isAjax = (($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest')
|
|
|| strpos($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') !== false;
|
|
if ($isAjax) {
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode(['success' => false, 'error' => $msg]);
|
|
} else {
|
|
echo htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
exit;
|
|
}
|
|
|
|
private static function pdo(): PDO
|
|
{
|
|
return DBHandlerSelect::getInstance()->getConnection();
|
|
}
|
|
}
|