training/app.js

871 lines
31 KiB
JavaScript
Raw Normal View History

2024-05-23 20:49:34 +02:00
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');
2024-05-26 18:25:15 +02:00
const moment = require('moment');
2024-05-23 20:49:34 +02:00
require('dotenv').config();
2024-05-31 22:21:44 +02:00
const log = require('node-file-logger');
2024-05-23 20:49:34 +02:00
const app = express();
2024-05-23 22:32:30 +02:00
const port = process.env.PORT;
2024-05-23 20:49:34 +02:00
2024-05-31 22:21:44 +02:00
const options = {
2024-06-17 21:31:08 +02:00
timeZone: 'europe/Berlin',
2024-05-31 22:21:44 +02:00
folderPath: './logs/',
dateBasedFileNaming: true,
fileNamePrefix: 'DailyLogs_',
2024-06-02 12:39:00 +02:00
fileNameExtension: '.log',
2024-05-31 22:21:44 +02:00
dateFormat: 'YYYY_MM_D',
2024-06-17 21:31:08 +02:00
timeFormat: 'H:mm:ss',
2024-05-31 22:21:44 +02:00
}
2024-06-02 12:39:00 +02:00
log.SetUserOptions(options);
2024-05-31 22:21:44 +02:00
2024-05-23 20:49:34 +02:00
// 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({
2024-05-23 21:58:22 +02:00
secret: process.env.SESSIONSECRET,
2024-05-23 20:49:34 +02:00
resave: false,
2024-06-02 01:35:38 +02:00
saveUninitialized: true,
cookie: { maxAge: 1000 * 60 * 60 * 24 * 2 }
2024-05-23 20:49:34 +02:00
}));
// 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({
2024-05-23 21:58:22 +02:00
host: process.env.MAILHOST,
2024-05-23 20:49:34 +02:00
port: 465,
secure: true,
auth: {
2024-05-23 21:58:22 +02:00
user: process.env.MAILUSER,
pass: process.env.MAILPASS
2024-05-23 20:49:34 +02:00
}
});
// 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) => {
2024-06-02 12:39:00 +02:00
const result = await pool.query(`
2024-05-23 20:49:34 +02:00
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
2024-05-23 20:49:34 +02:00
LIMIT 1
`, [kw]);
2024-05-23 20:49:34 +02:00
2024-06-02 12:39:00 +02:00
return result.rows[0];
2024-05-23 20:49:34 +02:00
};
// Funktion zum Laden aller Spiele
const getAllSpiele = async () => {
2024-06-02 12:39:00 +02:00
const result = await pool.query(`
2024-05-26 18:25:15 +02:00
SELECT * FROM spiele ORDER BY name ASC;
2024-05-23 20:49:34 +02:00
`);
2024-06-02 12:39:00 +02:00
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;
}
};
2024-05-23 20:49:34 +02:00
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;
}
2024-06-01 22:38:25 +02:00
// Funktion zum Laden der vier Leute, die am längsten nicht Aufwärmen oder Spiel geleitet haben
2024-05-23 20:49:34 +02:00
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
2024-05-26 11:17:50 +02:00
ORDER BY weeks_since_last DESC;
2024-05-23 20:49:34 +02:00
`);
return result.rows;
};
const putInRiege = async (riege, teilnehmerID) => {
try {
2024-06-25 21:06:21 +02:00
if (riege == 0) {
const resultRiege = await pool.query('DELETE FROM riegen WHERE fremdid_teilnehmende = $1;', [teilnehmerID]);
} else {
2024-05-27 22:14:35 +02:00
const resultRiege = await pool.query('SELECT * FROM riegen WHERE fremdid_teilnehmende = $1;', [teilnehmerID]);
if (resultRiege.rows.length > 0) {
2024-06-02 12:39:00 +02:00
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.");
2024-06-25 21:06:21 +02:00
}}
} catch (error) {
console.error('Error adding new spiel:', error);
throw error;
}
};
2024-05-23 20:49:34 +02:00
// 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
2024-05-26 11:17:50 +02:00
ORDER BY weeks_since_last DESC;
2024-05-23 20:49:34 +02:00
`);
return result.rows;
};
// Funktion zum Laden der Riegenteilnehmer absteigend nach Alter sortiert
const getRiegenMitgliederSortedByAge = async () => {
2024-06-02 12:39:00 +02:00
const result = await pool.query(`
2024-05-23 20:49:34 +02:00
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
`);
2024-06-02 12:39:00 +02:00
return result.rows;
};
2024-05-23 20:49:34 +02:00
2024-06-02 12:39:00 +02:00
const getAnwesenheit = function (id, anwesend) {
for (let item of anwesend) {
if (item.fid_teilnehmer === id) {
return true;
2024-05-31 18:42:27 +02:00
}
2024-06-02 12:39:00 +02:00
}
return false;
};
2024-05-31 18:42:27 +02:00
2024-05-23 20:49:34 +02:00
// Registrierung
app.post('/register', async (req, res) => {
2024-05-29 21:28:35 +02:00
const { username, email, password } = req.body;
2024-05-23 20:49:34 +02:00
try {
const hashedPassword = await bcrypt.hash(password, 10);
2024-05-29 21:28:35 +02:00
await pool.query('INSERT INTO users (username, email, password) VALUES ($1, $2, $3)', [username, email, hashedPassword]);
2024-05-29 20:58:49 +02:00
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;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
}
});
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
} catch (error) {
console.error('Error registering user:', error);
2024-05-29 20:55:02 +02:00
const message = 'Error registering user:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
// Login
app.post('/login', async (req, res) => {
const { username, password } = req.body;
2024-06-02 12:39:00 +02:00
2024-05-23 20:49:34 +02:00
try {
2024-06-02 12:39:00 +02:00
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]);
2024-05-23 20:49:34 +02:00
if (userResult.rows.length > 0) {
const user = userResult.rows[0];
const match = await bcrypt.compare(password, user.password);
if (match) {
2024-05-28 15:48:28 +02:00
if (user.is_active) {
req.session.userId = user.id;
2024-05-30 19:24:40 +02:00
req.session.userName = user.username;
req.session.activeRiege = 1;
req.session.activeTab = 'geraete';
2024-06-02 12:39:00 +02:00
req.session.message = [title = '', message = '', type = 'none'];
2024-05-31 22:21:44 +02:00
log.Info(username + ' ' + password);
2024-05-29 19:57:45 +02:00
if (user.admin_status === 'expired') {
2024-06-02 12:39:00 +02:00
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;
}
2024-05-28 16:19:59 +02:00
res.redirect('/training');
2024-06-02 12:39:00 +02:00
} else {
2024-05-28 15:48:28 +02:00
res.redirect('/freischaltung')
}
2024-05-23 20:49:34 +02:00
} else {
2024-05-29 20:55:02 +02:00
const message = 'Falscher Benutzername oder falsches Passwort';
2024-06-02 12:39:00 +02:00
res.render('login', { session: req.session, username, message });
2024-05-23 20:49:34 +02:00
}
} else {
2024-05-29 20:55:02 +02:00
const message = 'Falscher Benutzername oder falsches Passwort';
2024-06-02 12:39:00 +02:00
res.render('login', { session: req.session, username, message });
2024-05-23 20:49:34 +02:00
}
} catch (error) {
console.error('Error logging in:', error);
2024-05-29 20:55:02 +02:00
const message = 'Error logging in:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
2024-05-28 16:19:59 +02:00
//Wird angezeigt, wenn ein nicht freigeschalteter User sich anmelden will.
2024-05-28 15:48:28 +02:00
app.get('/freischaltung', async (req, res) => {
2024-06-02 12:39:00 +02:00
res.render('freischaltung', { session: req.session });
2024-05-28 15:48:28 +02:00
})
2024-05-23 20:49:34 +02:00
// Logout
2024-05-26 20:05:30 +02:00
app.get('/logout', (req, res) => {
2024-05-23 20:49:34 +02:00
req.session.destroy(err => {
if (err) {
return res.status(500).send('Internal Server Error');
}
2024-05-28 16:19:59 +02:00
res.redirect('/');
2024-05-23 20:49:34 +02:00
});
});
// Benutzer freischalten (nur Admin)
2024-05-29 19:57:45 +02:00
app.post('/userrights', requireAuth, requireAdmin, async (req, res) => {
const { userId, type } = req.body;
2024-05-23 20:49:34 +02:00
try {
2024-06-02 12:39:00 +02:00
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 });
}
})
}
}
2024-06-02 12:39:00 +02:00
} 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]);
}
2024-05-23 20:49:34 +02:00
res.redirect('/admin');
} catch (error) {
console.error('Error activating user:', error);
2024-05-29 20:55:02 +02:00
const message = 'Error activating user:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
// Passwort-Zurücksetzung anfordern
2024-05-26 20:05:30 +02:00
app.post('/send-password', async (req, res) => {
2024-05-23 20:49:34 +02:00
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}`;
2024-06-02 12:39:00 +02:00
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]);
2024-05-23 20:49:34 +02:00
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);
2024-05-29 20:55:02 +02:00
const message = 'Error sending Mail:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
} else {
2024-05-29 20:55:02 +02:00
const message = 'Password reset link sent';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
} else {
2024-05-29 20:55:02 +02:00
const message = 'Email not found';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
} catch (error) {
console.error('Error in forgot-password:', error);
2024-05-29 20:55:02 +02:00
const message = 'Error in forgot-password';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
app.get('/forgot-password', async (req, res) => {
2024-06-02 12:39:00 +02:00
res.render('forgot-password', { session: req.session })
2024-05-23 20:49:34 +02:00
})
// Passwort zurücksetzen
app.get('/reset-password/:token', async (req, res) => {
const { token } = req.params;
try {
2024-06-17 18:55:38 +02:00
// 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]);
2024-05-23 20:49:34 +02:00
if (userResult.rows.length > 0) {
2024-06-17 18:55:38 +02:00
res.render('reset-password', { session: req.session, token }); // Stelle sicher, dass es eine reset-password.ejs gibt
2024-05-23 20:49:34 +02:00
} else {
2024-05-29 20:55:02 +02:00
const message = 'Token ungültig oder abgelaufen';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
} catch (error) {
console.error('Error in reset-password:', error);
2024-05-29 20:55:02 +02:00
const message = 'Error in reset-password';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
app.post('/reset-password/:token', async (req, res) => {
const { token } = req.params;
const { password } = req.body;
try {
2024-06-17 18:55:38 +02:00
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]);
2024-05-23 20:49:34 +02:00
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 {
2024-05-29 20:55:02 +02:00
const message = 'Token ungültig oder abgelaufen';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
} catch (error) {
console.error('Error in reset-password:', error);
2024-05-29 20:55:02 +02:00
const message = 'Error in reset-password';
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
// Profilseite
app.get('/profile', requireAuth, (req, res) => {
2024-06-02 12:39:00 +02:00
res.render('profile', { session: req.session }); // Stelle sicher, dass es eine profile.ejs gibt
2024-05-23 20:49:34 +02:00
});
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);
2024-05-29 20:55:02 +02:00
const message = 'Error updating profile:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
2024-05-28 16:19:59 +02:00
app.post('/update-training', requireAuth, async (req, res) => {
2024-05-26 18:25:15 +02:00
const { trainingId, type, spielName } = req.body;
req.session.activeTab = 'spiel';
2024-05-26 18:25:15 +02:00
let spielId;
2024-05-23 21:58:22 +02:00
2024-05-26 18:25:15 +02:00
const spiel = await pool.query(`SELECT * FROM spiele WHERE name = $1`, [spielName]);
2024-06-02 12:39:00 +02:00
2024-05-26 18:25:15 +02:00
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;
2024-06-01 22:38:25 +02:00
req.session.message = [title = 'Neues Spiel', body = 'Das Spiel ${ spielName } wurde angelegt.', type = 'Success'];
2024-06-02 12:39:00 +02:00
}
2024-05-23 21:58:22 +02:00
try {
if (type === 'spiel') {
2024-06-02 12:39:00 +02:00
await pool.query('UPDATE trainings SET spiel = $1 WHERE id = $2', [spielId, trainingId]);
2024-05-23 21:58:22 +02:00
} else if (type === 'aufwaermen') {
2024-06-02 12:39:00 +02:00
await pool.query('UPDATE trainings SET aufwaermen = $1 WHERE id = $2', [spielId, trainingId]);
2024-05-23 21:58:22 +02:00
}
2024-06-02 12:39:00 +02:00
2024-05-29 20:07:59 +02:00
res.redirect('/training');
2024-05-29 20:55:02 +02:00
} catch (error) {
console.error(error);
const message = 'Error:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 21:58:22 +02:00
}
});
2024-06-02 12:39:00 +02:00
app.post('/update-leader', requireAuth, async (req, res) => {
2024-05-23 20:49:34 +02:00
const { trainingId, type, leaderId } = req.body;
2024-06-02 12:39:00 +02:00
req.session.activeTab = 'spiel';
2024-05-23 20:49:34 +02:00
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]);
}
2024-05-29 20:07:59 +02:00
res.redirect('/training');
2024-05-29 20:55:02 +02:00
} catch (error) {
console.error(error);
const message = 'Error:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
// Admin-Seite
app.get('/admin', requireAuth, requireAdmin, async (req, res) => {
2024-05-29 19:57:45 +02:00
const usersResult = await pool.query('SELECT * FROM users');
2024-05-23 20:49:34 +02:00
res.render('admin', { users: usersResult.rows, session: req.session }); // Stelle sicher, dass es eine admin.ejs gibt
});
2024-06-02 12:39:00 +02:00
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;
2024-06-02 12:39:00 +02:00
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" );
2024-06-02 12:39:00 +02:00
putInRiege(riege, teilnehmerID.rows[0].id);
res.redirect('/riege');
} catch (error) {
const message = 'Error:' + error;
res.render('error', { session: req.session, message });
}
})
2024-05-23 20:49:34 +02:00
// Teilnehmer_innen
2024-05-28 16:19:59 +02:00
app.get('/training', requireAuth, async (req, res) => {
2024-05-23 20:49:34 +02:00
try {
2024-05-26 18:25:15 +02:00
let dateParam = req.query.date;
2024-06-01 22:38:25 +02:00
let kwParam = req.query.kw;
let jahrParam = req.query.jahr;
2024-05-26 18:25:15 +02:00
let selectedDate;
2024-06-01 22:38:25 +02:00
let selectedKW;
let selectetYear;
2024-06-02 12:39:00 +02:00
2024-05-26 18:25:15 +02:00
if (kwParam) {
selectedKW = kwParam;
} else {
selectedKW = moment().isoWeek();
}
2024-05-26 18:25:15 +02:00
2024-06-01 22:38:25 +02:00
if (jahrParam) {
selectedYear = jahrParam;
2024-06-01 22:38:25 +02:00
} else {
selectedYear = moment().year();
2024-06-01 22:38:25 +02:00
}
2024-05-23 20:49:34 +02:00
const training = await getTraining(selectedKW);
2024-06-02 12:39:00 +02:00
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');
2024-05-23 20:49:34 +02:00
const trainingsDates = trainingsResult.rows.map(tr => ({
kw: tr.kw,
datum: formatDate(getThursdayOfWeek(tr.kw, tr.jahr))
2024-05-23 20:49:34 +02:00
}));
2024-05-26 18:25:15 +02:00
// 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]);
2024-05-26 18:25:15 +02:00
const previousTraining = previousTrainingResult.rows.length > 0 ? previousTrainingResult.rows[0] : null;
const nextTraining = nextTrainingResult.rows.length > 0 ? nextTrainingResult.rows[0] : null;
2024-06-02 12:39:00 +02:00
// Abrufen der Riegendaten einschließlich der Teilnehmer und deren Altersberechnung
const result = await pool.query(`
2024-05-31 18:42:27 +02:00
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
`);
2024-06-02 12:39:00 +02:00
// 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
2024-05-31 18:42:27 +02:00
});
2024-06-02 12:39:00 +02:00
});
2024-05-31 18:42:27 +02:00
2024-05-23 20:49:34 +02:00
if (training) {
training.datum = getThursdayOfWeek(training.kw, training.jahr);
2024-05-23 20:49:34 +02:00
}
const aufwaermleiterCandidates = await getCandidatesForAufwaermleiter();
const spielleiterCandidates = await getCandidatesForSpielleiter();
const spielCandidates = await getAllSpiele();
const aufwaermenCandidates = await getAllSpiele();
res.render('trainings', {
training,
trainingsDates,
selectedKW: training.kw,
2024-05-23 20:49:34 +02:00
aufwaermleiterCandidates,
spielleiterCandidates,
aufwaermenCandidates, // Übergeben der Kandidaten für Aufwärmleiter
spielCandidates, // Übergeben der Spiele
2024-06-02 12:39:00 +02:00
session: req.session,
previousTraining,
2024-05-26 18:25:15 +02:00
nextTraining,
2024-05-31 18:42:27 +02:00
riegen,
activeRiege: req.session.activeRiege,
activeTab: req.session.activeTab,
2024-06-02 12:39:00 +02:00
moment
2024-05-23 20:49:34 +02:00
});
2024-05-29 20:55:02 +02:00
} catch (error) {
console.error(error);
const message = 'Error:' + error;
2024-06-02 12:39:00 +02:00
res.render('error', { session: req.session, message });
2024-05-23 20:49:34 +02:00
}
});
app.get('/riege', requireAuth, async (req, res) => {
try {
// Abrufen der Riegendaten einschließlich der Teilnehmer und deren Altersberechnung
const result = await pool.query(`
2024-05-29 20:55:02 +02:00
SELECT r.riegennummer, t.id, t.name, t.vorname, t.nachname, t.geburtsdatum, r.helfer
2024-05-23 20:49:34 +02:00
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,
2024-05-29 20:55:02 +02:00
vorname: row.vorname,
nachname: row.nachname,
2024-05-23 20:49:34 +02:00
age: age,
helfer: row.helfer,
});
});
res.render('riegen', { riegen: riegen, session: req.session });
} catch (error) {
console.error('Error fetching riegen:', error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', error, 'error'];
res.render('error', { session: req.session });
2024-05-23 20:49:34 +02:00
}
});
app.get('/teilnehmer', requireAuth, async (req, res) => {
try {
2024-06-25 20:46:20 +02:00
const teilnehmendeResult = await pool.query('SELECT * FROM teilnehmende ORDER BY helfer DESC, vorname ASC');
2024-05-23 20:49:34 +02:00
const teilnehmende = teilnehmendeResult.rows.map(t => ({
...t,
age: calculateAge(t.geburtsdatum)
2024-06-25 20:46:20 +02:00
}));
2024-05-23 20:49:34 +02:00
res.render('teilnehmer', { teilnehmende, session: req.session });
2024-05-29 20:55:02 +02:00
} catch (error) {
console.error(error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', error, 'error'];
res.render('error', { session: req.session });
2024-05-23 20:49:34 +02:00
}
});
app.get('/mitglied/:id', requireAuth, async (req, res) => {
const { id } = req.params;
try {
2024-06-25 21:06:21 +02:00
var riege = 0;
2024-05-23 20:49:34 +02:00
const userResult = await pool.query('SELECT * FROM teilnehmende WHERE id = $1', [id]);
2024-05-27 22:14:35 +02:00
const riegeResult = await pool.query('SELECT * FROM riegen WHERE fremdid_teilnehmende = $1', [id]);
2024-06-25 21:06:21 +02:00
if (riegeResult.rows.length > 0 ) {
riege = riegeResult.rows[0].riegennummer;
}
req.session.activeRiege = riege;
2024-05-31 21:45:21 +02:00
const anwesendResult = await pool.query('SELECT * FROM anwesend WHERE fid_teilnehmer = $1', [id]);
const anwesend = anwesendResult.rows.length;
2024-05-27 22:14:35 +02:00
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
2024-05-23 20:49:34 +02:00
if (userResult.rows.length > 0) {
const mitglied = userResult.rows.map(t => ({
...t,
age: calculateAge(t.geburtsdatum)
}))
2024-06-02 12:39:00 +02:00
res.render('mitglied', {
2024-05-23 20:49:34 +02:00
id,
2024-06-02 12:39:00 +02:00
mitglied: mitglied[0],
numbers,
riege,
anwesend,
session: req.session
2024-05-23 20:49:34 +02:00
});
} else {
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', 'Mitglied existiert nicht', 'error'];
res.redirect('/teilnehmer')
2024-05-23 20:49:34 +02:00
}
} catch (error) {
console.error('Error in Mitglied:', error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', 'Mitglied existiert nicht', 'error'];
res.redirect('/teilnehmer');
2024-05-23 20:49:34 +02:00
}
});
app.post('/set-riege', requireAuth, async (req, res) => {
const { riege, id } = req.body;
putInRiege(riege, id);
res.redirect('/riege');
})
2024-05-28 16:19:59 +02:00
app.post('/update-mitglied', requireAdmin, async (req, res) => {
const { type, id, geburt, telid, adresse, name, verbindung, nummer, probe } = req.body;
2024-06-02 12:39:00 +02:00
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") {
2024-05-27 22:14:35 +02:00
await pool.query('DELETE FROM telefonnummern WHERE id = $1', [telid]);
console.log('delete numer $1', [telid]);
2024-06-02 12:39:00 +02:00
} 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]);
2024-05-27 22:14:35 +02:00
}
2024-06-02 12:39:00 +02:00
2024-05-27 22:14:35 +02:00
res.redirect('/mitglied/' + id);
2024-05-29 20:55:02 +02:00
} catch (error) {
console.error(error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', error, 'error'];
res.redirect('/mitglied/' + id);
}
});
2024-05-23 20:49:34 +02:00
// Login und Registrierung anzeigen
app.get('/login', (req, res) => {
2024-06-02 12:39:00 +02:00
req.session.message = ['', '', 'none'];
res.render('login', { session: req.session }); // Stelle sicher, dass es eine login.ejs gibt
2024-05-23 20:49:34 +02:00
});
2024-05-28 16:19:59 +02:00
// Registrierung
2024-05-23 20:49:34 +02:00
app.get('/register', (req, res) => {
2024-06-02 12:39:00 +02:00
res.render('register', { session: req.session }); // Stelle sicher, dass es eine register.ejs gibt
2024-05-23 20:49:34 +02:00
});
2024-05-28 16:19:59 +02:00
// Spieleliste
2024-05-28 00:17:57 +02:00
app.get('/spiele', async (req, res) => {
try {
2024-05-30 18:16:36 +02:00
const spieleResult = await pool.query('SELECT * FROM spiele ORDER BY name ASC;');
2024-05-28 00:17:57 +02:00
const spiele = spieleResult.rows;
res.render('spiele', { spiele, session: req.session });
} catch (error) {
console.error('Error in Mitglied:', error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', error, 'error'];
res.render('spiele', { spiele, session: req.session });
2024-05-28 00:17:57 +02:00
}
})
2024-06-02 12:39:00 +02:00
app.post('/delete-spiel', requireAdmin, async (req, res) => {
2024-05-30 18:29:14 +02:00
const { spielId } = req.body;
console.log(spielId);
await pool.query('DELETE FROM spiele WHERE id = $1', [spielId]);
res.redirect('/spiele');
})
2024-05-28 16:19:59 +02:00
// Gerenderte Seite für gewähltes Spiel
2024-05-28 00:17:57 +02:00
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) {
2024-06-02 12:39:00 +02:00
const spiel = spieleResult.rows[0];
res.render('spiel', { spiel, session: req.session });
} else {
req.session.message = ['Error', 'Spiel existiert nicht', 'error'];
2024-06-02 12:39:00 +02:00
res.redirect('/spiele');
}
2024-05-28 00:17:57 +02:00
} catch (error) {
console.error('Error in Spiele:', error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', 'Spiel existiert nicht', 'error'];
res.redirect('/spiele');
2024-05-28 00:17:57 +02:00
}
})
2024-05-28 16:19:59 +02:00
// Postseite für Änderungen
2024-05-28 00:17:57 +02:00
app.post('/edit-spiel', requireAuth, async (req, res) => {
2024-06-02 12:39:00 +02:00
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);
}
2024-05-28 00:17:57 +02:00
})
2024-05-28 16:19:59 +02:00
// Startseite
app.get('/', (req, res) => {
req.session.message = ['', '', 'none']
2024-06-02 12:39:00 +02:00
res.render('index', { session: req.session });
2024-05-28 16:19:59 +02:00
});
2024-05-30 19:24:40 +02:00
// Changelog
app.get('/changelog', async (req, res) => {
try {
const changeResult = await pool.query('SELECT * FROM changelog ORDER BY datetime DESC;');
const changes = changeResult.rows;
2024-06-02 12:39:00 +02:00
req.session.message = ['Erfolg', 'Log gespeichert', 'success'];
2024-05-30 19:24:40 +02:00
res.render('changelog', { changes, session: req.session });
} catch (error) {
console.error('Error:', error);
2024-06-02 12:39:00 +02:00
req.session.message = ['Error', error, 'error'];
res.redirect('/changelog');
2024-05-30 19:24:40 +02:00
}
})
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]);
2024-06-02 12:39:00 +02:00
2024-05-30 19:24:40 +02:00
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) {
2024-06-02 12:39:00 +02:00
console.error('Error:', error);
req.session.message = ['Error', error, 'error'];
res.render('changelog', { changes, session: req.session });
}
2024-06-06 22:17:19 +02:00
})
2024-05-30 19:24:40 +02:00
2024-05-31 18:42:27 +02:00
app.post('/anwesend', requireAuth, async (req, res) => {
2024-06-11 17:25:32 +02:00
const { anw, inriege , trainingId, riege } = req.body;
2024-06-02 12:39:00 +02:00
req.session.activeTab = 'anwesend';
try {
2024-06-11 17:25:32 +02:00
for (const mitgliedId of inriege){
const Idresult = await pool.query('SELECT *From anwesend WHERE fid_teilnehmer = $1 AND fid_training=$2', [mitgliedId, trainingId])
2024-06-17 19:20:03 +02:00
console.log(anw);
console.log(inriege);
2024-06-11 17:25:32 +02:00
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])
}
}
}
2024-06-02 12:39:00 +02:00
for (const teilnehmer of anw) {
2024-06-11 17:25:32 +02:00
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]);
2024-06-02 12:39:00 +02:00
}
2024-06-11 17:25:32 +02:00
}
2024-06-02 12:39:00 +02:00
req.session.activeRiege = riege;
2024-06-05 12:39:30 +02:00
req.session.activeTab = 'anwesend';
req.session.message = [title = 'Erfolg', body = 'Die Anwesenheit wurde gespeichert', type = 'success'];
2024-06-02 12:39:00 +02:00
res.redirect('/training');
} catch (error) {
console.error('Error:', error);
req.session.message = ['Error', error, 'error'];
res.redirect('/training');
}
})
2024-05-31 18:42:27 +02:00
2024-05-23 20:49:34 +02:00
const server = app.listen(port, '0.0.0.0', () => {
2024-06-02 12:39:00 +02:00
log.Info(`Server is running on ${process.env.HOST}:${port}/`);
});