838 lines
29 KiB
JavaScript
838 lines
29 KiB
JavaScript
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 fs = require('fs');
|
|
const log = require('node-file-logger');
|
|
|
|
const outputLog = fs.createWriteStream('./outputLog.log');
|
|
const errorsLog = fs.createWriteStream('./errorsLog.log');
|
|
const consoler = new console.Console(outputLog, errorsLog);
|
|
|
|
const app = express();
|
|
const port = process.env.PORT;
|
|
|
|
const options = {
|
|
folderPath: './logs/',
|
|
dateBasedFileNaming: true,
|
|
fileNamePrefix: 'DailyLogs_',
|
|
fileNameExtension: '.log',
|
|
dateFormat: 'YYYY_MM_D',
|
|
timeFormat: 'h:mm:ss A',
|
|
}
|
|
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: false,
|
|
cookie: { maxAge: 1800000 }
|
|
}));
|
|
|
|
// 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 (selectedDate) => {
|
|
const today = selectedDate ? new Date(selectedDate) : new Date();
|
|
const dayOfWeek = today.getDay();
|
|
|
|
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.datum <= $1
|
|
ORDER BY tr.datum DESC
|
|
LIMIT 1
|
|
`, [today]);
|
|
|
|
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;
|
|
}
|
|
};
|
|
|
|
// Funktion zum Laden der vier Leute, die am längsten nicht Aufwärmen bzw. Spiel geleitet haben
|
|
// Funktion zum Laden der vier Leute, die am längsten nicht Aufwärmen 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 {
|
|
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]);
|
|
console.log("Mitglied ist jetzt in Riege $1", [riege]);
|
|
} else {
|
|
const resultRiege = await pool.query('INSERT INTO riegen (fremdid_teilnehmende, riegennummer) VALUES ($1, $2)', [teilnehmerID, riege]);
|
|
console.log("Mitglied neu in Riege $1 eingefügt.", [riege]);
|
|
}
|
|
} 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(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 = 'Falscher Benutzername oder falsches Passwort';
|
|
res.render('login', {session: req.session, username, message});
|
|
}
|
|
} else {
|
|
const message = 'Falscher Benutzername oder falsches Passwort';
|
|
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()]);
|
|
if (userResult.rows.length > 0) {
|
|
res.render('reset-password', { 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 * FROM users WHERE reset_password_token = $1 AND reset_password_expires > $2', [token, Date.now()]);
|
|
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;
|
|
console.log('Spiel existiert, die ID ist $1', [ spielId ]);
|
|
} else {
|
|
const newSpiel = await pool.query('INSERT INTO spiele (name) VALUES ($1) RETURNING id', [spielName]);
|
|
spielId = newSpiel.rows[0].id;
|
|
console.log('Spiel existiert nicht, wurde mitID $1 angelegt', [ spielId ]);
|
|
}
|
|
|
|
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 ]);
|
|
}
|
|
req.session.message = [title = '', body = '', type = 'none'];
|
|
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} = req.body;
|
|
const name = vorname + ' ' + nachname;
|
|
console.log(name + ', ' + geburt + ', ' + riege + ', ' + adresse);
|
|
try {
|
|
const teilnehmerID = await pool.query('INSERT INTO teilnehmende (name, geburtsdatum, adresse, vorname, nachname) VALUES ($1, $2, $3, $4, $5) RETURNING id', [name, geburt, adresse, vorname, nachname]);
|
|
console.log(teilnehmerID.rows[0].id);
|
|
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 selectedDate;
|
|
|
|
|
|
if (dateParam) {
|
|
selectedDate = moment(dateParam, 'DD.MM.YYYY').toDate();
|
|
} else {
|
|
selectedDate = moment().toDate();
|
|
}
|
|
|
|
const training =await getTraining(selectedDate);
|
|
|
|
const trainingsResult = await pool.query('SELECT datum FROM trainings ORDER BY datum ASC');
|
|
const anwesendResult = await pool.query('SELECT * FROM anwesend WHERE fid_training = $1',[ training.id ]);
|
|
anwesend=anwesendResult.rows;
|
|
const trainingsDates = trainingsResult.rows.map(tr => ({
|
|
datum: formatDate(tr.datum),
|
|
rawDatum: tr.datum
|
|
}));
|
|
|
|
// Vorheriges Training ermitteln
|
|
const previousTrainingResult = await pool.query('SELECT * FROM trainings WHERE datum < $1 ORDER BY datum DESC LIMIT 1',[ selectedDate ]);
|
|
const nextTrainingResult = await pool.query('SELECT * FROM trainings WHERE datum > $1 ORDER BY datum ASC LIMIT 1',[ selectedDate ]);
|
|
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 = formatDate(training.datum);
|
|
}
|
|
|
|
const aufwaermleiterCandidates = await getCandidatesForAufwaermleiter();
|
|
const spielleiterCandidates = await getCandidatesForSpielleiter();
|
|
const spielCandidates = await getAllSpiele();
|
|
const aufwaermenCandidates = await getAllSpiele();
|
|
|
|
res.render('trainings', {
|
|
training,
|
|
trainingsDates,
|
|
selectedDate: training.datum,
|
|
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, async (req, res) => {
|
|
try {
|
|
const teilnehmendeResult = await pool.query('SELECT * FROM teilnehmende');
|
|
|
|
const teilnehmende = teilnehmendeResult.rows.map(t => ({
|
|
...t,
|
|
age: calculateAge(t.geburtsdatum)
|
|
})).sort((a, b) => b.age - a.age);
|
|
|
|
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, async (req, res) => {
|
|
const { id } = req.params;
|
|
try {
|
|
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]);
|
|
const 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, telid, adresse, name, verbindung, nummer } = 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 adresse = $1 WHERE id = $2', [adresse, 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, trainingId, riege } = req.body;
|
|
req.session.activeTab = 'anwesend';
|
|
req.session.message = [title = 'Erfolg', body = 'Die Anwesenheit wurde gespeichert', type = 'success'];
|
|
try {
|
|
for (const teilnehmer of anw) {
|
|
const resultAnw = await pool.query('Select * FROM anwesend WHERE fid_teilnehmer = $1 AND fid_training = $2', [teilnehmer, trainingId]);
|
|
if (resultAnw.rows.length == 0) {
|
|
await pool.query('INSERT INTO anwesend (fid_teilnehmer, fid_training) VALUES ($1, $2)', [teilnehmer, trainingId]);
|
|
}}
|
|
req.session.activeRiege = riege;
|
|
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}/`);
|
|
});
|
|
|
|
|
|
|