Files
skyview.astronomiemuseum.de/public/settings.php
T

430 lines
15 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;
}
$config = require __DIR__ . '/../config/database.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,
]
);
$userId = (int) $_SESSION['user_id'];
$errors = [];
$successMessage = '';
$telegramConfig = require __DIR__ . '/../config/telegram.php';
function h(?string $value): string
{
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}
function generateTelegramLinkToken(int $length = 32): string
{
return bin2hex(random_bytes(max(16, (int) ceil($length / 2))));
}
$stmtUser = $pdo->prepare("
SELECT
`id`,
`username`,
`email`,
`display_name`,
`telegram_username`,
`telegram_chat_id`,
`telegram_tcrb_v_enabled`,
`telegram_link_token`,
`telegram_link_token_expires_at`,
`telegram_connected_at`,
`role`,
`is_active`
FROM `app_users`
WHERE `id` = :id
LIMIT 1
");
$stmtUser->execute([':id' => $userId]);
$user = $stmtUser->fetch();
if (!$user) {
$_SESSION = [];
session_destroy();
header('Location: login.php');
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'update_profile') {
$displayName = trim($_POST['display_name'] ?? '');
$email = trim($_POST['email'] ?? '');
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.';
}
if ($displayName !== '' && mb_strlen($displayName) > 100) {
$errors[] = 'Der Anzeigename darf maximal 100 Zeichen lang sein.';
}
if (empty($errors)) {
$stmtCheck = $pdo->prepare("
SELECT `id`
FROM `app_users`
WHERE `email` = :email
AND `id` <> :id
LIMIT 1
");
$stmtCheck->execute([
':email' => $email,
':id' => $userId,
]);
if ($stmtCheck->fetch()) {
$errors[] = 'Die E-Mail-Adresse ist bereits vergeben.';
}
}
if (empty($errors)) {
$stmtUpdate = $pdo->prepare("
UPDATE `app_users`
SET
`display_name` = :display_name,
`email` = :email,
`updated_at` = NOW()
WHERE `id` = :id
");
$stmtUpdate->execute([
':display_name' => $displayName !== '' ? $displayName : null,
':email' => $email,
':id' => $userId,
]);
$_SESSION['display_name'] = $displayName !== '' ? $displayName : null;
$successMessage = 'Die Kontodaten wurden gespeichert.';
}
}
if ($action === 'generate_telegram_link') {
$token = generateTelegramLinkToken(32);
$expiresAt = (new DateTimeImmutable('now'))->modify('+30 minutes')->format('Y-m-d H:i:s');
$stmtLink = $pdo->prepare("
UPDATE `app_users`
SET
`telegram_link_token` = :token,
`telegram_link_token_expires_at` = :expires_at,
`updated_at` = NOW()
WHERE `id` = :id
");
$stmtLink->execute([
':token' => $token,
':expires_at' => $expiresAt,
':id' => $userId,
]);
$successMessage = 'Ein neuer Telegram-Verbindungscode wurde erzeugt.';
}
if ($action === 'disconnect_telegram') {
$stmtDisconnect = $pdo->prepare("
UPDATE `app_users`
SET
`telegram_username` = NULL,
`telegram_chat_id` = NULL,
`telegram_tcrb_v_enabled` = 0,
`telegram_link_token` = NULL,
`telegram_link_token_expires_at` = NULL,
`telegram_connected_at` = NULL,
`updated_at` = NOW()
WHERE `id` = :id
");
$stmtDisconnect->execute([
':id' => $userId,
]);
$successMessage = 'Die Telegram-Verknüpfung wurde entfernt.';
}
if ($action === 'update_tcrb_telegram_notifications') {
$enabled = isset($_POST['telegram_tcrb_v_enabled']) ? 1 : 0;
if ($enabled === 1 && empty($user['telegram_chat_id'])) {
$errors[] = 'Bitte zuerst Telegram verbinden, bevor du T-CrB-Nachrichten aktivierst.';
}
if (empty($errors)) {
$stmtNotification = $pdo->prepare("
UPDATE `app_users`
SET
`telegram_tcrb_v_enabled` = :enabled,
`updated_at` = NOW()
WHERE `id` = :id
");
$stmtNotification->execute([
':enabled' => $enabled,
':id' => $userId,
]);
$successMessage = $enabled === 1
? 'T-CrB-Telegram-Nachrichten wurden aktiviert.'
: 'T-CrB-Telegram-Nachrichten wurden deaktiviert.';
}
}
if ($action === 'change_password') {
$currentPassword = $_POST['current_password'] ?? '';
$newPassword = $_POST['new_password'] ?? '';
$newPasswordRepeat = $_POST['new_password_repeat'] ?? '';
$stmtPassword = $pdo->prepare("
SELECT `password_hash`
FROM `app_users`
WHERE `id` = :id
LIMIT 1
");
$stmtPassword->execute([':id' => $userId]);
$passwordRow = $stmtPassword->fetch();
if (!$passwordRow || !password_verify($currentPassword, $passwordRow['password_hash'])) {
$errors[] = 'Das aktuelle Passwort ist nicht korrekt.';
}
if ($newPassword === '') {
$errors[] = 'Bitte ein neues Passwort eingeben.';
} elseif (strlen($newPassword) < 8) {
$errors[] = 'Das neue Passwort muss mindestens 8 Zeichen lang sein.';
}
if ($newPassword !== $newPasswordRepeat) {
$errors[] = 'Die neuen Passwörter stimmen nicht überein.';
}
if (empty($errors)) {
$newHash = password_hash($newPassword, PASSWORD_DEFAULT);
$stmtUpdatePassword = $pdo->prepare("
UPDATE `app_users`
SET
`password_hash` = :password_hash,
`updated_at` = NOW()
WHERE `id` = :id
");
$stmtUpdatePassword->execute([
':password_hash' => $newHash,
':id' => $userId,
]);
$successMessage = 'Das Passwort wurde geaendert.';
}
}
$stmtUser->execute([':id' => $userId]);
$user = $stmtUser->fetch();
}
$loggedIn = true;
$publicBasePath = './';
$telegramBotUsername = trim((string) ($telegramConfig['bot_username'] ?? ''));
$telegramHasConnection = !empty($user['telegram_chat_id']);
$telegramTcrbVEnabled = !empty($user['telegram_tcrb_v_enabled']);
$telegramLinkToken = trim((string) ($user['telegram_link_token'] ?? ''));
$telegramLinkExpiresAt = !empty($user['telegram_link_token_expires_at'])
? new DateTimeImmutable((string) $user['telegram_link_token_expires_at'])
: null;
$telegramLinkIsActive = $telegramLinkToken !== ''
&& $telegramLinkExpiresAt instanceof DateTimeImmutable
&& $telegramLinkExpiresAt > new DateTimeImmutable('now');
$telegramDeepLink = $telegramLinkIsActive && $telegramBotUsername !== ''
? 'https://t.me/' . $telegramBotUsername . '?start=connect_' . $telegramLinkToken
: null;
?>
<?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>Kontodaten</h2>
<table class="data-table mb-lg">
<tr><td>Benutzername</td><td><?= h($user['username']) ?></td></tr>
<tr><td>Rolle</td><td><?= h($user['role']) ?></td></tr>
</table>
<form method="post" action="" class="form-stack">
<input type="hidden" name="action" value="update_profile">
<div class="form-group">
<label for="display_name">Anzeigename <span class="form-optional">(optional)</span></label>
<input
type="text"
id="display_name"
name="display_name"
maxlength="100"
value="<?= h($user['display_name'] ?? '') ?>"
>
</div>
<div class="form-group">
<label for="email">E-Mail-Adresse</label>
<input
type="email"
id="email"
name="email"
required
maxlength="190"
value="<?= h($user['email']) ?>"
>
</div>
<button type="submit" class="btn btn-primary btn-full">Speichern</button>
</form>
</div>
<div class="card">
<h2>Telegram verbinden</h2>
<div class="form-stack">
<p class="hint">
Spätere Bot-Nachrichten funktionieren nur mit einer verknüpften Chat-ID. Der Telegram-Username allein reicht Telegram für aktive Nachrichten an einen Nutzer nicht aus.
</p>
<table class="data-table mb-lg">
<tr><td>Status</td><td><?= $telegramHasConnection ? 'Verbunden' : 'Nicht verbunden' ?></td></tr>
<tr><td>Telegram-Username</td><td><?= h(($user['telegram_username'] ?? '') !== '' ? '@' . ltrim((string) $user['telegram_username'], '@') : '—') ?></td></tr>
<tr><td>Chat-ID</td><td><?= h($user['telegram_chat_id'] ?? '—') ?></td></tr>
<tr><td>Verbunden seit</td><td><?= h($user['telegram_connected_at'] ?? '—') ?></td></tr>
</table>
<p class="hint"><strong>T CrB letzter V-Wert:</strong> <?= $telegramTcrbVEnabled ? 'Aktiv' : 'Aus' ?></p>
<?php if ($telegramLinkIsActive): ?>
<p class="hint">
Aktiver Verbindungscode bis <?= h($telegramLinkExpiresAt?->format('d.m.Y H:i')) ?>:
<strong><?= h($telegramLinkToken) ?></strong>
</p>
<?php endif; ?>
<div class="input-row">
<form method="post" action="">
<input type="hidden" name="action" value="generate_telegram_link">
<button type="submit" class="btn btn-primary"><?= $telegramLinkIsActive ? 'Neuen Verbindungscode erzeugen' : 'Telegram verbinden' ?></button>
</form>
<?php if ($telegramHasConnection): ?>
<form method="post" action="" onsubmit="return confirm('Telegram-Verknüpfung wirklich entfernen?');">
<input type="hidden" name="action" value="disconnect_telegram">
<button type="submit" class="btn btn-danger">Verknüpfung lösen</button>
</form>
<?php endif; ?>
</div>
<?php if ($telegramLinkIsActive): ?>
<?php if ($telegramDeepLink !== null): ?>
<div class="telegram-qr-block">
<div class="telegram-qr-image" id="telegramConnectQr" data-telegram-link="<?= h($telegramDeepLink) ?>"></div>
<p class="hint">QR-Code mit dem Handy in Telegram scannen und dann im Bot nur noch auf <strong>Start</strong> tippen.</p>
</div>
<?php endif; ?>
<p class="hint">
Verbindung starten: <a href="<?= h($publicBasePath . 'telegram/connect.php') ?>">Telegram-Verknüpfung öffnen</a>
<?php if ($telegramDeepLink !== null): ?>
oder direkt im Bot:
<a href="<?= h($telegramDeepLink) ?>" target="_blank" rel="noopener">@<?= h($telegramBotUsername) ?></a>
<?php endif; ?>
</p>
<?php endif; ?>
<form method="post" action="" class="form-stack">
<input type="hidden" name="action" value="update_tcrb_telegram_notifications">
<label class="checkbox-row">
<input
type="checkbox"
name="telegram_tcrb_v_enabled"
value="1"
<?= $telegramTcrbVEnabled ? 'checked' : '' ?>
<?= !$telegramHasConnection ? 'disabled' : '' ?>
>
<span>Letzten T CrB-Wert im Filter V per Telegram erhalten</span>
</label>
<?php if (!$telegramHasConnection): ?>
<p class="hint">Die Auswahl wird erst aktiv, nachdem dein Telegram-Konto verbunden ist.</p>
<?php endif; ?>
<button type="submit" class="btn btn-primary" <?= !$telegramHasConnection ? 'disabled' : '' ?>>Benachrichtigung speichern</button>
</form>
</div>
</div>
</div>
<div class="grid-2">
<div class="card">
<h2>Passwort aendern</h2>
<form method="post" action="" class="form-stack">
<input type="hidden" name="action" value="change_password">
<div class="form-group">
<label for="current_password">Aktuelles Passwort</label>
<input type="password" id="current_password" name="current_password" required>
</div>
<div class="form-group">
<label for="new_password">Neues Passwort</label>
<input type="password" id="new_password" name="new_password" required>
</div>
<div class="form-group">
<label for="new_password_repeat">Neues Passwort wiederholen</label>
<input type="password" id="new_password_repeat" name="new_password_repeat" required>
</div>
<button type="submit" class="btn btn-primary btn-full">Passwort aendern</button>
</form>
</div>
</div>
<?php if ($telegramDeepLink !== null): ?>
<script src="<?= h($publicBasePath . 'js/qrcode.min.js') ?>"></script>
<script>
(function () {
const qrEl = document.getElementById('telegramConnectQr');
if (!qrEl || typeof QRCode === 'undefined') {
return;
}
const qrLink = qrEl.getAttribute('data-telegram-link');
if (!qrLink) {
return;
}
new QRCode(qrEl, {
text: qrLink,
width: 220,
height: 220,
correctLevel: QRCode.CorrectLevel.M
});
})();
</script>
<?php endif; ?>
<?php require __DIR__ . '/footer.php'; ?>