Files
skyview.astronomiemuseum.de/public/telegram/broadcast_test.php
T
2026-04-08 13:14:40 +02:00

382 lines
13 KiB
PHP

<?php
declare(strict_types=1);
ini_set('display_errors', '1');
error_reporting(E_ALL);
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: ../login.php');
exit;
}
require_once __DIR__ . '/../auth_helpers.php';
$config = require __DIR__ . '/../../config/database.php';
$telegramConfig = require __DIR__ . '/../../config/telegram.php';
require_once __DIR__ . '/../../scripts/telegram/lib/message_footer.php';
require_once __DIR__ . '/../../scripts/telegram/lib/http.php';
$dsn = sprintf(
'mysql:host=%s;dbname=%s;charset=%s',
$config['host'],
$config['dbname'],
$config['charset'] ?? 'utf8mb4'
);
$pdo = new PDO(
$dsn,
$config['user'],
$config['pass'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
$currentUserId = (int) $_SESSION['user_id'];
$loggedIn = true;
$publicBasePath = '../';
$pageTitle = 'Telegram-Testversand - AstroTools';
$headerIntroPre = 'Administration';
$headerIntroTitle = 'Telegram-Testversand';
$headerIntroSub = 'Testnachrichten nur an verknuepfte Master-Konten senden.';
$errors = [];
$successMessage = '';
$resultRows = [];
$messageText = "Testnachricht von SkyView\n\nDer Telegram-Bot ist jetzt erfolgreich verbunden.";
$sendMode = 'self';
$selectedRecipientIds = [];
function h(?string $value): string
{
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}
function textLength(string $value): int
{
if (function_exists('mb_strlen')) {
return mb_strlen($value);
}
return strlen($value);
}
function sendTelegramMessage(string $botToken, string $chatId, string $messageText): array
{
$response = telegramHttpPostJson(
'https://api.telegram.org/bot' . $botToken . '/sendMessage',
[
'chat_id' => $chatId,
'text' => appendTelegramServiceFooter($messageText),
]
);
if (!$response['ok']) {
return [
'ok' => false,
'description' => (string) ($response['error'] ?? 'Telegram konnte nicht erreicht werden.'),
];
}
$decoded = json_decode((string) $response['body'], true);
if (!is_array($decoded)) {
return [
'ok' => false,
'description' => 'Telegram hat keine gültige JSON-Antwort geliefert.',
];
}
return [
'ok' => (bool) ($decoded['ok'] ?? false),
'description' => (string) ($decoded['description'] ?? ''),
];
}
if (empty($_SESSION['telegram_broadcast_csrf'])) {
$_SESSION['telegram_broadcast_csrf'] = bin2hex(random_bytes(16));
}
$stmtCurrentUser = $pdo->prepare("
SELECT `id`, `username`, `display_name`, `role`, `is_active`, `telegram_chat_id`
FROM `app_users`
WHERE `id` = :id
LIMIT 1
");
$stmtCurrentUser->execute([':id' => $currentUserId]);
$currentUser = $stmtCurrentUser->fetch();
if (
!$currentUser ||
!isMasterRole((string) $currentUser['role']) ||
(int) $currentUser['is_active'] !== 1
) {
$_SESSION = [];
session_destroy();
header('Location: ../login.php');
exit;
}
$stmtRecipients = $pdo->query("
SELECT
`id`,
`username`,
`display_name`,
`role`,
`telegram_username`,
`telegram_chat_id`,
`telegram_connected_at`
FROM `app_users`
WHERE `is_active` = 1
AND `role` = 'master'
AND `telegram_chat_id` IS NOT NULL
AND `telegram_chat_id` <> ''
ORDER BY COALESCE(`display_name`, `username`) ASC, `id` ASC
");
$recipients = $stmtRecipients->fetchAll();
$recipientIndex = [];
foreach ($recipients as $recipient) {
$recipientIndex[(int) $recipient['id']] = $recipient;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = (string) ($_POST['action'] ?? '');
$csrfToken = (string) ($_POST['csrf_token'] ?? '');
$messageText = trim((string) ($_POST['message_text'] ?? ''));
$sendMode = (string) ($_POST['send_mode'] ?? 'self');
$selectedRecipientIds = array_values(array_unique(array_map(
static fn ($value): int => (int) $value,
is_array($_POST['recipient_ids'] ?? null) ? $_POST['recipient_ids'] : []
)));
if (!hash_equals($_SESSION['telegram_broadcast_csrf'], $csrfToken)) {
$errors[] = 'Die Sitzung ist abgelaufen. Bitte die Seite neu laden.';
}
if ($action !== 'send_broadcast') {
$errors[] = 'Die angeforderte Aktion ist ungültig.';
}
if ($messageText === '') {
$errors[] = 'Bitte eine Nachricht eingeben.';
} elseif (textLength($messageText) > 4000) {
$errors[] = 'Die Nachricht ist zu lang. Bitte auf maximal 4000 Zeichen kuerzen.';
}
$botToken = trim((string) ($telegramConfig['bot_token'] ?? ''));
if ($botToken === '') {
$errors[] = 'In config/telegram.php ist noch kein Bot-Token hinterlegt.';
}
if (empty($recipients)) {
$errors[] = 'Es gibt derzeit keine verknuepften Master-Konten mit Telegram.';
}
$targetRecipients = [];
if (empty($errors)) {
if ($sendMode === 'self') {
if (empty($currentUser['telegram_chat_id'])) {
$errors[] = 'Dein Administrationskonto ist noch nicht mit Telegram verknuepft.';
} else {
foreach ($recipients as $recipient) {
if ((int) $recipient['id'] === $currentUserId) {
$targetRecipients[] = $recipient;
break;
}
}
if (empty($targetRecipients)) {
$targetRecipients[] = [
'id' => $currentUserId,
'username' => (string) $currentUser['username'],
'display_name' => (string) ($currentUser['display_name'] ?? ''),
'telegram_username' => '',
'telegram_chat_id' => (string) $currentUser['telegram_chat_id'],
'telegram_connected_at' => null,
];
}
}
} elseif ($sendMode === 'selected') {
if (empty($selectedRecipientIds)) {
$errors[] = 'Bitte mindestens einen Empfänger auswählen.';
} else {
foreach ($selectedRecipientIds as $recipientId) {
if (isset($recipientIndex[$recipientId])) {
$targetRecipients[] = $recipientIndex[$recipientId];
}
}
if (empty($targetRecipients)) {
$errors[] = 'Die ausgewählten Empfänger konnten nicht geladen werden.';
}
}
} elseif ($sendMode === 'all') {
$targetRecipients = $recipients;
} else {
$errors[] = 'Der Versandmodus ist ungültig.';
}
}
if (empty($errors)) {
$successCount = 0;
foreach ($targetRecipients as $recipient) {
$chatId = trim((string) ($recipient['telegram_chat_id'] ?? ''));
$sendResult = sendTelegramMessage($botToken, $chatId, $messageText);
$wasSuccessful = (bool) ($sendResult['ok'] ?? false);
if ($wasSuccessful) {
$successCount++;
}
$resultRows[] = [
'username' => (string) ($recipient['username'] ?? ''),
'display_name' => (string) ($recipient['display_name'] ?? ''),
'telegram_username' => (string) ($recipient['telegram_username'] ?? ''),
'chat_id' => $chatId,
'ok' => $wasSuccessful,
'description' => (string) ($sendResult['description'] ?? ''),
];
}
$successMessage = sprintf(
'Versand abgeschlossen: %d von %d Master-Konten erfolgreich erreicht.',
$successCount,
count($targetRecipients)
);
}
}
?>
<?php require __DIR__ . '/../header.php'; ?>
<?php if ($successMessage !== ''): ?>
<p class="msg-success"><?= h($successMessage) ?></p>
<?php endif; ?>
<?php if (!empty($errors)): ?>
<ul class="msg-error">
<?php foreach ($errors as $error): ?>
<li><?= h($error) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<div class="grid-2">
<div class="card">
<h2>Testnachricht senden</h2>
<p class="hint">
Diese Seite sendet Testnachrichten ausschliesslich an aktive Master-Konten mit hinterlegter Telegram-Chat-ID.
</p>
<table class="data-table mb-lg">
<tr><td>Verknüpfte Master-Konten</td><td><?= count($recipients) ?></td></tr>
<tr><td>Bot</td><td><?= h(($telegramConfig['bot_username'] ?? '') !== '' ? '@' . (string) $telegramConfig['bot_username'] : 'nicht konfiguriert') ?></td></tr>
</table>
<form method="post" action="" class="form-stack">
<input type="hidden" name="action" value="send_broadcast">
<input type="hidden" name="csrf_token" value="<?= h($_SESSION['telegram_broadcast_csrf']) ?>">
<div class="form-group">
<label>Empfänger</label>
<label>
<input type="radio" name="send_mode" value="self" <?= $sendMode === 'self' ? 'checked' : '' ?>>
Nur an mich senden
</label>
<label>
<input type="radio" name="send_mode" value="selected" <?= $sendMode === 'selected' ? 'checked' : '' ?>>
An ausgewählte Nutzer senden
</label>
<label>
<input type="radio" name="send_mode" value="all" <?= $sendMode === 'all' ? 'checked' : '' ?>>
An alle verknuepften Master senden
</label>
</div>
<div class="form-group">
<label for="recipient_ids">Auswahl für "ausgewählte Nutzer"</label>
<select id="recipient_ids" name="recipient_ids[]" multiple size="8">
<?php foreach ($recipients as $recipient): ?>
<?php $recipientId = (int) $recipient['id']; ?>
<?php $recipientLabel = ($recipient['display_name'] !== '' ? $recipient['display_name'] : $recipient['username']) . ' (' . $recipient['username'] . ')'; ?>
<option value="<?= $recipientId ?>" <?= in_array($recipientId, $selectedRecipientIds, true) ? 'selected' : '' ?>>
<?= h($recipientLabel) ?>
</option>
<?php endforeach; ?>
</select>
<p class="hint">Mit gedrueckter Strg-Taste lassen sich mehrere Benutzer markieren.</p>
</div>
<div class="form-group">
<label for="message_text">Nachricht</label>
<textarea
id="message_text"
name="message_text"
rows="8"
maxlength="4000"
required
><?= h($messageText) ?></textarea>
</div>
<button type="submit" class="btn btn-primary">Testnachricht an Master senden</button>
</form>
</div>
<div class="card">
<h2>Empfänger</h2>
<?php if (empty($recipients)): ?>
<p class="hint">Noch keine verknuepften Master-Konten vorhanden.</p>
<?php else: ?>
<table class="data-table">
<thead>
<tr>
<th>Benutzer</th>
<th>Telegram</th>
<th>Chat-ID</th>
</tr>
</thead>
<tbody>
<?php foreach ($recipients as $recipient): ?>
<tr>
<td>
<strong><?= h($recipient['display_name'] !== '' ? $recipient['display_name'] : $recipient['username']) ?></strong><br>
<span class="hint"><?= h($recipient['username']) ?></span>
</td>
<td><?= h(($recipient['telegram_username'] ?? '') !== '' ? '@' . ltrim((string) $recipient['telegram_username'], '@') : '—') ?></td>
<td><?= h((string) $recipient['telegram_chat_id']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
<?php if (!empty($resultRows)): ?>
<div class="card">
<h2>Versandprotokoll</h2>
<table class="data-table">
<thead>
<tr>
<th>Benutzer</th>
<th>Chat-ID</th>
<th>Status</th>
<th>Rueckmeldung</th>
</tr>
</thead>
<tbody>
<?php foreach ($resultRows as $row): ?>
<tr>
<td><?= h($row['display_name'] !== '' ? $row['display_name'] : $row['username']) ?></td>
<td><?= h($row['chat_id']) ?></td>
<td><?= $row['ok'] ? 'OK' : 'Fehler' ?></td>
<td><?= h($row['description'] !== '' ? $row['description'] : 'Nachricht gesendet.') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php require __DIR__ . '/../footer.php'; ?>