134 lines
5.1 KiB
PHP
134 lines
5.1 KiB
PHP
<?php
|
|
require_once __DIR__ . '/bootstrap.php';
|
|
|
|
/**
|
|
* Endpoint pubblico LISTA eventi (sola lettura).
|
|
* Ritorna gli eventi PUBBLICATI e NON ancora terminati, con posti/prezzo/gallery.
|
|
*
|
|
* Parametri (query string):
|
|
* ?id=12 -> un solo evento
|
|
* ?ids=12,15,20 -> solo questi eventi (nell'ordine per data)
|
|
* ?limit=3 -> massimo N eventi
|
|
* Senza parametri: tutti i pubblicati futuri, per data crescente.
|
|
*
|
|
* Regole di visibilità:
|
|
* status = 'published' AND COALESCE(ends_at, starts_at) >= NOW()
|
|
* (l'evento sparisce da solo quando è terminato)
|
|
*/
|
|
try {
|
|
$pdo = pdo_conn();
|
|
|
|
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
|
$idsParam = trim($_GET['ids'] ?? '');
|
|
$limit = isset($_GET['limit']) ? max(1, min(50, (int) $_GET['limit'])) : 0;
|
|
|
|
$where = ["e.status IN ('published','scheduled')", "COALESCE(e.ends_at, e.starts_at) >= NOW()"];
|
|
$params = [];
|
|
|
|
if ($id > 0) {
|
|
$where[] = 'e.id = ?';
|
|
$params[] = $id;
|
|
} elseif ($idsParam !== '') {
|
|
$ids = array_values(array_filter(array_map('intval', explode(',', $idsParam)), function ($v) {
|
|
return $v > 0;
|
|
}));
|
|
if (!empty($ids)) {
|
|
$where[] = 'e.id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')';
|
|
foreach ($ids as $v) {
|
|
$params[] = $v;
|
|
}
|
|
} else {
|
|
send_json(['ok' => true, 'count' => 0, 'events' => []]);
|
|
}
|
|
}
|
|
|
|
$sql = "SELECT e.*, u.first_name AS cf, u.last_name AS cl,
|
|
COALESCE(b.occupied, 0) AS occupied,
|
|
COALESCE(w.waiting, 0) AS waiting
|
|
FROM events e
|
|
LEFT JOIN auth_users u ON u.id = e.user_id
|
|
LEFT JOIN (
|
|
SELECT event_id, SUM(seats) AS occupied
|
|
FROM event_bookings WHERE status IN ('confirmed','pending','offered')
|
|
GROUP BY event_id
|
|
) b ON b.event_id = e.id
|
|
LEFT JOIN (
|
|
SELECT event_id, SUM(seats) AS waiting
|
|
FROM event_bookings WHERE status = 'waiting'
|
|
GROUP BY event_id
|
|
) w ON w.event_id = e.id
|
|
WHERE " . implode(' AND ', $where) . "
|
|
ORDER BY e.starts_at ASC";
|
|
|
|
if ($limit > 0) {
|
|
$sql .= ' LIMIT ' . (int) $limit;
|
|
}
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$symbols = ['EUR' => '€', 'USD' => '$', 'GBP' => '£', 'CHF' => 'CHF'];
|
|
$events = [];
|
|
|
|
foreach ($rows as $r) {
|
|
$maxSeats = (int) $r['max_seats'];
|
|
$occupied = (int) $r['occupied'];
|
|
$remaining = max(0, $maxSeats - $occupied);
|
|
|
|
$gallery = [];
|
|
if (!empty($r['gallery'])) {
|
|
$g = json_decode($r['gallery'], true);
|
|
if (is_array($g)) {
|
|
foreach ($g as $path) {
|
|
if (is_string($path) && $path !== '') {
|
|
$gallery[] = public_url($path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$organizer = trim((string) $r['organizer_name']) !== ''
|
|
? $r['organizer_name']
|
|
: trim(($r['cf'] ?? '') . ' ' . ($r['cl'] ?? ''));
|
|
|
|
$events[] = [
|
|
'id' => (int) $r['id'],
|
|
'title' => $r['title'],
|
|
'slug' => $r['slug'],
|
|
'status' => $r['status'],
|
|
'scheduled' => $r['status'] === 'scheduled',
|
|
'bookable' => $r['status'] === 'published',
|
|
'publish_at' => $r['publish_at'],
|
|
'description' => $r['description'], // HTML (sanificare al rendering in WP)
|
|
'instructions' => $r['instructions'],
|
|
'what_to_bring' => $r['what_to_bring'],
|
|
'suitable_for' => $r['suitable_for'],
|
|
'organizer' => $organizer !== '' ? $organizer : null,
|
|
'starts_at' => $r['starts_at'],
|
|
'ends_at' => $r['ends_at'],
|
|
'address' => $r['address'],
|
|
'lat' => $r['lat'] !== null ? (float) $r['lat'] : null,
|
|
'lng' => $r['lng'] !== null ? (float) $r['lng'] : null,
|
|
'cost' => (float) $r['cost'],
|
|
'currency' => $r['currency'],
|
|
'currency_symbol' => $symbols[$r['currency']] ?? $r['currency'],
|
|
'color' => $r['color'],
|
|
'cover_image' => public_url($r['cover_image']),
|
|
'gallery' => $gallery,
|
|
'max_seats' => $maxSeats,
|
|
'max_per_booking' => (int) $r['max_per_booking'],
|
|
'occupied' => $occupied,
|
|
'remaining' => $remaining,
|
|
'sold_out' => $remaining <= 0,
|
|
'waitlist_enabled' => ($r['waitlist_enabled'] ?? 'N') === 'Y',
|
|
'waiting' => (int) $r['waiting'],
|
|
];
|
|
}
|
|
|
|
send_json(['ok' => true, 'count' => count($events), 'events' => $events]);
|
|
} catch (Throwable $ex) {
|
|
error_log('[api/events] ' . $ex->getMessage());
|
|
send_json(['ok' => false, 'error' => 'Errore nel recupero degli eventi.'], 500);
|
|
}
|