schreiben jetzt per Ajax
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
session_start();
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Nur POST ist erlaubt.',
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
$sessionToken = isset($_SESSION['observation_tip_insert_token']) && is_string($_SESSION['observation_tip_insert_token'])
|
||||
? $_SESSION['observation_tip_insert_token']
|
||||
: '';
|
||||
$submittedToken = isset($_POST['observation_tip_insert_token']) ? (string) $_POST['observation_tip_insert_token'] : '';
|
||||
|
||||
if ($sessionToken === '' || $submittedToken === '' || !hash_equals($sessionToken, $submittedToken)) {
|
||||
http_response_code(403);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Sicherheitspruefung fehlgeschlagen. Bitte die Seite neu laden und erneut versuchen.',
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
$payloadJson = isset($_POST['observation_tip_payload']) ? (string) $_POST['observation_tip_payload'] : '';
|
||||
$rows = json_decode($payloadJson, true);
|
||||
if (!is_array($rows)) {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Ungueltige Ereignisdaten empfangen.',
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
$normalized = [];
|
||||
foreach ($rows as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$moment = trim((string) ($row['moment'] ?? ''));
|
||||
$tip = trim((string) ($row['tip'] ?? ''));
|
||||
if ($moment === '' || $tip === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$normalized[] = [
|
||||
'moment' => $moment,
|
||||
'tip' => $tip,
|
||||
];
|
||||
}
|
||||
|
||||
if ($normalized === []) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Keine gueltigen Ereignisse zum Eintragen vorhanden.',
|
||||
'inserted' => 0,
|
||||
'skipped' => 0,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$dbConfig = require __DIR__ . '/../../config/observationtips_database.php';
|
||||
$dsn = sprintf(
|
||||
'mysql:host=%s;dbname=%s;charset=%s',
|
||||
$dbConfig['host'],
|
||||
$dbConfig['dbname'],
|
||||
$dbConfig['charset'] ?? 'utf8mb4'
|
||||
);
|
||||
$pdo = new PDO(
|
||||
$dsn,
|
||||
$dbConfig['user'],
|
||||
$dbConfig['pass'],
|
||||
[
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]
|
||||
);
|
||||
|
||||
$checkStmt = $pdo->prepare(
|
||||
'SELECT 1 FROM `astro_sonobs_observationtips` WHERE `moment` = :moment AND `tip` = :tip LIMIT 1'
|
||||
);
|
||||
$insertStmt = $pdo->prepare(
|
||||
'INSERT INTO `astro_sonobs_observationtips` (`moment`, `tip`) VALUES (:moment, :tip)'
|
||||
);
|
||||
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
foreach ($normalized as $row) {
|
||||
$checkStmt->execute([
|
||||
':moment' => $row['moment'],
|
||||
':tip' => $row['tip'],
|
||||
]);
|
||||
|
||||
if ($checkStmt->fetchColumn()) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$insertStmt->execute([
|
||||
':moment' => $row['moment'],
|
||||
':tip' => $row['tip'],
|
||||
]);
|
||||
$inserted++;
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => sprintf('%d Ereignisse eingetragen, %d bereits vorhanden.', $inserted, $skipped),
|
||||
'inserted' => $inserted,
|
||||
'skipped' => $skipped,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
} catch (Throwable $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Eintragen in `astro_sonobs_observationtips` fehlgeschlagen: ' . $e->getMessage(),
|
||||
'inserted' => 0,
|
||||
'skipped' => 0,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
+90
-114
@@ -257,11 +257,12 @@ $favoriteCometEvents = [];
|
||||
$seasonChanges = [];
|
||||
$timeChanges = [];
|
||||
$monthEventList = [];
|
||||
$observationTipInsertResult = null;
|
||||
$starDataError = null;
|
||||
$monthNarrativeText = '';
|
||||
$observationTipInsertSql = '';
|
||||
$observationTipCalendarIcs = '';
|
||||
$observationTipInsertPayloadJson = '[]';
|
||||
$observationTipInsertEndpoint = $publicBasePath . 'ajax/insert_observationtips.php';
|
||||
$chartConfig = null;
|
||||
$chartConfigJson = 'null';
|
||||
$starDataJson = '[]';
|
||||
@@ -635,62 +636,6 @@ if (!function_exists('normalizeObservationTipEvents')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('insertObservationTipEvents')) {
|
||||
function insertObservationTipEvents(PDO $pdo, array $events, DateTimeZone $timezone): array
|
||||
{
|
||||
$normalized = normalizeObservationTipEvents($events, $timezone);
|
||||
if ($normalized === []) {
|
||||
return [
|
||||
'inserted' => 0,
|
||||
'skipped' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$checkStmt = $pdo->prepare(
|
||||
'SELECT 1 FROM `astro_sonobs_observationtips` WHERE `moment` = :moment AND `tip` = :tip LIMIT 1'
|
||||
);
|
||||
$insertStmt = $pdo->prepare(
|
||||
'INSERT INTO `astro_sonobs_observationtips` (`moment`, `tip`) VALUES (:moment, :tip)'
|
||||
);
|
||||
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
foreach ($normalized as $row) {
|
||||
$checkStmt->execute([
|
||||
':moment' => $row['moment'],
|
||||
':tip' => $row['tip'],
|
||||
]);
|
||||
|
||||
if ($checkStmt->fetchColumn()) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$insertStmt->execute([
|
||||
':moment' => $row['moment'],
|
||||
':tip' => $row['tip'],
|
||||
]);
|
||||
$inserted++;
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return [
|
||||
'inserted' => $inserted,
|
||||
'skipped' => $skipped,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('escapeIcalText')) {
|
||||
function escapeIcalText(string $value): string
|
||||
{
|
||||
@@ -2490,56 +2435,10 @@ $monthNarrativeText = monthForecastBuildNarrativeText($monthEventList, $selected
|
||||
|
||||
$observationTipInsertSql = buildObservationTipInsertSql($monthEventList, new DateTimeZone($chartTimezone));
|
||||
$observationTipCalendarIcs = buildObservationTipCalendarIcs($monthEventList, new DateTimeZone($chartTimezone));
|
||||
|
||||
if (
|
||||
$_SERVER['REQUEST_METHOD'] === 'POST'
|
||||
&& isset($_POST['insert_observation_tips'])
|
||||
&& $_POST['insert_observation_tips'] === '1'
|
||||
) {
|
||||
$submittedToken = isset($_POST['observation_tip_insert_token']) ? (string) $_POST['observation_tip_insert_token'] : '';
|
||||
if (!hash_equals($observationTipInsertToken, $submittedToken)) {
|
||||
$observationTipInsertResult = [
|
||||
'success' => false,
|
||||
'message' => 'Sicherheitspruefung fehlgeschlagen. Bitte die Seite neu laden und erneut versuchen.',
|
||||
];
|
||||
} else {
|
||||
try {
|
||||
$observationTipDbConfig = require __DIR__ . '/../config/observationtips_database.php';
|
||||
$observationTipDsn = sprintf(
|
||||
'mysql:host=%s;dbname=%s;charset=%s',
|
||||
$observationTipDbConfig['host'],
|
||||
$observationTipDbConfig['dbname'],
|
||||
$observationTipDbConfig['charset'] ?? 'utf8mb4'
|
||||
);
|
||||
$observationTipPdo = new PDO(
|
||||
$observationTipDsn,
|
||||
$observationTipDbConfig['user'],
|
||||
$observationTipDbConfig['pass'],
|
||||
[
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]
|
||||
);
|
||||
|
||||
$observationTipInsertResult = insertObservationTipEvents(
|
||||
$observationTipPdo,
|
||||
$monthEventList,
|
||||
new DateTimeZone($chartTimezone)
|
||||
);
|
||||
$observationTipInsertResult['success'] = true;
|
||||
$observationTipInsertResult['message'] = sprintf(
|
||||
'%d Ereignisse eingetragen, %d bereits vorhanden.',
|
||||
(int) $observationTipInsertResult['inserted'],
|
||||
(int) $observationTipInsertResult['skipped']
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
$observationTipInsertResult = [
|
||||
'success' => false,
|
||||
'message' => 'Eintragen in `astro_sonobs_observationtips` fehlgeschlagen: ' . $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$observationTipInsertPayloadJson = json_encode(
|
||||
normalizeObservationTipEvents($monthEventList, new DateTimeZone($chartTimezone)),
|
||||
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||
) ?: '[]';
|
||||
|
||||
$chartConfig = [
|
||||
'monthName' => $months[$selectedMonth],
|
||||
@@ -2768,10 +2667,11 @@ $observationTipCalendarFilenameJson = json_encode(sprintf('astrotools-monatserei
|
||||
</div>
|
||||
<div class="monatskarte-export">
|
||||
<?php if ($monthEventList): ?>
|
||||
<form method="post" class="monatskarte-inline-form">
|
||||
<form method="post" action="<?= htmlspecialchars($observationTipInsertEndpoint, ENT_QUOTES, 'UTF-8') ?>" class="monatskarte-inline-form" id="observationTipInsertForm">
|
||||
<input type="hidden" name="insert_observation_tips" value="1">
|
||||
<input type="hidden" name="observation_tip_insert_token" value="<?= htmlspecialchars($observationTipInsertToken, ENT_QUOTES, 'UTF-8') ?>">
|
||||
<button type="submit" class="monatskarte-export-button">
|
||||
<input type="hidden" name="observation_tip_payload" value="<?= htmlspecialchars($observationTipInsertPayloadJson, ENT_QUOTES, 'UTF-8') ?>">
|
||||
<button type="submit" class="monatskarte-export-button" id="observationTipInsertButton">
|
||||
Direkt in Datenbank eintragen
|
||||
</button>
|
||||
</form>
|
||||
@@ -2790,11 +2690,7 @@ $observationTipCalendarFilenameJson = json_encode(sprintf('astrotools-monatserei
|
||||
</div>
|
||||
|
||||
<div class="monatskarte-footer">
|
||||
<?php if (is_array($observationTipInsertResult)): ?>
|
||||
<p class="monatskarte-insert-status <?= !empty($observationTipInsertResult['success']) ? 'is-success' : 'is-error' ?>">
|
||||
<?= htmlspecialchars((string) ($observationTipInsertResult['message'] ?? ''), ENT_QUOTES, 'UTF-8') ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<p class="monatskarte-insert-status" id="observationTipInsertStatus" role="status" aria-live="polite" hidden></p>
|
||||
<?php if ($observationTipInsertSql !== ''): ?>
|
||||
<div class="monatskarte-sql-export" id="observationTipSqlPanel" hidden>
|
||||
<label class="monatskarte-sql-label" for="observationTipSqlOutput">SQL für `astro_sonobs_observationtips`</label>
|
||||
@@ -2869,6 +2765,11 @@ $observationTipCalendarFilenameJson = json_encode(sprintf('astrotools-monatserei
|
||||
border: 1px solid #efc0c0;
|
||||
}
|
||||
|
||||
.monatskarte-export-button.is-success {
|
||||
background: rgba(36, 104, 62, 0.92);
|
||||
border-color: rgba(141, 214, 167, 0.82);
|
||||
}
|
||||
|
||||
.monatsvorhersage-shell {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
@@ -3475,12 +3376,87 @@ function monthChartCometRaDec(comet, date) {
|
||||
}
|
||||
|
||||
(function () {
|
||||
const insertForm = document.getElementById('observationTipInsertForm');
|
||||
const insertButton = document.getElementById('observationTipInsertButton');
|
||||
let insertStatus = document.getElementById('observationTipInsertStatus');
|
||||
const toggleButton = document.getElementById('toggleObservationTipSql');
|
||||
const copyButton = document.getElementById('copyObservationTipSql');
|
||||
const icalButton = document.getElementById('downloadObservationTipIcal');
|
||||
const panel = document.getElementById('observationTipSqlPanel');
|
||||
const output = document.getElementById('observationTipSqlOutput');
|
||||
|
||||
if (insertForm && insertButton) {
|
||||
insertForm.addEventListener('submit', async function (event) {
|
||||
event.preventDefault();
|
||||
const originalLabel = insertButton.textContent;
|
||||
insertButton.classList.remove('is-success');
|
||||
insertButton.disabled = true;
|
||||
insertButton.textContent = 'Trage ein...';
|
||||
|
||||
try {
|
||||
const response = await fetch(insertForm.action, {
|
||||
method: 'POST',
|
||||
body: new FormData(insertForm),
|
||||
headers: {
|
||||
'X-Requested-With': 'fetch'
|
||||
}
|
||||
});
|
||||
|
||||
const payload = await response.json();
|
||||
if (!insertStatus) {
|
||||
insertStatus = document.createElement('p');
|
||||
insertStatus.id = 'observationTipInsertStatus';
|
||||
insertStatus.setAttribute('role', 'status');
|
||||
insertStatus.setAttribute('aria-live', 'polite');
|
||||
insertStatus.className = 'monatskarte-insert-status';
|
||||
const footer = insertForm.closest('.monatskarte-card')?.querySelector('.monatskarte-footer');
|
||||
if (footer) {
|
||||
footer.insertBefore(insertStatus, footer.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
if (insertStatus) {
|
||||
insertStatus.hidden = false;
|
||||
insertStatus.className = 'monatskarte-insert-status ' + (payload && payload.success ? 'is-success' : 'is-error');
|
||||
insertStatus.textContent = payload && payload.message ? payload.message : 'Unbekannte Rueckmeldung vom Server.';
|
||||
}
|
||||
|
||||
if (payload && payload.success) {
|
||||
insertButton.classList.add('is-success');
|
||||
insertButton.textContent = 'Eingetragen';
|
||||
window.setTimeout(function () {
|
||||
insertButton.classList.remove('is-success');
|
||||
insertButton.textContent = originalLabel;
|
||||
}, 1800);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
if (!insertStatus) {
|
||||
insertStatus = document.createElement('p');
|
||||
insertStatus.id = 'observationTipInsertStatus';
|
||||
insertStatus.setAttribute('role', 'status');
|
||||
insertStatus.setAttribute('aria-live', 'polite');
|
||||
insertStatus.className = 'monatskarte-insert-status is-error';
|
||||
const footer = insertForm.closest('.monatskarte-card')?.querySelector('.monatskarte-footer');
|
||||
if (footer) {
|
||||
footer.insertBefore(insertStatus, footer.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
if (insertStatus) {
|
||||
insertStatus.hidden = false;
|
||||
insertStatus.className = 'monatskarte-insert-status is-error';
|
||||
insertStatus.textContent = 'Eintragen fehlgeschlagen. Bitte erneut versuchen.';
|
||||
}
|
||||
} finally {
|
||||
insertButton.disabled = false;
|
||||
if (!insertButton.classList.contains('is-success')) {
|
||||
insertButton.textContent = originalLabel;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (toggleButton && panel) {
|
||||
toggleButton.addEventListener('click', function () {
|
||||
const isHidden = panel.hasAttribute('hidden');
|
||||
|
||||
Reference in New Issue
Block a user