query( "SELECT SUM(status IN ('sent','delivered') AND is_sandbox = 0) AS total_sent, SUM(status = 'failed' AND is_sandbox = 0) AS total_failed FROM delivery_log" )->fetch(); $total_attempts = (int) $stats['total_sent'] + (int) $stats['total_failed']; $stats['success_rate'] = $total_attempts > 0 ? round(((int) $stats['total_sent'] / $total_attempts) * 100, 1) : 0.0; // Paginated log entries — pass ?all=1 to skip pagination (used by DataTables) $fetchAll = isset($_GET['all']) && $_GET['all'] === '1'; $perPage = 50; $page = max(1, (int) ($_GET['page'] ?? 1)); $offset = ($page - 1) * $perPage; $limitClause = $fetchAll ? '' : "LIMIT $perPage OFFSET $offset"; // $perPage and $offset are cast ints — no injection risk from interpolation $entries = $db->query( "SELECT dl.id, dl.mobile_number, dl.status, dl.sent_at, dl.delivered_at, dl.error_message, CONCAT(a.first_name, ' ', a.last_name) AS attendee_name, COALESCE(t.name, 'Custom message') AS template_name, COALESCE(sj.custom_body, t.body) AS message_body, sj.id AS job_id FROM delivery_log dl LEFT JOIN attendees a ON a.id = dl.attendee_id LEFT JOIN send_jobs sj ON sj.id = dl.send_job_id LEFT JOIN sms_templates t ON t.id = sj.template_id ORDER BY dl.sent_at DESC $limitClause" )->fetchAll(); $total = (int) $db->query('SELECT COUNT(*) FROM delivery_log')->fetchColumn(); json_out([ 'stats' => $stats, 'entries' => $entries, 'total' => $total, 'page' => $fetchAll ? 1 : $page, 'per_page' => $fetchAll ? $total : $perPage, 'pages' => $fetchAll ? 1 : (int) ceil($total / $perPage), ]); } catch (PDOException $e) { error_out('Database error: ' . $e->getMessage(), 500); }