idbookingclass da cancellare * * Sicurezza: * - Verifica che la prenotazione appartenga a $user (iduser). * - Rispetta il limite orario option.maxbeforetimecancell (se presente). * * Comportamento: * - Come delete_lesson.php della webapp, ma senza email (per ora) e con * prepared statement + ownership check. * -------------------------------------------------------------------------- */ require_once __DIR__ . '/_bootstrap.php'; // Da qui: $user (autenticato) e $db (PDO) disponibili. $userId = (int) $user->id; // ========================================================================== // INPUT: accetta sia JSON body sia form POST // ========================================================================== $raw = file_get_contents('php://input'); $json = json_decode($raw, true); if (is_array($json)) { $bookingId = (int) ($json['booking_id'] ?? 0); } else { $bookingId = (int) ($_POST['booking_id'] ?? 0); } if ($bookingId <= 0) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'booking_id mancante']); exit; } // ========================================================================== // 1) Recupera la prenotazione E verifica che sia dell'utente // ========================================================================== $stmt = $db->prepare(" SELECT bc.idbookingclass, bc.status, ss.dateschedule, s.servicename FROM bookingclass bc LEFT JOIN serviceschedule ss ON bc.idserviceschedule = ss.idserviceschedule LEFT JOIN service s ON bc.idservice = s.idservice WHERE bc.idbookingclass = :bid AND bc.iduser = :uid LIMIT 1 "); $stmt->execute([':bid' => $bookingId, ':uid' => $userId]); $booking = $stmt->fetch(); if (!$booking) { // Non esiste, oppure non appartiene all'utente: stessa risposta (non rivelare). http_response_code(404); echo json_encode(['success' => false, 'error' => 'Prenotazione non trovata']); exit; } // ========================================================================== // 2) Controllo limite orario (option.maxbeforetimecancell), difensivo // ========================================================================== $maxBeforeHours = null; try { $optStmt = $db->query("SELECT maxbeforetimecancell FROM `option` LIMIT 1"); $optRow = $optStmt->fetch(); if ($optRow && isset($optRow['maxbeforetimecancell'])) { $maxBeforeHours = (int) $optRow['maxbeforetimecancell']; } } catch (Throwable $e) { // Se la tabella/colonna non c'è, non blocchiamo per questo motivo. $maxBeforeHours = null; } if ($maxBeforeHours !== null && !empty($booking['dateschedule'])) { $now = new DateTime(); $classTime = new DateTime($booking['dateschedule']); // Ore mancanti alla lezione (può essere negativo se già passata). $diffSeconds = $classTime->getTimestamp() - $now->getTimestamp(); $hoursToClass = $diffSeconds / 3600; if ($hoursToClass < $maxBeforeHours) { http_response_code(409); echo json_encode([ 'success' => false, 'error' => "Troppo tardi per cancellare (minimo {$maxBeforeHours}h prima).", 'code' => 'too_late', ]); exit; } } // ========================================================================== // 3) Cancellazione (con doppio vincolo di sicurezza nella WHERE) // ========================================================================== $del = $db->prepare(" DELETE FROM bookingclass WHERE idbookingclass = :bid AND iduser = :uid LIMIT 1 "); $del->execute([':bid' => $bookingId, ':uid' => $userId]); if ($del->rowCount() < 1) { http_response_code(500); echo json_encode(['success' => false, 'error' => 'Cancellazione non riuscita']); exit; } // ========================================================================== // OUTPUT // ========================================================================== echo json_encode([ 'success' => true, 'booking_id' => $bookingId, 'message' => 'Lezione cancellata', ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);