const express = require('express'); const session = require('express-session'); const bcrypt = require('bcrypt'); const crypto = require('crypto'); const nodemailer = require('nodemailer'); const { Pool } = require('pg'); const path = require('path'); const moment = require('moment'); require('dotenv').config(); const log = require('node-file-logger'); const app = express(); const port = process.env.PORT; /* const TeleBot = require('telebot'); const bot = new TeleBot(process.env.TELEBOT); telebotChatID=process.env.TELECHAT; bot.on('text', (msg) => { if (msg.from.id==telebotChatID) { msg.reply.text(msg.text); } else { msg.reply.text("Entschuldige, " + msg.from.username + "\nIch darf nicht mit fremden reden."); log.Info("Telebot-nachricht: " + msg.from.username + " - " + msg.text); } }); bot.start(); */ const options = { timeZone: 'europe/Berlin', folderPath: './logs/', dateBasedFileNaming: true, fileNamePrefix: 'DailyLogs_', fileNameExtension: '.log', dateFormat: 'YYYY_MM_D', timeFormat: 'H:mm:ss', } log.SetUserOptions(options); // Middleware app.use(express.static(path.join(__dirname, 'public'))); app.use(express.json()); app.set('view engine', 'ejs'); app.use(express.urlencoded({ extended: false })); // Session-Konfiguration app.use(session({ secret: process.env.SESSIONSECRET, resave: false, saveUninitialized: true, cookie: { maxAge: 1000 * 60 * 60 * 24 * 2 } })); // Authentifizierungs-Middleware const requireAuth = (req, res, next) => { if (!req.session.userId) { return res.redirect('/login'); } next(); }; const requireAdmin = (req, res, next) => { if (req.session.role !== 'admin') { return res.status(403).send('Access denied'); } next(); }; // Email-Konfiguration const transporter = nodemailer.createTransport({ host: process.env.MAILHOST, port: 465, secure: true, auth: { user: process.env.MAILUSER, pass: process.env.MAILPASS } }); // Datenbankverbindung const pool = new Pool({ connectionString: process.env.DATABASE_URL }); // Altersberechnung const calculateAge = (birthdate) => { const today = new Date(); const birthDate = new Date(birthdate); let age = today.getFullYear() - birthDate.getFullYear(); const m = today.getMonth() - birthDate.getMonth(); if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; }; // Datumsformatierung const formatDate = (date) => { const d = new Date(date); const day = String(d.getDate()).padStart(2, '0'); const month = String(d.getMonth() + 1).padStart(2, '0'); const year = d.getFullYear(); return `${day}.${month}.${year}`; }; // Funktion zum Laden des aktuellen oder letzten Trainings const getTraining = async (kw) => { const result = await pool.query(` SELECT tr.*, g1.name AS geraet_riege_1_name, g2.name AS geraet_riege_2_name, g3.name AS geraet_riege_3_name, g4.name AS geraet_riege_4_name, g5.name AS geraet_riege_5_name, t1.name AS aufwaermleiter_name, t2.name AS spielleiter_name, sp1.name AS aufwaermen_name, sp2.name AS spiel_name FROM trainings tr LEFT JOIN geraete g1 ON tr.geraet_riege_1 = g1.id LEFT JOIN geraete g2 ON tr.geraet_riege_2 = g2.id LEFT JOIN geraete g3 ON tr.geraet_riege_3 = g3.id LEFT JOIN geraete g4 ON tr.geraet_riege_4 = g4.id LEFT JOIN geraete g5 ON tr.geraet_riege_5 = g5.id LEFT JOIN teilnehmende t1 ON tr.aufwaermleiter = t1.id LEFT JOIN teilnehmende t2 ON tr.spielleiter = t2.id LEFT JOIN spiele sp1 ON tr.aufwaermen = sp1.id LEFT JOIN spiele sp2 ON tr.spiel = sp2.id WHERE tr.kw <= $1 ORDER BY tr.kw DESC LIMIT 1 `, [kw]); return result.rows[0]; }; // Funktion zum Laden aller Spiele const getAllSpiele = async () => { const result = await pool.query(` SELECT * FROM spiele ORDER BY name ASC; `); return result.rows; }; // Funktion zum Hinzufügen eines neuen Spiels, falls es noch nicht existiert const addNewSpiel = async (spielName) => { try { const result = await pool.query('INSERT INTO spiele (name) VALUES ($1) RETURNING id', [spielName]); return result.rows[0].id; } catch (error) { console.error('Error adding new spiel:', error); throw error; } }; function getThursdayOfWeek(week, year) { const firstDayOfYear = new Date(year, 0, 1); const dayOfWeek = firstDayOfYear.getDay(); const daysUntilFirstThursday = (dayOfWeek <= 4) ? (4 - dayOfWeek) : (11 - dayOfWeek); const daysUntilThursdayOfWeek = (week - 1) * 7 + daysUntilFirstThursday; const thursdayOfWeek = new Date(year, 0, 1 + daysUntilThursdayOfWeek); return thursdayOfWeek; } // Funktion zum Laden der vier Leute, die am längsten nicht Aufwärmen oder Spiel geleitet haben const getCandidatesForAufwaermleiter = async () => { const result = await pool.query(` SELECT t.id, t.name, COALESCE(EXTRACT(EPOCH FROM (NOW() - MAX(tr.datum))) / 604800, EXTRACT(EPOCH FROM (NOW() - '1970-01-01'::date)) / 604800) AS weeks_since_last FROM teilnehmende t LEFT JOIN trainings tr ON t.id = tr.aufwaermleiter WHERE t.helfer = true GROUP BY t.id ORDER BY weeks_since_last DESC; `); return result.rows; }; const putInRiege = async (riege, teilnehmerID) => { try { if (riege == 0) { const resultRiege = await pool.query('DELETE FROM riegen WHERE fremdid_teilnehmende = $1;', [teilnehmerID]); } else { const resultRiege = await pool.query('SELECT * FROM riegen WHERE fremdid_teilnehmende = $1;', [teilnehmerID]); if (resultRiege.rows.length > 0) { const resultRiege = await pool.query('UPDATE riegen SET riegennummer = $1 WHERE fremdid_teilnehmende = $2', [riege, teilnehmerID]); log.Info("Mitglied " + teilnehmerID + " ist jetzt in Riege " + riege); } else { const resultRiege = await pool.query('INSERT INTO riegen (fremdid_teilnehmende, riegennummer) VALUES ($1, $2)', [teilnehmerID, riege]); log.Info("Mitglied " + teilnehmerID + " neu in Riege " + riege + " eingefügt."); }} } catch (error) { console.error('Error adding new spiel:', error); throw error; } }; // Funktion zum Laden der vier Leute, die am längsten nicht Spiel geleitet haben const getCandidatesForSpielleiter = async () => { const result = await pool.query(` SELECT t.id, t.name, COALESCE(EXTRACT(EPOCH FROM (NOW() - MAX(tr.datum))) / 604800, EXTRACT(EPOCH FROM (NOW() - '1970-01-01'::date)) / 604800) AS weeks_since_last FROM teilnehmende t LEFT JOIN trainings tr ON t.id = tr.spielleiter WHERE t.helfer = true GROUP BY t.id ORDER BY weeks_since_last DESC; `); return result.rows; }; // Funktion zum Laden der Riegenteilnehmer absteigend nach Alter sortiert const getRiegenMitgliederSortedByAge = async () => { const result = await pool.query(` SELECT r.riegennummer, t.name, t.alter FROM riegen r JOIN teilnehmende t ON r.fremdid_teilnehmende = t.id ORDER BY r.riegennummer, t.alter DESC `); return result.rows; }; const getAnwesenheit = function (id, anwesend) { for (let item of anwesend) { if (item.fid_teilnehmer === id) { return true; } } return false; }; // Registrierung app.post('/register', async (req, res) => { const { username, email, password } = req.body; try { const hashedPassword = await bcrypt.hash(password, 10); await pool.query('INSERT INTO users (username, email, password) VALUES ($1, $2, $3)', [username, email, hashedPassword]); const message = 'Registrierung erfolgreich. Ein Admin wird dich in kürze freischalten'; const mailOptions = { to: 'admin@boergmann.it', from: 'admin@boergmann.it', subject: 'Neue Registrierung', text: `${username} hat sich registriert` }; transporter.sendMail(mailOptions, (error) => { if (error) { console.error('Error sending email:', error); const message = 'Error sending Mail:' + error; res.render('error', { session: req.session, message }); } }); res.render('error', { session: req.session, message }); } catch (error) { console.error('Error registering user:', error); const message = 'Error registering user:' + error; res.render('error', { session: req.session, message }); } }); // Login app.post('/login', async (req, res) => { const { username, password } = req.body; try { const userResult = await pool.query("SELECT *, CASE WHEN admin_temp IS NOT NULL AND (now() - admin_temp) > interval '22 hours' THEN 'expired' ELSE 'valid' END AS admin_status FROM users WHERE username = $1", [username]); if (userResult.rows.length > 0) { const user = userResult.rows[0]; const match = await bcrypt.compare(password, user.password); if (match) { if (user.is_active) { req.session.userId = user.id; req.session.userName = user.username; req.session.activeRiege = 1; req.session.activeTab = 'geraete'; req.session.message = [title = '', message = '', type = 'none']; log.Info('Success: ' + username + ' - ' + password); if (user.admin_status === 'expired') { await pool.query('UPDATE users SET role = $1, admin_temp = NULL WHERE id = $2', ['user', user.id]); req.session.role = 'user'; } else { req.session.role = user.role; } res.redirect('/training'); } else { res.redirect('/freischaltung') } } else { const message = 'Falsches Passwort'; log.Info('wrong Pass' +username + ' - ' + password); res.render('login', { session: req.session, username, message }); } } else { const message = 'Unbekannter Benutzer'; log.Info('wrong User' +username + ' - ' + password) res.render('login', { session: req.session, username, message }); } } catch (error) { console.error('Error logging in:', error); const message = 'Error logging in:' + error; res.render('error', { session: req.session, message }); } }); //Wird angezeigt, wenn ein nicht freigeschalteter User sich anmelden will. app.get('/freischaltung', async (req, res) => { res.render('freischaltung', { session: req.session }); }) // Logout app.get('/logout', (req, res) => { req.session.destroy(err => { if (err) { return res.status(500).send('Internal Server Error'); } res.redirect('/'); }); }); // Benutzer freischalten (nur Admin) app.post('/userrights', requireAuth, requireAdmin, async (req, res) => { const { userId, type } = req.body; try { if (type === 'activate') { await pool.query('UPDATE users SET is_active = TRUE WHERE id = $1', [userId]); const userResult = await pool.query('SELECT * FROM users WHERE id = $1', [userId]); if (userResult.rows.length > 0) { if (userResult.rows[0].email) { const mailOptions = { to: userResult.rows[0].email, from: 'admin@boergmann.it', subject: 'Freischaltung', text: `Hallo ${userResult.rows[0].username}, du wurdest soeben freigeschaltet.` }; transporter.sendMail(mailOptions, (error) => { if (error) { console.error('Error sending email:', error); const message = 'Error sending Mail:' + error; res.render('error', { session: req.session, message }); } }) } } } else if (type === 'admin') { await pool.query('UPDATE users SET role = $1 WHERE id = $2', ['admin', userId]); } else if (type === 'admint') { await pool.query('UPDATE users SET role = $1, admin_temp = $2 WHERE id = $3', ['admin', moment().toDate(), userId]); } else if (type === 'delete') { await pool.query('DELETE FROM users WHERE id = $1', [userId]); } res.redirect('/admin'); } catch (error) { console.error('Error activating user:', error); const message = 'Error activating user:' + error; res.render('error', { session: req.session, message }); } }); // Passwort-Zurücksetzung anfordern app.post('/send-password', async (req, res) => { const { email } = req.body; try { const userResult = await pool.query('SELECT * FROM users WHERE email = $1', [email]); if (userResult.rows.length > 0) { const user = userResult.rows[0]; const token = crypto.randomBytes(20).toString('hex'); const resetLink = `http://tkd.boergmann.it/reset-password/${token}`; await pool.query('UPDATE users SET reset_password_token = $1, reset_password_expires = $2 WHERE id = $3', [token, selectedDate = moment().add(1, 'd').toDate(), user.id]); const mailOptions = { to: user.email, from: 'admin@boergmann.it', subject: 'Password Reset', text: `Click the following link to reset your password: ${resetLink}` }; transporter.sendMail(mailOptions, (err) => { if (err) { console.error('Error sending email:', err); const message = 'Error sending Mail:' + error; res.render('error', { session: req.session, message }); } else { const message = 'Password reset link sent'; res.render('error', { session: req.session, message }); } }); } else { const message = 'Email not found'; res.render('error', { session: req.session, message }); } } catch (error) { console.error('Error in forgot-password:', error); const message = 'Error in forgot-password'; res.render('error', { session: req.session, message }); } }); app.get('/forgot-password', async (req, res) => { res.render('forgot-password', { session: req.session }) }) // Passwort zurücksetzen app.get('/reset-password/:token', async (req, res) => { const { token } = req.params; try { // const userResult = await pool.query('SELECT * FROM users WHERE reset_password_token = $1 AND reset_password_expires > $2', [token, Date.now()]); const userResult = await pool.query("SELECT *, CASE WHEN reset_password_token IS NOT NULL AND (now() - reset_password_expires) > interval '22 hours' THEN 'expired' ELSE 'valid' END AS reset_status FROM users WHERE reset_password_token = $1", [token]); if (userResult.rows.length > 0) { res.render('reset-password', { session: req.session, token }); // Stelle sicher, dass es eine reset-password.ejs gibt } else { const message = 'Token ungültig oder abgelaufen'; res.render('error', { session: req.session, message }); } } catch (error) { console.error('Error in reset-password:', error); const message = 'Error in reset-password'; res.render('error', { session: req.session, message }); } }); app.post('/reset-password/:token', async (req, res) => { const { token } = req.params; const { password } = req.body; try { const userResult = await pool.query("SELECT *, CASE WHEN reset_password_token IS NOT NULL AND (now() - reset_password_expires) > interval '22 hours' THEN 'expired' ELSE 'valid' END AS reset_status FROM users WHERE reset_password_token = $1", [token]); if (userResult.rows.length > 0) { const user = userResult.rows[0]; const hashedPassword = await bcrypt.hash(password, 10); await pool.query('UPDATE users SET password = $1, reset_password_token = NULL, reset_password_expires = NULL WHERE id = $2', [hashedPassword, user.id]); res.redirect('/login'); } else { const message = 'Token ungültig oder abgelaufen'; res.render('error', { session: req.session, message }); } } catch (error) { console.error('Error in reset-password:', error); const message = 'Error in reset-password'; res.render('error', { session: req.session, message }); } }); // Profilseite app.get('/profile', requireAuth, (req, res) => { res.render('profile', { session: req.session }); // Stelle sicher, dass es eine profile.ejs gibt }); app.post('/profile', requireAuth, async (req, res) => { const { email, password } = req.body; try { if (email) { await pool.query('UPDATE users SET email = $1 WHERE id = $2', [email, req.session.userId]); } if (password) { const hashedPassword = await bcrypt.hash(password, 10); await pool.query('UPDATE users SET password = $1 WHERE id = $2', [hashedPassword, req.session.userId]); } res.redirect('/profile'); } catch (error) { console.error('Error updating profile:', error); const message = 'Error updating profile:' + error; res.render('error', { session: req.session, message }); } }); app.post('/update-training', requireAuth, async (req, res) => { const { trainingId, type, spielName } = req.body; req.session.activeTab = 'spiel'; let spielId; const spiel = await pool.query(`SELECT * FROM spiele WHERE name = $1`, [spielName]); if (spiel.rows.length > 0) { spielId = spiel.rows[0].id; } else { const newSpiel = await pool.query('INSERT INTO spiele (name) VALUES ($1) RETURNING id', [spielName]); spielId = newSpiel.rows[0].id; req.session.message = [title = 'Neues Spiel', body = 'Das Spiel ${ spielName } wurde angelegt.', type = 'Success']; } try { if (type === 'spiel') { await pool.query('UPDATE trainings SET spiel = $1 WHERE id = $2', [spielId, trainingId]); } else if (type === 'aufwaermen') { await pool.query('UPDATE trainings SET aufwaermen = $1 WHERE id = $2', [spielId, trainingId]); } res.redirect('/training'); } catch (error) { console.error(error); const message = 'Error:' + error; res.render('error', { session: req.session, message }); } }); app.post('/update-leader', requireAuth, async (req, res) => { const { trainingId, type, leaderId } = req.body; req.session.activeTab = 'spiel'; try { if (type === 'aufwaermleiter') { await pool.query('UPDATE trainings SET aufwaermleiter = $1 WHERE id = $2', [leaderId, trainingId]); } else if (type === 'spielleiter') { await pool.query('UPDATE trainings SET spielleiter = $1 WHERE id = $2', [leaderId, trainingId]); } res.redirect('/training'); } catch (error) { console.error(error); const message = 'Error:' + error; res.render('error', { session: req.session, message }); } }); // Admin-Seite app.get('/admin', requireAuth, requireAdmin, async (req, res) => { const usersResult = await pool.query('SELECT * FROM users'); res.render('admin', { users: usersResult.rows, session: req.session }); // Stelle sicher, dass es eine admin.ejs gibt }); app.post('/new-member', requireAuth, requireAdmin, async (req, res) => { const { vorname, nachname, geburt, riege, adresse, probe} = req.body; var geb = "01.01.2024"; const name = vorname + ' ' + nachname; try { if(geburt){ geb = geburt; } const teilnehmerID = await pool.query('INSERT INTO teilnehmende (name, geburtsdatum, adresse, vorname, nachname, probe) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id', [name, geb, adresse, vorname, nachname, probe ? true : false]); log.Info("Mitglied " + name + " durch " + req.session.userName + " angelegt" ); putInRiege(riege, teilnehmerID.rows[0].id); res.redirect('/riege'); } catch (error) { const message = 'Error:' + error; res.render('error', { session: req.session, message }); } }) // Teilnehmer_innen app.get('/training', requireAuth, async (req, res) => { try { let dateParam = req.query.date; let kwParam = req.query.kw; let jahrParam = req.query.jahr; let selectedDate; let selectedKW; let selectetYear; if (kwParam) { selectedKW = kwParam; } else { selectedKW = moment().isoWeek(); } if (jahrParam) { selectedYear = jahrParam; } else { selectedYear = moment().year(); } const training = await getTraining(selectedKW); const anwesendResult = await pool.query('SELECT * FROM anwesend WHERE fid_training = $1', [training.id]); anwesend = anwesendResult.rows; const trainingsResult = await pool.query('SELECT kw, jahr FROM trainings ORDER BY kw ASC'); const trainingsDates = trainingsResult.rows.map(tr => ({ kw: tr.kw, datum: formatDate(getThursdayOfWeek(tr.kw, tr.jahr)) })); // Vorheriges Training ermitteln const previousTrainingResult = await pool.query('SELECT * FROM trainings WHERE kw < $1 ORDER BY kw DESC LIMIT 1', [selectedKW]); const nextTrainingResult = await pool.query('SELECT * FROM trainings WHERE kw > $1 ORDER BY kw ASC LIMIT 1', [selectedKW]); const previousTraining = previousTrainingResult.rows.length > 0 ? previousTrainingResult.rows[0] : null; const nextTraining = nextTrainingResult.rows.length > 0 ? nextTrainingResult.rows[0] : null; // Abrufen der Riegendaten einschließlich der Teilnehmer und deren Altersberechnung const result = await pool.query(` SELECT r.riegennummer, t.id, t.name, t.vorname, t.nachname, t.geburtsdatum, r.helfer FROM riegen r JOIN teilnehmende t ON r.fremdID_Teilnehmende = t.id ORDER BY r.riegennummer, t.geburtsdatum ASC `); // Gruppieren der Riegenteilnehmer nach Riegennummer const riegen = {}; result.rows.forEach(row => { const age = calculateAge(row.geburtsdatum); const tnAnwesend = getAnwesenheit(row.id, anwesend); if (!riegen[row.riegennummer]) { riegen[row.riegennummer] = []; } riegen[row.riegennummer].push({ id: row.id, name: row.name, vorname: row.vorname, nachname: row.nachname, age: age, helfer: row.helfer, anwesend: tnAnwesend }); }); if (training) { training.datum = getThursdayOfWeek(training.kw, training.jahr); } const aufwaermleiterCandidates = await getCandidatesForAufwaermleiter(); const spielleiterCandidates = await getCandidatesForSpielleiter(); const spielCandidates = await getAllSpiele(); const aufwaermenCandidates = await getAllSpiele(); res.render('trainings', { training, trainingsDates, selectedKW: training.kw, aufwaermleiterCandidates, spielleiterCandidates, aufwaermenCandidates, // Übergeben der Kandidaten für Aufwärmleiter spielCandidates, // Übergeben der Spiele session: req.session, previousTraining, nextTraining, riegen, activeRiege: req.session.activeRiege, activeTab: req.session.activeTab, moment }); } catch (error) { console.error(error); const message = 'Error:' + error; res.render('error', { session: req.session, message }); } }); app.get('/riege', requireAuth, async (req, res) => { try { // Abrufen der Riegendaten einschließlich der Teilnehmer und deren Altersberechnung const result = await pool.query(` SELECT r.riegennummer, t.id, t.name, t.vorname, t.nachname, t.geburtsdatum, r.helfer FROM riegen r JOIN teilnehmende t ON r.fremdID_Teilnehmende = t.id ORDER BY r.riegennummer, t.geburtsdatum ASC `); // Gruppieren der Riegenteilnehmer nach Riegennummer const riegen = {}; result.rows.forEach(row => { const age = calculateAge(row.geburtsdatum); if (!riegen[row.riegennummer]) { riegen[row.riegennummer] = []; } riegen[row.riegennummer].push({ id: row.id, name: row.name, vorname: row.vorname, nachname: row.nachname, age: age, helfer: row.helfer, }); }); res.render('riegen', { riegen: riegen, session: req.session }); } catch (error) { console.error('Error fetching riegen:', error); req.session.message = ['Error', error, 'error']; res.render('error', { session: req.session }); } }); app.get('/teilnehmer', requireAuth, requireAdmin, async (req, res) => { try { const teilnehmendeResult = await pool.query('SELECT * FROM teilnehmende ORDER BY helfer DESC, vorname ASC'); const teilnehmende = teilnehmendeResult.rows.map(t => ({ ...t, age: calculateAge(t.geburtsdatum) })); res.render('teilnehmer', { teilnehmende, session: req.session }); } catch (error) { console.error(error); req.session.message = ['Error', error, 'error']; res.render('error', { session: req.session }); } }); app.get('/mitglied/:id', requireAuth, requireAdmin, async (req, res) => { const { id } = req.params; try { var riege = 0; const userResult = await pool.query('SELECT * FROM teilnehmende WHERE id = $1', [id]); const riegeResult = await pool.query('SELECT * FROM riegen WHERE fremdid_teilnehmende = $1', [id]); if (riegeResult.rows.length > 0 ) { riege = riegeResult.rows[0].riegennummer; } req.session.activeRiege = riege; const anwesendResult = await pool.query('SELECT * FROM anwesend WHERE fid_teilnehmer = $1', [id]); const anwesend = anwesendResult.rows.length; const numberResult = await pool.query('SELECT telefonnummern.*, telverbindung.bezeichnung FROM telefonnummern JOIN telverbindung ON telefonnummern.verbindung = telverbindung.id WHERE telefonnummern.fid_teilnehmer = $1', [id]); const numbers = numberResult.rows if (userResult.rows.length > 0) { const mitglied = userResult.rows.map(t => ({ ...t, age: calculateAge(t.geburtsdatum) })) res.render('mitglied', { id, mitglied: mitglied[0], numbers, riege, anwesend, session: req.session }); } else { req.session.message = ['Error', 'Mitglied existiert nicht', 'error']; res.redirect('/teilnehmer') } } catch (error) { console.error('Error in Mitglied:', error); req.session.message = ['Error', 'Mitglied existiert nicht', 'error']; res.redirect('/teilnehmer'); } }); app.post('/set-riege', requireAuth, async (req, res) => { const { riege, id } = req.body; putInRiege(riege, id); res.redirect('/riege'); }) app.post('/update-mitglied', requireAdmin, async (req, res) => { const { type, id, geburt, telid, adresse, name, verbindung, nummer, probe } = req.body; try { if (type == "tel") { console.log('INSERT INTO telefonnummern (fid_teilnehmer, name, verbindung, nummer, stand) VALUES ($1, $2, $3, $4, $5)', [id, name, verbindung, nummer, moment().toDate()]); await pool.query('INSERT INTO telefonnummern (fid_teilnehmer, name, verbindung, nummer, stand) VALUES ($1, $2, $3, $4, $5)', [id, name, verbindung, nummer, moment().toDate()]); } else if (type == "tel-delete") { await pool.query('DELETE FROM telefonnummern WHERE id = $1', [telid]); console.log('delete numer $1', [telid]); } else if (type == "adresse") { await pool.query('UPDATE teilnehmende SET geburtsdatum = $1, adresse = $2, probe = $3 WHERE id = $4', [geburt, adresse, probe ? true : false, id]); } res.redirect('/mitglied/' + id); } catch (error) { console.error(error); req.session.message = ['Error', error, 'error']; res.redirect('/mitglied/' + id); } }); // Login und Registrierung anzeigen app.get('/login', (req, res) => { req.session.message = ['', '', 'none']; res.render('login', { session: req.session }); // Stelle sicher, dass es eine login.ejs gibt }); // Registrierung app.get('/register', (req, res) => { res.render('register', { session: req.session }); // Stelle sicher, dass es eine register.ejs gibt }); // Spieleliste app.get('/spiele', async (req, res) => { try { const spieleResult = await pool.query('SELECT * FROM spiele ORDER BY name ASC;'); const spiele = spieleResult.rows; res.render('spiele', { spiele, session: req.session }); } catch (error) { console.error('Error in Mitglied:', error); req.session.message = ['Error', error, 'error']; res.render('spiele', { spiele, session: req.session }); } }) app.post('/delete-spiel', requireAdmin, async (req, res) => { const { spielId } = req.body; console.log(spielId); await pool.query('DELETE FROM spiele WHERE id = $1', [spielId]); res.redirect('/spiele'); }) // Gerenderte Seite für gewähltes Spiel app.get('/spiel/:id', async (req, res) => { const { id } = req.params; try { const spieleResult = await pool.query('SELECT * FROM spiele WHERE id = $1', [id]); if (spieleResult.rows.length > 0) { const spiel = spieleResult.rows[0]; res.render('spiel', { spiel, session: req.session }); } else { req.session.message = ['Error', 'Spiel existiert nicht', 'error']; res.redirect('/spiele'); } } catch (error) { console.error('Error in Spiele:', error); req.session.message = ['Error', 'Spiel existiert nicht', 'error']; res.redirect('/spiele'); } }) // Postseite für Änderungen app.post('/edit-spiel', requireAuth, async (req, res) => { const { material, dauer, regeln, variationen, type, id } = req.body; try { const queryResult = await pool.query('UPDATE spiele set material = $1, regeln = $2, dauer = $3, variationen = $4, type = $5 Where id = $6 ', [material, regeln, dauer, variationen, type, id]); req.session.message = ['Erfolg', 'Das Spiel wurde gespeichert', 'success']; res.redirect('/spiel/' + id); } catch (error) { console.error('Error in edit Spiel:', error); req.session.message = ['Error', error, 'error']; res.redirect('/spiel/' + id); } }) // Startseite app.get('/', (req, res) => { req.session.message = ['', '', 'none'] res.render('index', { session: req.session }); }); // Changelog app.get('/changelog', async (req, res) => { try { const changeResult = await pool.query('SELECT * FROM changelog ORDER BY datetime DESC;'); const changes = changeResult.rows; req.session.message = ['Erfolg', 'Log gespeichert', 'success']; res.render('changelog', { changes, session: req.session }); } catch (error) { console.error('Error:', error); req.session.message = ['Error', error, 'error']; res.redirect('/changelog'); } }) app.post('/changelog', requireAdmin, async (req, res) => { const { title, body } = req.body; try { await pool.query('INSERT INTO changelog (title, body) VALUES ($1, $2);', [title, body]); const changeResult = await pool.query('SELECT * FROM changelog ORDER BY datetime DESC;'); const changes = changeResult.rows; res.render('changelog', { changes, session: req.session }); } catch (error) { console.error('Error:', error); req.session.message = ['Error', error, 'error']; res.render('changelog', { changes, session: req.session }); } }) app.post('/anwesend', requireAuth, async (req, res) => { const { anw, inriege , trainingId, riege } = req.body; req.session.activeTab = 'anwesend'; try { for (const mitgliedId of inriege){ const Idresult = await pool.query('SELECT *From anwesend WHERE fid_teilnehmer = $1 AND fid_training=$2', [mitgliedId, trainingId]) console.log(anw); console.log(inriege); if (Idresult.rows.length > 0) { if (!anw.includes(mitgliedId)){ await pool.query('Delete FROM anwesend WHERE fid_teilnehmer = $1 AND fid_training=$2', [mitgliedId, trainingId]) } } } for (const teilnehmer of anw) { const Tnresult = await pool.query('SELECT *From anwesend WHERE fid_teilnehmer = $1 AND fid_training=$2', [teilnehmer, trainingId]) if (Tnresult.rows.length === 0) { await pool.query('INSERT INTO anwesend (fid_teilnehmer, fid_training) VALUES ($1, $2)', [teilnehmer, trainingId]); } } req.session.activeRiege = riege; req.session.activeTab = 'anwesend'; req.session.message = [title = 'Erfolg', body = 'Die Anwesenheit wurde gespeichert', type = 'success']; res.redirect('/training'); } catch (error) { console.error('Error:', error); req.session.message = ['Error', error, 'error']; res.redirect('/training'); } }) const server = app.listen(port, '0.0.0.0', () => { log.Info(`Server is running on ${process.env.HOST}:${port}/`); });