Compare commits
9 Commits
bff6d80e6f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fbce630b52 | |||
| 33f3795e5b | |||
| 561e3a06c6 | |||
| a8f29717b4 | |||
| ede0cce8ba | |||
| 98580d45d9 | |||
| 142ad57f98 | |||
| 63c760f8df | |||
| 7d0624addf |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,5 +10,5 @@ video
|
||||
download
|
||||
*.log
|
||||
webseiten
|
||||
|
||||
sternwarte/javascript
|
||||
sternwarte/beoanswer/.env.production
|
||||
|
||||
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@@ -37,6 +37,15 @@
|
||||
"pathMappings": {
|
||||
"/var/www/html": "${workspaceFolder}/sternwarte"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Debug checkfuehrung.js",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/sternwarte/checkfuehrung/checkfuehrung.js",
|
||||
"args": ["-d", "2"],
|
||||
"cwd": "${workspaceFolder}/sternwarte/checkfuehrung",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
96
sternwarte/Anleitungen/NAS_ohne_VPN.md
Normal file
96
sternwarte/Anleitungen/NAS_ohne_VPN.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# NAS ohne VPN
|
||||
|
||||
## Übersicht
|
||||
Auf das NAS-Laufwerk in der Sternwarte kann auf zwei Arten zugegriffen werden:
|
||||
|
||||
1. Über VPN (Wireguard), wie in der ersten Anleitung beschrieben (<https://www.sternwarte-welzheim.de/intern/download/Wireguard/Wireguard.pdf>
|
||||
**Vorteil**:
|
||||
Der Zugriff ist einfach, das NAS kann direkt in das lokale Filesystem eingebunden werden.
|
||||
**Nachteil**:
|
||||
Es muss der Wirguard-Client auf dem lokalen Gerät installiert werden.
|
||||
|
||||
2. Direkt über den WEB-Browser.
|
||||
**Vorteil**:
|
||||
Einfacher Zugriff direkt im Browser.
|
||||
**Nachteil**:
|
||||
Es wird ein zusätzliches Login für die QNAP-Cloud benötigt.
|
||||
|
||||
## Vorgehen
|
||||
* Aufruf im WEB-Browser mit der URL
|
||||
**https://qlink.to/stwnaswelzheim**
|
||||
Es erscheint folgendes Fenster:
|
||||
|
||||
|
||||

|
||||
|
||||
Auch wenn hier "Problemlösung" steht ist das nichts Anderes als die Aufforderung, sich an der QNAP-Cloud anzumelden.
|
||||
Also nun auf **anmelden** klicken, dann kommt:
|
||||
|
||||

|
||||
|
||||
und hier dann ausfüllen:
|
||||
bei E-Mail Adresse oder Telefonnummer:
|
||||
**sternwarte.welzheim@gmx.de**
|
||||
und bei Kennwort:
|
||||
**Ekg!Te4!8?W5**
|
||||
Dieses Kennwort ist absichtlich etwas kompliziert, um den Zugang zu userem NAS gut abzusichern. Bitte aufschreiben oder in dem Passwortsafe des Browsers abspeichern.
|
||||
|
||||
Das Anklicken von "Ich möchte angemeldet bleiben" bringt nicht viel, da die Anmeldung nur für 2 Tage gemerkt wird und man sich dann eh neu anmelden muss.
|
||||
|
||||
Dann Klick auf **anmelden**. Es kann nun sein, dass die Cloud eine 2-Faktor-Authentifizierung anfordert. Sie macht das nicht jedesmal, aber beim ersten mal ziemlich sicher und dann irgendwann wieder. Sie sendet dann einen Code an die die Anmlede-EMail (*sternwarte.welzheim@gmx.de*). Ich habe diese E-Mail-Adresse gewählt, weil dann jeder von Euch direkt über die GMX-Webseite sich anmelden und die Email abrufen kann (siehe Anhang).
|
||||
Dann kommt nochmal eine Info-Seite, die durch Klick auf **OK** geschlossen werden kann.
|
||||

|
||||
|
||||
|
||||
Nun verbindet sich die QNAP-Cloud mit der NAS namens **Goldgrube**, diese will nun (auch) eine Anmeldung:
|
||||
|
||||
|
||||

|
||||
|
||||
Hier ist der Benutzername:
|
||||
**Plejaden**
|
||||
klick auf "Weiter", das Passwort heißt:
|
||||
**Subaru7ge\***
|
||||
(Eselsbrücke: Das japanische Wort für Plejaden = Subaru und 7ge* soll "Siebengestirn" bedeuten).
|
||||
|
||||
Nun auf Anmeldung klicken und schon landet man auf dem NAS.
|
||||
|
||||
Um nun Dateien runter zu laden, auf das Icon "File Station 5" klicken. Damit kommt man zu den Verzeichnissen und Dateien auf dem NAS.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Nun auswählen, welche Datei aus welchem Verzeichnis man runterladen will, diese dann links an dem Kästchen ankreuzen, oben in der Menüleiste der Filestation auf den Schraubenschlüssel klicken und dann "Herunterladen" auswählen. Nun wird die Datei von dem NAS auf den lokalen Rechner kopiert und zwar in das Verzeichnis, das beim Browser eingestellt ist. In der Rgel ist das das Verzeichnis **Downloads**.
|
||||
|
||||

|
||||
|
||||
Das Ganze klingt jetzt sehr kompliziert, aber wenn man es ein paarmal gemacht hat und wenn die Zugangsdaten abgespeichert wurden, geht das ganz flott. Wie gesagt, der große Vorteil ist, dass man nix extra installieren muss.
|
||||
|
||||
Im Moment ist der Zugriff über diesen Zugang **nur lesend !** Auch das dient zur Absicherung unseres NAS. Wer von Euch schreibenden Zugang auf das NAS benötigt, sollte bitte den VPN (Wirguard)-Zugang verwenden. Falls das nicht möglich ist, bitte bei mir melden, ich mache dann einen extra Zuganng zum Schreiben.
|
||||
|
||||
Sollte ich was vergessen haben oder etwas unklar sein, einfach eine Mail an mich schreiben (<rxf@fuerst-stuttgart.de>)
|
||||
|
||||
## Anmeldung bei GMX
|
||||
Diese Anmeldung ist nur notwendig, wenn - wie oben erwähnt - die QNAP-Cloud eine 2-Faktor-Authentifizierung anfordert. Dann wie folgt vorgehen:
|
||||
Die Webseite von GMX im Browser aufrufen: **gmx.de**. Ganz unten am Bildschirm steht dann: **GMX Zum Postfach**. Hier dann drauf klicken. Nun anmleden mit:
|
||||
E-Mail -> **sternwarte.welzheim@gmx.de**, dann *weiter* und
|
||||
Passwort -> **c3zx4C6Yy6CU** , dann *Login*.
|
||||

|
||||
|
||||
Nun erscheint die Seite mit den EMails. Hier dann die Neueste von QNAP nehmen (steht normalerweise ganz oben), den gesendeten Code ausschneiden und dann in die Maske bei der QNAP-Anmeldung einfügen.
|
||||
|
||||
Bitte **unbedingt** bei GMX wieder abmelden.
|
||||
Rechts oben auf den kleine Kreis mit **SW** klicken, dann auf **Logout**.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### Versionen
|
||||
|
||||
Datum | Version | Bemerkung
|
||||
-----|:-----:|----
|
||||
2026-03-09 | 1.1 | Zugang zu Cloud geändert, GMX dazu
|
||||
2025-06-12 | 1.0 | erste veröffentlichte Version
|
||||
|
||||
BIN
sternwarte/Anleitungen/NAS_ohne_VPN.pdf
Normal file
BIN
sternwarte/Anleitungen/NAS_ohne_VPN.pdf
Normal file
Binary file not shown.
@@ -612,7 +612,7 @@ class RepoSoFue
|
||||
// Bei status=4 (stattgefunden) macht 'neu' keinen Sinn, ignoriere termin
|
||||
// termin kann 'all', 'neu' sein - nur 'neu' wird behandelt
|
||||
if ($termin === 'neu' && (int)$status !== 4) {
|
||||
$countSql .= " AND wtermin >= NOW()";
|
||||
$countSql .= " AND wtermin >= CURDATE() - INTERVAL 1 DAY ";
|
||||
}
|
||||
|
||||
// Lastdate-Filter auch beim Count hinzufügen
|
||||
@@ -652,7 +652,7 @@ class RepoSoFue
|
||||
// Bei status=4 (stattgefunden) macht 'neu' keinen Sinn, ignoriere termin
|
||||
// termin kann 'all', 'neu' sein - nur 'neu' wird behandelt
|
||||
if ($termin === 'neu' && (int)$status !== 4) {
|
||||
$sql .= " AND wtermin >= NOW()";
|
||||
$sql .= " AND wtermin >= CURDATE() - INTERVAL 1 DAY ";
|
||||
}
|
||||
|
||||
// Lastdate-Filter hinzufügen
|
||||
@@ -898,6 +898,7 @@ class RepoKalender
|
||||
{
|
||||
const TBL = 'kalender';
|
||||
|
||||
|
||||
public static function getEntries(string $start, string $end): array
|
||||
{
|
||||
$s = date('Ymd', strtotime($start));
|
||||
@@ -905,6 +906,14 @@ class RepoKalender
|
||||
return DB::all("SELECT * FROM " . self::TBL . " WHERE start >= ? AND start <= ?", [$s, $e]);
|
||||
}
|
||||
|
||||
public static function getOneEntry(string $start): array
|
||||
{
|
||||
$end = new DateTime($start);
|
||||
$end->modify('+1 day');
|
||||
$end = $end->format('Y-m-d');
|
||||
return RepoKalender::getEntries($start, $end);
|
||||
}
|
||||
|
||||
public static function insert(array $data): bool
|
||||
{
|
||||
$sql = "INSERT INTO " . self::TBL . " (start, end, title, description) VALUES (?, ?, ?, ?)";
|
||||
@@ -917,6 +926,68 @@ class RepoKalender
|
||||
DB::exec("DELETE FROM " . self::TBL . " WHERE id=?", [$id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function updateBeos(int $id, string $mitarbeiter): bool
|
||||
{
|
||||
// First, get the existing calendar entry
|
||||
$existingEntry = DB::one("SELECT * FROM " . self::TBL . " WHERE id=?", [$id]);
|
||||
|
||||
if (!$existingEntry) {
|
||||
error_log("RepoKalender::updateBeos - Calendar entry with ID {$id} not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the original Sonderführung name from the existing title
|
||||
// Expected format: "WK, SF [Sonderführung Name], [Old Mitarbeiter]"
|
||||
$oldTitle = $existingEntry['title'];
|
||||
$sofueName = '';
|
||||
if (preg_match('/^WK, SF (.*), .*$/', $oldTitle, $matches)) {
|
||||
$sofueName = trim($matches[1]);
|
||||
}
|
||||
|
||||
$newTitle = '';
|
||||
if (!empty($sofueName)) {
|
||||
$newTitle = "WK, SF {$sofueName}, {$mitarbeiter}";
|
||||
} else {
|
||||
// Fallback: If we can't extract the original Sonderführung name,
|
||||
// we'll try to keep the original structure if possible, or
|
||||
// simply create a title indicating the BEO update.
|
||||
// For now, let's just make it clear it's a BEO update.
|
||||
$newTitle = "Kalender BEO: {$mitarbeiter}"; // More general fallback
|
||||
error_log("RepoKalender::updateBeos - Could not parse original SF name from title '{$oldTitle}'. Using generic title fallback.");
|
||||
}
|
||||
|
||||
$sql = "UPDATE " . self::TBL . " SET title=? WHERE id=?";
|
||||
DB::exec($sql, [$newTitle, $id]);
|
||||
error_log("Kalender-Eintrag ID {$id} BEOs aktualisiert zu: {$mitarbeiter} (Titel: '{$newTitle}')");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function findEntryBySofueIdAndTermin(int $sofueId, string $wtermin): ?int
|
||||
{
|
||||
// Fetch Sonderführung details to get its name
|
||||
$sofue = RepoSoFue::getById($sofueId);
|
||||
if (!$sofue) {
|
||||
error_log("RepoKalender::findEntryBySofueIdAndTermin - Sofue ID {$sofueId} not found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
$sofueName = trim($sofue['name']);
|
||||
$searchTitlePart = "WK, SF " . $sofueName; // We'll look for this part in the title
|
||||
|
||||
// Convert wtermin to YYYY-MM-DD H:i format for comparison with kalender.start
|
||||
$terminDate = new DateTime($wtermin);
|
||||
$startDateStr = $terminDate->format('Y-m-d H:i');
|
||||
|
||||
// Find calendar entry that matches the start date and contains the sofue name in its title
|
||||
// Use LIKE for title matching because the full title includes the BEO's name which might change.
|
||||
$sql = "SELECT id FROM " . self::TBL . " WHERE start = ? AND title LIKE ?";
|
||||
$params = [$startDateStr, "%{$searchTitlePart}%"];
|
||||
|
||||
$result = DB::one($sql, $params);
|
||||
|
||||
return $result ? (int)$result['id'] : null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Email Service (einfach) ----
|
||||
@@ -1013,8 +1084,10 @@ class Commands
|
||||
'SENDMAIL2BEO' => 'Mail an Mitarbeiter',
|
||||
'SENDMAIL2LISTE' => 'Mail an Verteiler',
|
||||
'PUT2KALENDER' => 'Kalender-Eintrag',
|
||||
'UPDATE_KALENDER_BEO' => 'Kalender-Eintrag BEOS aktualisieren',
|
||||
'GET_FDATES' => 'Führungstermine für Kalenderansicht',
|
||||
'GET_CALENTRIES' => 'Kalendereinträge abrufen',
|
||||
'GET_ONEENTRY' => 'einen Kalendereintrag abrufen',
|
||||
'PUT_CALENTRY' => 'Kalendereintrag erstellen',
|
||||
'DEL_CALENTRY' => 'Kalendereintrag löschen',
|
||||
'GET_YEARS' => 'Liste verfügbare Jahre (Statistik)',
|
||||
@@ -1234,7 +1307,6 @@ try {
|
||||
IBAN DE18 6007 0070 0122 0383 00
|
||||
BIC: DEUTDESSXXX
|
||||
|
||||
|
||||
Mit sternfreundlichen Grüßen
|
||||
Reinhard X. Fürst
|
||||
Sternwarte Welzheim
|
||||
@@ -1243,6 +1315,8 @@ try {
|
||||
respond(['success' => $ok]);
|
||||
|
||||
case 'SENDMAIL2BEO':
|
||||
$mailNote = trim((string)($input['mail_note'] ?? ''));
|
||||
$mailNoteBlock = $mailNote !== '' ? "\n " . $mailNote . "\n" : "\n";
|
||||
$mail = RepoBeos::email($input['ma']);
|
||||
$vor = RepoBeos::vorname($input['ma']);
|
||||
$dt = date('d.m.Y H:i', strtotime($input['termin']));
|
||||
@@ -1260,6 +1334,8 @@ Hallo " . $vor .",
|
||||
Der Termin wurde in den Sternwartenkalender eingetragen.
|
||||
|
||||
Die Kontaktdaten sind auf der Sonderführungsseite ( https://sternwarte-welzheim.de/intern/sofue/sofue.php ) zu finden.
|
||||
|
||||
{$mailNoteBlock}
|
||||
|
||||
Viele Grüße
|
||||
Reinhard
|
||||
@@ -1272,16 +1348,13 @@ Hallo " . $vor .",
|
||||
case 'SENDMAIL2LISTE':
|
||||
$info = RepoSoFue::getById((int)$input['id']);
|
||||
if (!$info) respondError('Führung nicht gefunden', 404);
|
||||
$mailNote = trim((string)($input['mail_note'] ?? ''));
|
||||
$to = $input['to'] ?? LISTE_EMAIL;
|
||||
$subject = 'Neue Anfrage Sonderführung am ' . date('d.m.Y', strtotime($info['wtermin']));
|
||||
$body = "
|
||||
Liebe BEOs,
|
||||
|
||||
wer kann folgende Sonderführung übernehmen?
|
||||
|
||||
Viele Grüße
|
||||
Reinhard
|
||||
|
||||
---------------------------------------------------------------------------------------------------";
|
||||
|
||||
$body = $body . "
|
||||
@@ -1294,6 +1367,10 @@ Weitere Fragen oder Mitteilungen:
|
||||
" . $info['mitteilung'] . "
|
||||
Spendenbescheinigung: \t" . $info['spende'] . "
|
||||
---------------------------------------------------------------------------------------------------";
|
||||
if ($mailNote !== '') {
|
||||
$body .= "\n\n" . $mailNote . "\n";
|
||||
}
|
||||
$body .= "\n\nViele Grüße\nReinhard\n";
|
||||
$ok = Mailer::sendPlain($to, $subject, $body);
|
||||
respond(['success' => $ok]);
|
||||
|
||||
@@ -1328,6 +1405,29 @@ Spendenbescheinigung: \t" . $info['spende'] . "
|
||||
]);
|
||||
error_log('Kalender-Eintrag erstellt: ' . $input['id'] . ' ' . $input['termin'] . ' ' . $input['mitarbeiter']);
|
||||
respond(['success' => true]);
|
||||
|
||||
case 'UPDATE_KALENDER_BEO':
|
||||
if (!isset($input['id'], $input['mitarbeiter'])) respondError('Missing fields for calendar update');
|
||||
|
||||
$sofueId = (int)$input['id'];
|
||||
$mitarbeiter = $input['mitarbeiter'];
|
||||
|
||||
// Fetch Sonderführung details to get wtermin
|
||||
$sofue = RepoSoFue::getById($sofueId);
|
||||
if (!$sofue) respondError('Sonderführung not found for calendar update', 404);
|
||||
|
||||
$wtermin = $sofue['wtermin'];
|
||||
|
||||
// Find the calendar entry ID based on sofueId and wtermin
|
||||
$kalenderId = RepoKalender::findEntryBySofueIdAndTermin($sofueId, $wtermin);
|
||||
|
||||
if (!$kalenderId) {
|
||||
error_log("UPDATE_KALENDER_BEO: Could not find calendar entry for Sofue ID {$sofueId} and wtermin {$wtermin}.");
|
||||
respondError('Corresponding calendar entry not found.', 404);
|
||||
}
|
||||
|
||||
RepoKalender::updateBeos($kalenderId, $mitarbeiter);
|
||||
respond(['success' => true]);
|
||||
case 'GET_FDATES':
|
||||
// Returns führungen for calendar display
|
||||
if (!isset($input['start'], $input['end'])) respondError('start and end required');
|
||||
@@ -1352,6 +1452,9 @@ Spendenbescheinigung: \t" . $info['spende'] . "
|
||||
case 'GET_CALENTRIES':
|
||||
if (!isset($input['start'], $input['end'])) respondError('start and end required');
|
||||
respond(RepoKalender::getEntries($input['start'], $input['end']));
|
||||
case 'GET_ONEENTRY':
|
||||
if (!isset($input['date'])) respondError('date required');
|
||||
respond(RepoKalender::getOneEntry($input['date']));
|
||||
case 'PUT_CALENTRY':
|
||||
RepoKalender::insert($input['data']);
|
||||
respond(['success' => true]);
|
||||
|
||||
@@ -17,6 +17,20 @@ server {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
|
||||
# Serve beoanswer frontend build output from dist
|
||||
location = /beoanswer/ {
|
||||
try_files /beoanswer/dist/index.html =404;
|
||||
}
|
||||
|
||||
location /beoanswer/assets/ {
|
||||
alias /var/www/html/beoanswer/dist/assets/;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /beoanswer/anleitung.html {
|
||||
try_files /beoanswer/dist/anleitung.html =404;
|
||||
}
|
||||
|
||||
# Specify the details of favicon.ico
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ $allowedOrigins = [
|
||||
'https://ihre-produktions-domain.de' // Ersetzen Sie durch Ihre echte Domain
|
||||
];
|
||||
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||
$origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
|
||||
if (in_array($origin, $allowedOrigins)) {
|
||||
header("Access-Control-Allow-Origin: $origin");
|
||||
} else {
|
||||
@@ -41,16 +41,24 @@ $backendUrl = 'https://sternwarte-welzheim.de/intern/sofue/php/sofueDB.php';
|
||||
|
||||
// Credentials sicher laden - verschiedene Optionen:
|
||||
// Option 1: Aus Environment Variables (empfohlen)
|
||||
$username = getenv('SOFUE_USERNAME') ?: $_ENV['SOFUE_USERNAME'] ?? null;
|
||||
$password = getenv('SOFUE_PASSWORD') ?: $_ENV['SOFUE_PASSWORD'] ?? null;
|
||||
$username = getenv('SOFUE_USERNAME');
|
||||
if ($username === false || $username === '') {
|
||||
$username = isset($_ENV['SOFUE_USERNAME']) ? $_ENV['SOFUE_USERNAME'] : null;
|
||||
}
|
||||
|
||||
$password = getenv('SOFUE_PASSWORD');
|
||||
if ($password === false || $password === '') {
|
||||
$password = isset($_ENV['SOFUE_PASSWORD']) ? $_ENV['SOFUE_PASSWORD'] : null;
|
||||
}
|
||||
|
||||
// Option 2: Aus separater Config-Datei (Fallback)
|
||||
if (!$username || !$password) {
|
||||
$configFile = __DIR__ . '/cors-config.php';
|
||||
if (file_exists($configFile)) {
|
||||
include $configFile;
|
||||
// cors-config.php sollte enthalten:
|
||||
// <?php $username = 'beogruppe'; $password = 'ArktUhr'; ?>
|
||||
// cors-config.php sollte enthalten:
|
||||
// $username = 'beogruppe';
|
||||
// $password = 'ArktUhr';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "beoanswer_react",
|
||||
"private": true,
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -29,7 +29,7 @@ section {
|
||||
border-bottom : 1px solid rgb(187, 185, 185);
|
||||
text-align: left;
|
||||
margin: 0 auto 20px auto;
|
||||
padding: 0 0em 1em 2em;
|
||||
padding: 0 0em 0.5em 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ export default function FandStattVer({left, right, title, onNext, radioName = "f
|
||||
const handleRadioChange = (e) => {
|
||||
const value = e.target.value
|
||||
updateFormData(fieldName, value)
|
||||
setAuswahl(value)
|
||||
setbackButton(true)
|
||||
if(radioName !== 'abgesagt') {
|
||||
setAuswahl(value)
|
||||
onNext(value)
|
||||
} else {
|
||||
onNext()
|
||||
|
||||
@@ -53,6 +53,9 @@ export default function Verschoben({onNext, isCompleted}) {
|
||||
<button className="okbutton" onClick={handleOK}>OK</button>
|
||||
|
||||
</div>
|
||||
<p style={{ fontWeight: 'normal', fontSize: '0.9em', marginTop: '1.5em' }}>
|
||||
Falls noch kein Termin bekannt ist, bitte <strong>31.12.2099 20:00</strong> eingeben.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<Modal
|
||||
|
||||
@@ -15,6 +15,9 @@ Dieses Programm kann auch die Überwachung machen, dass Einträge in der DB gel
|
||||
|
||||
|
||||
Versions:
|
||||
V 1.0.2 2026-03-01 rxf
|
||||
- Mehrere Führungen am gleichen Tag werden nun alle verarbeitet (je eine E-Mail pro Eintrag).
|
||||
|
||||
V 1.0.1 2025-11-17 rxf
|
||||
- Übergabe der Tage bis zu 'gestern' als Commandline Parameter: '-d x'. Ohne -d wird 1 angesetzt.
|
||||
|
||||
@@ -61,30 +64,44 @@ const transporter = DEVELOP ? nodemailer.createTransport({
|
||||
});
|
||||
|
||||
|
||||
// Ajax-Call, um die Daten von der DBase zu holen
|
||||
async function fetchDatafromDB(conn,termin) {
|
||||
let result;
|
||||
let id;
|
||||
let query = "select mitarbeiter,id from SoFue2 where DATE(wtermin) = '" + termin + "' and status = 2";
|
||||
// Daten aus der DB holen und für jeden Eintrag eine E-Mail senden
|
||||
async function fetchDatafromDB(conn, termin) {
|
||||
try {
|
||||
result = await conn.query(query);
|
||||
if (result[0].length == 0) {
|
||||
const query = "select mitarbeiter,id from SoFue2 where DATE(wtermin) = '" + termin + "' and status = 2";
|
||||
const [rows] = await conn.query(query);
|
||||
|
||||
if (rows.length === 0) {
|
||||
console.log("Keine Führung gewesen");
|
||||
return;
|
||||
}
|
||||
let ma = result[0][0].mitarbeiter;
|
||||
id = result[0][0].id;
|
||||
query = "select vorname,email_1 from beos where name = '" + ma + "'";
|
||||
result = await conn.query(query);
|
||||
|
||||
console.log(`${rows.length} Führung(en) gefunden für ${termin}`);
|
||||
|
||||
for (const row of rows) {
|
||||
const ma = row.mitarbeiter;
|
||||
const id = row.id;
|
||||
const beoQuery = "select vorname,email_1 from beos where name = '" + ma + "'";
|
||||
const [beoRows] = await conn.query(beoQuery);
|
||||
|
||||
if (beoRows.length === 0) {
|
||||
console.log(`Kein BEO-Eintrag gefunden für Mitarbeiter: ${ma} (id=${id})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
send2BEO({
|
||||
name: beoRows[0].vorname,
|
||||
email: (beoRows[0].email_1).toLowerCase(),
|
||||
date: termin,
|
||||
id: id
|
||||
});
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
finally {
|
||||
finally {
|
||||
conn.end();
|
||||
}
|
||||
let erg = result[0];
|
||||
send2BEO({name: erg[0].vorname, email: erg[0].email_1, date: termin, id: id});
|
||||
}
|
||||
|
||||
|
||||
@@ -116,13 +133,17 @@ function send2BEO(info) {
|
||||
async function main() {
|
||||
// console.log(DB_host, DB_port, DB_user, DB_pass, DB_dbase);
|
||||
console.log('Start: ' + moment().format('YYYY-MM-DD HH:mm'))
|
||||
const connection = await mysql.createConnection({
|
||||
// host: DB_host,
|
||||
// port: DB_port,
|
||||
const connection = await mysql.createConnection(DEVELOP ? {
|
||||
host: DB_host,
|
||||
port: DB_port,
|
||||
user: DB_user,
|
||||
password: DB_pass,
|
||||
database: DB_dbase,
|
||||
socketPath: '/var/lib/mysql/mysql.sock'
|
||||
} : {
|
||||
user: DB_user,
|
||||
password: DB_pass,
|
||||
database: DB_dbase,
|
||||
socketPath: '/var/lib/mysql/mysql.sock'
|
||||
});
|
||||
const yesterday = moment().subtract(DAYS, 'd').format('YYYY-MM-DD');
|
||||
console.log('Yesterday:', yesterday)
|
||||
|
||||
@@ -21,6 +21,6 @@ Widerspruch.
|
||||
</p>
|
||||
<p>Wir weisen Sie abschließend darauf hin, dass die Datenübertragung im Internet (z.B. bei der
|
||||
Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor
|
||||
dem Zugriff durch Dritte ist nicht möglich.</p>
|
||||
dem Zugriff durch Dritte ist nicht möglich.</p>
|
||||
Der Datenschutzbeauftragte C.A. Riedl - Kontakt: <a href="mailto: HUK@gfpw.org"> HUK@gfpw.org</a>
|
||||
<p></p>
|
||||
|
||||
@@ -25,7 +25,7 @@ function checkFuehrung(was) {
|
||||
}
|
||||
|
||||
//Übersicht über alle Stati
|
||||
//Jeweils nur 5 Einträge, kein Pager
|
||||
//Jeweils nur 5 Einträge, kein Pager/
|
||||
function uebersicht() {
|
||||
for (var i=0; i< stati.length; i++) {
|
||||
buildGrid(''+(i+1),15,false);
|
||||
@@ -565,13 +565,31 @@ function saveSettings() {
|
||||
// 'Content-Type': 'application/json'
|
||||
// }
|
||||
// })
|
||||
doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
|
||||
if (status == 1 || status == 2) {
|
||||
doAjaxCall_arr(ajaxURL, cmd, function() {
|
||||
openMailNoteDialog(status, id, marb, termin);
|
||||
});
|
||||
} else {
|
||||
doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
|
||||
}
|
||||
}
|
||||
|
||||
if(status == 1) { // offen -> mail an Liste
|
||||
sendmail2liste(id, termin);
|
||||
function openMailNoteDialog(status, id, marb, termin) {
|
||||
$('#mailnote_text').val('');
|
||||
$('#div_mailnote').data({
|
||||
status: status,
|
||||
id: id,
|
||||
marb: marb,
|
||||
termin: termin
|
||||
}).dialog('open');
|
||||
}
|
||||
|
||||
function sendStatusMails(status, id, marb, termin, mailNote) {
|
||||
if (status == 1) { // offen -> mail an Liste
|
||||
sendmail2liste(id, termin, mailNote);
|
||||
}
|
||||
if (status == 2) {
|
||||
sendmail2beo(id, marb, termin)
|
||||
sendmail2beo(id, marb, termin, mailNote);
|
||||
sendmailzusage(id, marb, termin);
|
||||
}
|
||||
}
|
||||
@@ -612,9 +630,12 @@ function showdbase(val) {
|
||||
}
|
||||
|
||||
// Status wurde auf 'offen' gesetzt -> nun eine Mail an die Liste mit der Anfrage senden
|
||||
function sendmail2liste(id, termin) {
|
||||
function sendmail2liste(id, termin, mailNote) {
|
||||
const liste = 'sternwarte@planetariumsgesellschaft.de';
|
||||
let cmd = {cmd: 'SENDMAIL2LISTE', id: id, to: liste}
|
||||
if (mailNote) {
|
||||
cmd.mail_note = mailNote;
|
||||
}
|
||||
console.log("Sende mail to Liste");
|
||||
doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
|
||||
console.log("Mail gesendet");
|
||||
@@ -624,13 +645,16 @@ function sendmail2liste(id, termin) {
|
||||
}
|
||||
|
||||
// Status wurde auf 'zugesgat' gesetzt -> nun eine Mail an den BEO senden
|
||||
function sendmail2beo(id, beo, termin) {
|
||||
function sendmail2beo(id, beo, termin, mailNote) {
|
||||
let cmd = {cmd: 'SENDMAIL2BEO', ma: beo, termin: termin}
|
||||
if (mailNote) {
|
||||
cmd.mail_note = mailNote;
|
||||
}
|
||||
console.log("Sende mail to " + beo);
|
||||
doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
|
||||
console.log("Mail gesendet");
|
||||
// und in den Kalender eintragen
|
||||
cmd = {cmd: 'PUT2KALENDER', id: id, termin: termin, mitarbeiter: beo}
|
||||
cmd = {cmd: 'UPDATE_KALENDER_BEO', id: id, mitarbeiter: beo}
|
||||
doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
|
||||
}
|
||||
|
||||
@@ -786,8 +810,44 @@ $(document).ready(function() {
|
||||
],
|
||||
});
|
||||
|
||||
// 3. Dialog für optionale Mail-Bemerkung
|
||||
$('#div_mailnote').dialog({
|
||||
autoOpen: false,
|
||||
width: 600,
|
||||
modal: true,
|
||||
title: 'Zusätzliche Bemerkung für E-Mail',
|
||||
buttons: [
|
||||
{
|
||||
text: 'Ohne Bemerkung senden',
|
||||
class: 'btnOK ui-button-left',
|
||||
click: function() {
|
||||
var data = $('#div_mailnote').data();
|
||||
$(this).dialog('close');
|
||||
sendStatusMails(data.status, data.id, data.marb, data.termin, '');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Mit Bemerkung senden',
|
||||
class: 'btnOK ui-button-left',
|
||||
click: function() {
|
||||
var data = $('#div_mailnote').data();
|
||||
var note = $('#mailnote_text').val().trim();
|
||||
$(this).dialog('close');
|
||||
sendStatusMails(data.status, data.id, data.marb, data.termin, note);
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Abbrechen',
|
||||
click: function() {
|
||||
$(this).dialog('close');
|
||||
location.reload(true);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
// 3. Dialog für die Anleitung
|
||||
// 4. Dialog für die Anleitung
|
||||
// Dieser hat KEINEN Button (wird über das Schließkreuz beendet) und
|
||||
// eine etwas kleinere Schrift
|
||||
$("#anleitung").dialog({
|
||||
@@ -812,7 +872,7 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
|
||||
// 4. Dialog für die Wartungs-Meldung
|
||||
// 5. Dialog für die Wartungs-Meldung
|
||||
// Wird nur aufgerufen, wenn das Flag WARTUNG gesetzt ist
|
||||
// Kann NICHT beendet werden
|
||||
$('#maint').dialog({
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
// VersiosNummern und -Geschichte
|
||||
|
||||
var VERSION="1.95";
|
||||
var VDATE="2026-01-19";
|
||||
var VERSION="2.0.0";
|
||||
var VDATE="2026-03-17";
|
||||
|
||||
/* History
|
||||
|
||||
Rev. Datum Entwickler
|
||||
2.0.0 2026-03-17
|
||||
- Semantische Versionierung eiungeführt
|
||||
- Vor dem Senden der Mail bei 'offen' und 'zugesagt' erscheint ein Popup,
|
||||
in welches man einen Text eingeben kann, der in der Mail mit gesendet wird.
|
||||
|
||||
1.95 2026-01-19
|
||||
- Eintrag in den Kalender auch bei 'offen'
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ if ((isset($_GET['fuehrung'])) && ($_GET['fuehrung'] == "TFC7364gf:l@vtr")) {
|
||||
<div id="div_loesch">
|
||||
<p>Diesen Eintrag wirklich aus der Datenbank löschen ?</p>
|
||||
</div>
|
||||
<div id="div_mailnote" style="display:none;">
|
||||
<p>Optional: Zusätzliche Bemerkung für die ausgehende E-Mail.</p>
|
||||
<textarea id="mailnote_text" rows="6" style="width:98%;"></textarea>
|
||||
</div>
|
||||
<div id="anleitung"></div>
|
||||
<div id="maint"></div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user