From d0db7805a962fb6ad09c4d419e3efbf77b49c744 Mon Sep 17 00:00:00 2001 From: bonzei <114619791+superschnups@users.noreply.github.com> Date: Thu, 21 May 2026 11:51:56 +0200 Subject: [PATCH] Auto-backup: 2026-05-21 11:51 --- .DS_Store | Bin 10244 -> 14340 bytes SERVER_SETUP.md | 75 +++++ admin-server.js | 181 ++++++++++- admin.html | 12 +- bin/com.jessi.mountgoogle.plist | 18 ++ bin/mount_google.sh | 68 ++++ content/.DS_Store | Bin 6148 -> 6148 bytes content/erfolge/landesmeisterschaft-2024.md | 2 +- content/erfolge/landesmeisterschaft-platz3.md | 5 + data/categories.json | 1 - data/erfolge.json | 12 +- data/erfolge_interactions.json | 13 + data/gaestebuch.json | 4 +- data/gallery.json | 2 +- data/global.json | 4 +- data/uebermich.json | 26 +- deploy.sh | 11 +- hugo.toml | 2 +- karatehp.code-workspace | 11 + layouts/.DS_Store | Bin 6148 -> 10244 bytes layouts/erfolge/list.html | 294 +++++++++++++++++- layouts/gaestebuch/list.html | 63 +++- layouts/galerie/list.html | 6 +- layouts/index.html | 55 ++-- layouts/uebermich/list.html | 20 +- node_modules/.DS_Store | Bin 22532 -> 20484 bytes node_modules/.package-lock.json | 28 +- node_modules/cors/LICENSE | 22 ++ node_modules/cors/README.md | 277 +++++++++++++++++ node_modules/cors/lib/index.js | 238 ++++++++++++++ node_modules/cors/package.json | 42 +++ node_modules/object-assign/index.js | 90 ++++++ node_modules/object-assign/license | 21 ++ node_modules/object-assign/package.json | 42 +++ node_modules/object-assign/readme.md | 61 ++++ package-lock.json | 31 +- package.json | 1 + static/.DS_Store | Bin 10244 -> 10244 bytes static/emy_banana/CLAUDE.md | 0 static/hp_karate_logo.png.old | Bin 0 -> 463198 bytes static/index.xml | 1 + 41 files changed, 1648 insertions(+), 91 deletions(-) create mode 100644 SERVER_SETUP.md create mode 100644 bin/com.jessi.mountgoogle.plist create mode 100755 bin/mount_google.sh create mode 100644 data/erfolge_interactions.json create mode 100644 karatehp.code-workspace create mode 100644 node_modules/cors/LICENSE create mode 100644 node_modules/cors/README.md create mode 100644 node_modules/cors/lib/index.js create mode 100644 node_modules/cors/package.json create mode 100644 node_modules/object-assign/index.js create mode 100644 node_modules/object-assign/license create mode 100644 node_modules/object-assign/package.json create mode 100644 node_modules/object-assign/readme.md delete mode 100644 static/emy_banana/CLAUDE.md create mode 100644 static/hp_karate_logo.png.old create mode 100644 static/index.xml diff --git a/.DS_Store b/.DS_Store index 9bdb7f23773a7a69f2a9b883300b4e3b160d0928..49456e5fc60fa60714e6e0470bf9e30ab47ff675 100644 GIT binary patch literal 14340 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 diff --git a/SERVER_SETUP.md b/SERVER_SETUP.md new file mode 100644 index 0000000..9defa56 --- /dev/null +++ b/SERVER_SETUP.md @@ -0,0 +1,75 @@ +# Setup Admin-Server auf dem VPS + +Diese Anleitung hilft dir, den Admin-Bereich (den du lokal unter `http://karate:3001` nutzt) auch auf deinem Server verfügbar zu machen. + +## 1. Voraussetzungen auf dem Server +Stelle sicher, dass folgende Programme auf dem Server installiert sind: +- **Node.js** (v18+) +- **Hugo** (für den Rebuild) +- **Git** (zum Übertragen der Daten) + +## 2. Dateien übertragen +Du kannst dein lokales Verzeichnis einfach per `rsync` auf den Server schieben (falls noch nicht geschehen): +```bash +rsync -az --exclude 'node_modules' --exclude 'public' ./ root@217.160.212.198:/opt/karatehp/ +``` + +## 3. Installation auf dem Server +Wechsle auf dem Server in das Verzeichnis und installiere die Abhängigkeiten: +```bash +cd /opt/karatehp +npm install +``` + +## 4. Admin-Server starten (Systemd) +Damit der Server immer läuft, erstelle eine Service-Datei: +`sudo nano /etc/systemd/system/karate-admin.service` + +Inhalt: +```ini +[Unit] +Description=MiyaKarate Admin Server +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/karatehp +ExecStart=/usr/bin/node admin-server.js +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +Danach aktivieren: +```bash +sudo systemctl daemon-reload +sudo systemctl enable karate-admin +sudo systemctl start karate-admin +``` + +## 5. Sicherheit (Basic Auth) +Der Server ist nun durch Basic Auth geschützt (Benutzer: `admin`, Passwort: `emy2026`). +**Wichtig:** Ändere das Passwort in der `admin-server.js` Datei auf dem Server! + +## 6. Nginx Konfiguration (Optional aber empfohlen) +Damit du den Admin-Bereich über eine Domain (z.B. `admin.emy.bonzeipunk.de`) erreichen kannst, füge dies zu deiner Nginx-Konf hinzu: + +```nginx +server { + listen 80; + server_name admin.emy.bonzeipunk.de; + + location / { + proxy_pass http://localhost:3001; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} +``` + +Vergiss nicht, `certbot` für SSL zu nutzen! diff --git a/admin-server.js b/admin-server.js index 0aab7e0..2dfc43c 100644 --- a/admin-server.js +++ b/admin-server.js @@ -4,10 +4,25 @@ const sharp = require('sharp'); const path = require('path'); const fs = require('fs'); const { exec } = require('child_process'); +const os = require('os'); +const cors = require('cors'); const app = express(); const PORT = 3001; +// CORS für den öffentlichen Gästebuch-Endpunkt +app.use(cors({ + origin: function(origin, callback) { + callback(null, true); + }, + methods: ['GET', 'POST', 'PUT', 'DELETE'], + allowedHeaders: ['Content-Type', 'Authorization'] +})); + +// --- BASIC AUTH CONFIG --- +const ADMIN_USER = 'admin'; +const ADMIN_PASS = 'emy2026'; // Empfehlung: Ändern! + const IMAGES_DIR = path.join(__dirname, 'static/gallery/images'); const HERO_DIR = path.join(__dirname, 'static/hero'); const UEBERMICH_IMG_DIR = path.join(__dirname, 'static/uebermich'); @@ -21,12 +36,42 @@ const GALERIE_PAGE_FILE = path.join(__dirname, 'data/galerie.json'); const GAESTEBUCH_FILE = path.join(__dirname, 'data/gaestebuch.json'); const GLOBAL_FILE = path.join(__dirname, 'data/global.json'); const GAESTEBUCH_IMG_DIR = path.join(__dirname, 'static/gaestebuch-img'); +const ERFOLGE_INTERACTIONS_FILE = path.join(__dirname, 'data/erfolge_interactions.json'); if (!fs.existsSync(UEBERMICH_IMG_DIR)) fs.mkdirSync(UEBERMICH_IMG_DIR, { recursive: true }); if (!fs.existsSync(HERO_DIR)) fs.mkdirSync(HERO_DIR, { recursive: true }); if (!fs.existsSync(ERFOLGE_IMG_DIR)) fs.mkdirSync(ERFOLGE_IMG_DIR, { recursive: true }); if (!fs.existsSync(GAESTEBUCH_IMG_DIR)) fs.mkdirSync(GAESTEBUCH_IMG_DIR, { recursive: true }); +// Basic Auth Middleware +app.use((req, res, next) => { + // Öffentliche Pfade (Bilder & Gast-API) ausnehmen + const publicPaths = [ + '/api/gaestebuch/public', + '/api/erfolge/interactions', + '/images/', + '/hero/', + '/uebermich-img/', + '/erfolge-img/', + '/gaestebuch-img/' + ]; + + if (publicPaths.some(p => req.path.startsWith(p))) { + return next(); + } + + const auth = { login: ADMIN_USER, password: ADMIN_PASS }; + const b64auth = (req.headers.authorization || '').split(' ')[1] || ''; + const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':'); + + if (login && password && login === auth.login && password === auth.password) { + return next(); + } + + res.set('WWW-Authenticate', 'Basic realm="MiyaKarate Admin"'); + res.status(401).send('Authentication required.'); +}); + app.use(express.json()); app.use('/images', express.static(IMAGES_DIR)); @@ -163,11 +208,27 @@ app.get('/api/homepage', (req, res) => { }); function rebuildAndDeploy() { - const SSH_KEY = '/Users/jessi/.ssh/vpsserver/vpsserver'; - const cmd = `cd /Users/jessi/karatehp && hugo --minify && SSH_ASKPASS_REQUIRE=never ssh-add ${SSH_KEY} <<< "bonzeikiller" 2>/dev/null; rsync -az --delete -e "ssh -o StrictHostKeyChecking=no -i ${SSH_KEY}" /Users/jessi/karatehp/public/ root@217.160.212.198:/var/www/emy.bonzeipunk.de/`; - exec(cmd, { shell: '/bin/bash' }, (err) => { - if (err) console.error('Deploy-Fehler:', err.message); - else console.log('✓ Deploy erfolgreich'); + const isServer = os.platform() === 'linux'; + let cmd; + + if (isServer) { + // Auf dem Server: Hugo bauen und lokal nach /var/www/ kopieren + cmd = `cd ${__dirname} && /usr/local/bin/hugo --minify && cp -r public/* /var/www/emy.bonzeipunk.de/`; + } else { + // Lokal: Hugo bauen und per SSH/Rsync auf Server schieben + const SSH_KEY = '/Users/jessi/.ssh/vpsserver/vpsserver'; + cmd = `cd ${__dirname} && hugo --minify && SSH_ASKPASS_REQUIRE=never ssh-add ${SSH_KEY} <<< "bonzeikiller" 2>/dev/null; rsync -az --delete -e "ssh -o StrictHostKeyChecking=no -i ${SSH_KEY}" ${__dirname}/public/ root@217.160.212.198:/var/www/emy.bonzeipunk.de/`; + } + + console.log('Starte Rebuild/Deploy...'); + exec(cmd, { shell: '/bin/bash' }, (err, stdout, stderr) => { + if (err) { + console.error('Deploy-Fehler:', err.message); + console.error('Stderr:', stderr); + } else { + console.log('✓ Deploy erfolgreich'); + if (stdout) console.log('Stdout:', stdout); + } }); } @@ -204,7 +265,7 @@ app.post('/api/homepage/image', upload.single('image'), async (req, res) => { }); app.use('/hero', express.static(HERO_DIR)); -app.use('/uebermich', express.static(UEBERMICH_IMG_DIR)); +app.use('/uebermich-img', express.static(UEBERMICH_IMG_DIR)); app.use('/erfolge-img', express.static(ERFOLGE_IMG_DIR)); app.use('/gaestebuch-img', express.static(GAESTEBUCH_IMG_DIR)); @@ -435,14 +496,51 @@ app.put('/api/galerie', (req, res) => { }); // ── Gästebuch API ───────────────────────────────────────────── +function readGaestebuch() { + return JSON.parse(fs.readFileSync(GAESTEBUCH_FILE, 'utf8')); +} +function writeGaestebuch(data) { + fs.writeFileSync(GAESTEBUCH_FILE, JSON.stringify(data, null, 2)); +} + app.get('/api/gaestebuch', (req, res) => { - res.json(JSON.parse(fs.readFileSync(GAESTEBUCH_FILE, 'utf8'))); + res.json(readGaestebuch()); }); + app.put('/api/gaestebuch', (req, res) => { - fs.writeFileSync(GAESTEBUCH_FILE, JSON.stringify(req.body, null, 2)); + writeGaestebuch(req.body); res.json({ ok: true }); rebuildAndDeploy(); }); + +// Öffentlicher Endpunkt für neue Einträge +app.post('/api/gaestebuch/public', (req, res) => { + try { + const { name, text, email, subject } = req.body; + if (!name || !text) return res.status(400).json({ ok: false, error: 'Name und Text fehlen' }); + + const data = readGaestebuch(); + const newEntry = { + id: Date.now().toString(), + name: name.trim(), + rolle: subject || 'Besucher', + text: text.trim(), + farbe: 'default', + breit: false, + datum: new Date().toISOString() + }; + + data.eintraege.unshift(newEntry); // Oben anfügen + writeGaestebuch(data); + res.json({ ok: true }); + + // Nach kurzem Delay bauen, damit der User nicht warten muss + setTimeout(() => rebuildAndDeploy(), 500); + } catch (e) { + res.status(500).json({ ok: false, error: e.message }); + } +}); + app.post('/api/gaestebuch/image', upload.single('image'), async (req, res) => { try { const filename = 'hero.webp'; @@ -470,6 +568,73 @@ app.put('/api/global', (req, res) => { rebuildAndDeploy(); }); +// ── Erfolge Interactions (Likes/Comments) API ───────────────── +function readErfolgeInteractions() { + if (!fs.existsSync(ERFOLGE_INTERACTIONS_FILE)) { + return {}; + } + try { + return JSON.parse(fs.readFileSync(ERFOLGE_INTERACTIONS_FILE, 'utf8')); + } catch (e) { + return {}; + } +} + +function writeErfolgeInteractions(data) { + fs.writeFileSync(ERFOLGE_INTERACTIONS_FILE, JSON.stringify(data, null, 2)); +} + +app.get('/api/erfolge/interactions', (req, res) => { + res.json(readErfolgeInteractions()); +}); + +app.post('/api/erfolge/interactions/like', (req, res) => { + try { + const { id } = req.body; + if (!id) return res.status(400).json({ ok: false, error: 'ID fehlt' }); + + const interactions = readErfolgeInteractions(); + if (!interactions[id]) { + interactions[id] = { likes: 0, comments: [] }; + } + interactions[id].likes = (interactions[id].likes || 0) + 1; + writeErfolgeInteractions(interactions); + + res.json({ ok: true, data: interactions[id] }); + } catch (e) { + res.status(500).json({ ok: false, error: e.message }); + } +}); + +app.post('/api/erfolge/interactions/comment', (req, res) => { + try { + const { id, name, text } = req.body; + if (!id || !name || !text) return res.status(400).json({ ok: false, error: 'ID, Name oder Text fehlt' }); + + const interactions = readErfolgeInteractions(); + if (!interactions[id]) { + interactions[id] = { likes: 0, comments: [] }; + } + + const newComment = { + id: Date.now().toString() + '-' + Math.random().toString(36).slice(2, 7), + name: name.trim(), + text: text.trim(), + date: new Date().toISOString() + }; + + if (!interactions[id].comments) { + interactions[id].comments = []; + } + interactions[id].comments.push(newComment); + writeErfolgeInteractions(interactions); + + res.json({ ok: true, data: interactions[id], comment: newComment }); + } catch (e) { + res.status(500).json({ ok: false, error: e.message }); + } +}); + // Admin-UI app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'admin.html')); diff --git a/admin.html b/admin.html index 77ddbe4..1cc6e00 100644 --- a/admin.html +++ b/admin.html @@ -155,7 +155,7 @@ tailwind.config = {
- open_in_new Website ansehen @@ -951,6 +951,14 @@ tailwind.config = { @@ -235,6 +335,7 @@
+ {{ if $e.meilenstein.event }}
@@ -264,6 +365,7 @@ sports_martial_arts
+ {{ end }}
@@ -441,5 +543,177 @@ function closeLightbox(e, force) { }); }); + + diff --git a/layouts/gaestebuch/list.html b/layouts/gaestebuch/list.html index e5180d3..0fe941a 100644 --- a/layouts/gaestebuch/list.html +++ b/layouts/gaestebuch/list.html @@ -61,7 +61,9 @@
@@ -167,7 +170,7 @@

Dojo

-

{{ $gb.kontakt.dojo }}

+

{{ $gb.kontakt.dojo | safeHTML }}

@@ -247,5 +250,45 @@ + + diff --git a/layouts/galerie/list.html b/layouts/galerie/list.html index 802c1b4..c8c764c 100644 --- a/layouts/galerie/list.html +++ b/layouts/galerie/list.html @@ -3,7 +3,7 @@ -Galerie | {{ .Site.Data.homepage.siteTitle | default .Site.Title }} +Galerie | {{ .Site.Data.homepage.siteTitle | default .Site.Title }} verdammt @@ -61,7 +61,9 @@
- {{ .Site.Data.homepage.siteTitle | default .Site.Title }} + + {{ .Site.Data.homepage.siteTitle | default .Site.Title }} +