diff --git a/.env b/.env index 1d4b7a7..c6c153a 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ APP_ENV=production -APP_DEBUG=false +APP_DEBUG=true APP_KEY=base64:aj3bR0zA9I8nZ1Rm5alncE4QFTPNoHVkd8YSRJEImwY= APP_URL=https://yogibook.yogasoul.it diff --git a/public/cancella-prenotazione.php b/public/cancella-prenotazione.php new file mode 100644 index 0000000..2980324 --- /dev/null +++ b/public/cancella-prenotazione.php @@ -0,0 +1,139 @@ +connect_error) { + die("Connessione al database fallita: " . $conn->connect_error); +} + +// Recupera parametri GET: idbookingclass e token +if (isset($_GET['idbookingclass']) && isset($_GET['token'])) { + $idbookingclass = $_GET['idbookingclass']; + $token = $_GET['token']; + + // Verifica validità: token corrisponde, lezione futura e prima delle 12:00 del giorno + $query = "SELECT * FROM bookingclass + WHERE idbookingclass = ? + AND cancellation_token = ? + AND status = 'booked' + AND bookingstart > NOW() + AND NOW() <= DATE_ADD(DATE(bookingstart), INTERVAL 12 HOUR)"; + $stmt = $conn->prepare($query); + + if ($stmt) { + $stmt->bind_param("is", $idbookingclass, $token); + $stmt->execute(); + $result = $stmt->get_result(); + + if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + $bookingstart = $row['bookingstart']; + $newtimeformat = date("d-m-Y H:i", strtotime($bookingstart)); + + // Aggiorna status a 'cancelled' e invalida token + $updateQuery = "UPDATE bookingclass + SET status = 'cancelled', cancellation_token = NULL + WHERE idbookingclass = ?"; + $updateStmt = $conn->prepare($updateQuery); + $updateStmt->bind_param("i", $idbookingclass); + $updateStmt->execute(); + + // Recupera dati utente e servizio + $dataQuery = "SELECT bookingclass.*, auth_users.*, service.* + FROM bookingclass + LEFT JOIN auth_users ON bookingclass.iduser = auth_users.id + LEFT JOIN service ON bookingclass.idservice = service.idservice + WHERE bookingclass.idbookingclass = ?"; + $dataStmt = $conn->prepare($dataQuery); + $dataStmt->bind_param("i", $idbookingclass); + $dataStmt->execute(); + $dataResult = $dataStmt->get_result(); + $dataRow = $dataResult->fetch_assoc(); + + $emailuser = $dataRow['email']; + $firstname = $dataRow['first_name'] ?? 'Utente'; + + // Prepara messaggio email + $messagecancel = "
Ciao $firstname ,
+La tua lezione è stata cancellata con successo!
+Dettaglio: $newtimeformat
+Per vedere e gestire le tue lezioni clicca qui: https://yogibook.yogasoul.it
+Ci vediamo sul tappetino!
+Il Team Yogasoul
"; + + // Definisci $messageedit per il template + $messageedit = $messagecancel; + + // Definisci $buttonedit (pulsante generico) + $buttonedit = " + YogiBook - YogaSoul + "; + + require 'phpmailer/src/Exception.php'; + require 'phpmailer/src/PHPMailer.php'; + require 'phpmailer/src/SMTP.php'; + + $mail = new PHPMailer(true); + try { + $mail->isSMTP(); + $mail->Host = 'mail.yogasoul.it'; + $mail->SMTPAuth = true; + $mail->Username = 'info@yogasoul.it'; + $mail->Password = '!Testolina88'; + $mail->SMTPSecure = 'tls'; + $mail->Port = 587; + + // Verifica esistenza file template + if (!file_exists('mail/emailtemplate2.php')) { + throw new Exception("File emailtemplate2.php non trovato."); + } + include('mail/emailtemplate2.php'); + + // Verifica che $mailmessage1 esista + if (!isset($mailmessage1)) { + throw new Exception("Variabile \$mailmessage1 non definita in emailtemplate2.php."); + } + + // Sostituisci placeholder (per compatibilità) + $htmlContent = str_replace('{message}', $messagecancel, $mailmessage1); + + $mail->From = 'info@yogasoul.it'; + $mail->FromName = 'YogiBook [YogaSoul]'; + $mail->addAddress($emailuser); + $mail->Subject = "YogiBook - Lezione cancellata con successo!"; + $mail->Body = $htmlContent; + $mail->AltBody = 'This is the body in plain text for non-HTML mail clients'; + + $mail->send(); + + // Mostra landing di conferma + echo "La lezione del $newtimeformat è stata cancellata con successo.
"; + echo "Torna al portale"; + } catch (Exception $e) { + echo "Errore invio email: " . $mail->ErrorInfo; + } + } else { + echo "Link non valido o scaduto."; + } + $stmt->close(); + } else { + echo "Errore nella preparazione della query: " . $conn->error; + } +} else { + echo "Parametri mancanti."; +} + +$conn->close(); + diff --git a/public/fetch_available_classes.php b/public/fetch_available_classes.php new file mode 100644 index 0000000..e1ebbfb --- /dev/null +++ b/public/fetch_available_classes.php @@ -0,0 +1,26 @@ + 'Connessione al database fallita'])); +} + +// Query per ottenere tutte le classi disponibili +$sql = "SELECT id, servicename, day, time FROM classes ORDER BY servicename, day, time"; +$result = mysqli_query($conn, $sql); + +$classes = []; +while ($row = mysqli_fetch_assoc($result)) { + $classes[] = [ + 'id' => $row['id'], + 'servicename' => $row['servicename'], + 'day' => $row['day'], + 'time' => $row['time'] + ]; +} + +mysqli_close($conn); +header('Content-Type: application/json'); +echo json_encode($classes); diff --git a/public/fetch_available_dates.php b/public/fetch_available_dates.php new file mode 100644 index 0000000..20aee7c --- /dev/null +++ b/public/fetch_available_dates.php @@ -0,0 +1,35 @@ + 'Connessione al database fallita'])); +} + +$class_id = isset($_POST['class_id']) ? intval($_POST['class_id']) : 0; + +if ($class_id <= 0) { + die(json_encode(['error' => 'ID classe non valido'])); +} + +// Query per ottenere le date disponibili per la classe specificata +// Supponiamo che ci sia una tabella 'class_schedule' con le date disponibili +$sql = "SELECT DISTINCT DATE(bookingstart) as available_date + FROM class_schedule + WHERE class_id = ? + ORDER BY available_date"; +$stmt = mysqli_prepare($conn, $sql); +mysqli_stmt_bind_param($stmt, 'i', $class_id); +mysqli_stmt_execute($stmt); +$result = mysqli_stmt_get_result($stmt); + +$availableDates = []; +while ($row = mysqli_fetch_assoc($result)) { + $availableDates[] = $row['available_date']; +} + +mysqli_stmt_close($stmt); +mysqli_close($conn); +header('Content-Type: application/json'); +echo json_encode(['availableDates' => $availableDates]); diff --git a/public/promemoria-cron.php b/public/promemoria-cron.php new file mode 100644 index 0000000..c120d85 --- /dev/null +++ b/public/promemoria-cron.php @@ -0,0 +1,162 @@ +connect_error) { + die("Connessione al database fallita: " . $conn->connect_error); +} + +// Inizializza contatore e log +$emailCount = 0; +$errors = []; +$logFile = 'promemoria_cron_log.txt'; +$logMessage = "Esecuzione cron: " . date('Y-m-d H:i:s') . "\n"; + +// Seleziona prenotazioni per domani +$tomorrow = date('Y-m-d', strtotime('+1 day')); +$query = "SELECT bc.*, au.email, au.first_name, s.servicename + FROM bookingclass bc + LEFT JOIN auth_users au ON bc.iduser = au.id + LEFT JOIN service s ON bc.idservice = s.idservice + WHERE DATE(bc.bookingstart) = ? AND bc.status = 'booked'"; + +$stmt = $conn->prepare($query); +if (!$stmt) { + $errors[] = "Errore preparazione query: " . $conn->error; + file_put_contents($logFile, $logMessage . "Errore query: " . $conn->error . "\n", FILE_APPEND); + echo "Errore preparazione query: " . $conn->error; + exit; +} + +$stmt->bind_param("s", $tomorrow); +$stmt->execute(); +$result = $stmt->get_result(); + +if ($result->num_rows === 0) { + $logMessage .= "Nessuna prenotazione trovata per domani.\n"; + file_put_contents($logFile, $logMessage, FILE_APPEND); + echo "Nessuna prenotazione trovata per domani.\n"; + exit; +} + +while ($row = $result->fetch_assoc()) { + $idbookingclass = $row['idbookingclass']; + $token = $row['cancellation_token']; + + // Genera token se assente + if (empty($token)) { + $token = bin2hex(random_bytes(32)); + $updateQuery = "UPDATE bookingclass SET cancellation_token = ? WHERE idbookingclass = ?"; + $updateStmt = $conn->prepare($updateQuery); + if ($updateStmt) { + $updateStmt->bind_param("si", $token, $idbookingclass); + $updateStmt->execute(); + } else { + $errors[] = "Errore preparazione query token per ID $idbookingclass: " . $conn->error; + } + } + + $firstname = $row['first_name'] ?? 'Utente'; + $emailuser = $row['email']; + $servicename = $row['servicename'] ?? 'Sconosciuta'; + $bookingstart = $row['bookingstart']; + $dataformat = date("d-m-Y H:i", strtotime($bookingstart)); + + // Verifica email valida + if (!filter_var($emailuser, FILTER_VALIDATE_EMAIL)) { + $errors[] = "Email non valida per ID $idbookingclass: $emailuser"; + $logMessage .= "Email non valida per ID $idbookingclass: $emailuser\n"; + continue; + } + + // Link cancellazione + $link = "https://yogibook.yogasoul.it/cancella-prenotazione.php?idbookingclass=$idbookingclass&token=$token"; + + // Messaggio email + $message = "Ciao $firstname,
+Promemoria: domani hai la lezione $servicename del $dataformat.
+Puoi cancellarla fino alle 12:00 cliccando qui:
+Cancella prenotazione +Ci vediamo sul tappetino!
+Il Team Yogasoul
"; + + // Definisci $messageedit per il template + $messageedit = $message; + + // Definisci $buttonedit (vuoto o pulsante generico) + $buttonedit = " + YogiBook - YogaSoul + "; + + require 'phpmailer/src/Exception.php'; + require 'phpmailer/src/PHPMailer.php'; + require 'phpmailer/src/SMTP.php'; + + $mail = new PHPMailer(true); + try { + $mail->isSMTP(); + $mail->Host = 'mail.yogasoul.it'; + $mail->SMTPAuth = true; + $mail->Username = 'info@yogasoul.it'; + $mail->Password = '!Testolina88'; + $mail->SMTPSecure = 'tls'; + $mail->Port = 587; + + // Verifica esistenza file template + if (!file_exists('mail/emailtemplate2.php')) { + throw new Exception("File emailtemplate2.php non trovato."); + } + include('mail/emailtemplate2.php'); + + // Verifica che $mailmessage1 esista + if (!isset($mailmessage1)) { + throw new Exception("Variabile \$mailmessage1 non definita in emailtemplate2.php."); + } + + // Sostituisci placeholder (anche se non usato, per compatibilità) + $htmlContent = str_replace('{message}', $message, $mailmessage1); + + $mail->From = 'info@yogasoul.it'; + $mail->FromName = 'YogiBook [YogaSoul]'; + $mail->addAddress($emailuser); + $mail->Subject = "YogiBook - Promemoria lezione domani!"; + $mail->Body = $htmlContent; + $mail->AltBody = 'Promemoria lezione.'; + + $mail->send(); + $emailCount++; + $logMessage .= "Email inviata a $emailuser per lezione ID $idbookingclass ($dataformat)\n"; + } catch (Exception $e) { + $errors[] = "Errore invio email a $emailuser (ID $idbookingclass): " . $mail->ErrorInfo; + $logMessage .= "Errore invio a $emailuser (ID $idbookingclass): " . $mail->ErrorInfo . "\n"; + } + + sleep(2); // Delay 2 secondi +} + +// Scrivi log +file_put_contents($logFile, $logMessage, FILE_APPEND); + +// Output debug +echo "Esecuzione completata: $emailCount email inviate.\n"; +if (!empty($errors)) { + echo "Errori rilevati:\n"; + foreach ($errors as $error) { + echo "- $error\n"; + } +} else { + echo "Nessun errore.\n"; +} +echo "Dettagli nel file di log: $logFile\n"; + +$conn->close(); diff --git a/public/promemoria_cron_log.txt b/public/promemoria_cron_log.txt new file mode 100644 index 0000000..1e0540e --- /dev/null +++ b/public/promemoria_cron_log.txt @@ -0,0 +1,4 @@ +Esecuzione cron: 2025-10-08 13:39:42 +Esecuzione cron: 2025-10-08 13:40:48 +Esecuzione cron: 2025-10-08 13:54:46 +Email inviata a info@claudiosironi.com per lezione ID 8 (09-10-2025 18:15) diff --git a/public/reprogram_class.php b/public/reprogram_class.php new file mode 100644 index 0000000..08e2128 --- /dev/null +++ b/public/reprogram_class.php @@ -0,0 +1,57 @@ + false, 'message' => 'Connessione al database fallita'])); +} + +$id_booking_class = isset($_POST['id']) ? intval($_POST['id']) : 0; +$class_id = isset($_POST['class_id']) ? intval($_POST['class_id']) : 0; +$new_date = isset($_POST['new_date']) ? $_POST['new_date'] : ''; + +if ($id_booking_class <= 0 || $class_id <= 0 || empty($new_date)) { + die(json_encode(['success' => false, 'message' => 'Dati non validi'])); +} + +// Ottieni i dettagli della classe attuale +$sql = "SELECT bookingstart, servicename, day, time FROM bookingclass WHERE idbookingclass = ?"; +$stmt = mysqli_prepare($conn, $sql); +mysqli_stmt_bind_param($stmt, 'i', $id_booking_class); +mysqli_stmt_execute($stmt); +$result = mysqli_stmt_get_result($stmt); +$current_class = mysqli_fetch_assoc($result); + +if (!$current_class) { + die(json_encode(['success' => false, 'message' => 'Lezione non trovata'])); +} + +// Ottieni i dettagli della nuova classe +$sql = "SELECT servicename, day, time FROM classes WHERE id = ?"; +$stmt = mysqli_prepare($conn, $sql); +mysqli_stmt_bind_param($stmt, 'i', $class_id); +mysqli_stmt_execute($stmt); +$result = mysqli_stmt_get_result($stmt); +$new_class = mysqli_fetch_assoc($result); + +if (!$new_class) { + die(json_encode(['success' => false, 'message' => 'Classe non trovata'])); +} + +// Aggiorna la lezione +$sql = "UPDATE bookingclass + SET bookingstart = ?, prevbookingstart = ?, servicename = ?, day = ?, time = ? + WHERE idbookingclass = ?"; +$stmt = mysqli_prepare($conn, $sql); +$new_bookingstart = $new_date . ' ' . $new_class['time'] . ':00'; +mysqli_stmt_bind_param($stmt, 'sssssi', $new_bookingstart, $current_class['bookingstart'], $new_class['servicename'], $new_class['day'], $new_class['time'], $id_booking_class); + +if (mysqli_stmt_execute($stmt)) { + echo json_encode(['success' => true]); +} else { + echo json_encode(['success' => false, 'message' => 'Errore durante l\'aggiornamento della lezione']); +} + +mysqli_stmt_close($stmt); +mysqli_close($conn); diff --git a/public/situationusers.php b/public/situationusers.php index 0a9b585..0ffaeb2 100644 --- a/public/situationusers.php +++ b/public/situationusers.php @@ -17,7 +17,7 @@ SELECT auth_users.id AS id_utente, auth_users.first_name AS nome_utente, auth_users.last_name AS cognome_utente, - auth_users.email AS email_utente, -- Aggiungiamo l'email dell'utente + auth_users.email AS email_utente, COALESCE(lezioni_acquistate, 0) AS lezioni_acquistate, COUNT(CASE WHEN bookingclass.bookingstart <= CURDATE() AND bookingclass.lostlesson = 'N' THEN 1 END) AS lezioni_praticate, COUNT(CASE WHEN bookingclass.bookingstart > CURDATE() THEN 1 END) AS lezioni_programmate, @@ -70,7 +70,7 @@ if (!$result) { - + @@ -84,13 +84,15 @@ if (!$result) { - - - + + + @@ -456,210 +515,310 @@ if (!$result) { - - - - - -