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 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 ) ;
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 = {
folderPath : './logs/' ,
dateBasedFileNaming : true ,
fileNamePrefix : 'DailyLogs_' ,
fileNameExtension : '.log' ,
dateFormat : 'YYYY_MM_D' ,
timeFormat : 'h:mm:ss A' ,
}
log . SetUserOptions ( options ) ;
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 ,
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 ( {
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 ( 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 ( `
2024-05-26 18:25:15 +02:00
SELECT * FROM spiele ORDER BY name ASC ;
2024-05-23 20:49:34 +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 ;
}
} ;
// 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
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 ;
} ;
2024-05-27 20:37:35 +02:00
const putInRiege = async ( riege , teilnehmerID ) => {
try {
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-05-27 20:37:35 +02:00
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 ] ) ;
2024-05-27 22:14:35 +02:00
console . log ( "Mitglied neu in Riege $1 eingefügt." , [ riege ] ) ;
2024-05-27 20:37:35 +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 ( ) => {
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 ;
} ;
2024-05-31 18:42:27 +02:00
const getAnwesenheit = function ( id , anwesend ) {
for ( let item of anwesend ) {
if ( item . fid _teilnehmer === id ) {
return true ;
}
}
return false ;
} ;
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' ;
2024-05-29 21:25:27 +02:00
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 } ) ;
}
} ) ;
2024-05-29 20:58:49 +02:00
res . render ( 'error' , { session : req . session , message } ) ;
2024-05-29 21:25:27 +02:00
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 ;
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-05-31 22:21:44 +02:00
2024-05-23 20:49:34 +02:00
try {
2024-05-29 20:04:50 +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 ;
2024-05-31 21:29:18 +02:00
req . session . activeRiege = 1 ;
req . session . activeTab = 'geraete' ;
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-05-29 20:04:50 +02:00
await pool . query ( 'UPDATE users SET role = $1, admin_temp = NULL WHERE id = $2' , [ 'user' , user . id ] ) ;
2024-05-29 19:57:45 +02:00
req . session . role = 'user' ;
} else {
req . session . role = user . role ;
}
2024-05-28 16:19:59 +02:00
res . redirect ( '/training' ) ;
2024-05-28 15:48:28 +02:00
} else {
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' ;
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' ;
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 ;
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 ) => {
res . render ( 'freischaltung' , { session : req . session } ) ;
} )
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-05-29 19:57:45 +02:00
if ( type === 'activate' ) {
2024-05-23 20:49:34 +02:00
await pool . query ( 'UPDATE users SET is_active = TRUE WHERE id = $1' , [ userId ] ) ;
2024-05-29 21:25:27 +02:00
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-05-29 19:57:45 +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 ] ) ;
2024-05-29 21:06:42 +02:00
} else if ( type === 'delete' ) {
await pool . query ( 'DELETE FROM users WHERE id = $1' , [ userId ] ) ;
2024-05-29 19:57:45 +02:00
}
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 ;
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-05-26 20:05:30 +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 ;
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' ;
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' ;
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' ;
res . render ( 'error' , { session : req . session , message } ) ;
2024-05-23 20:49:34 +02:00
}
} ) ;
app . get ( '/forgot-password' , async ( req , res ) => {
2024-05-26 20:05:30 +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 {
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 {
2024-05-29 20:55:02 +02:00
const message = 'Token ungültig oder abgelaufen' ;
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' ;
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 {
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 {
2024-05-29 20:55:02 +02:00
const message = 'Token ungültig oder abgelaufen' ;
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' ;
res . render ( 'error' , { session : req . session , message } ) ;
2024-05-23 20:49:34 +02:00
}
} ) ;
// 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 ) ;
2024-05-29 20:55:02 +02:00
const message = 'Error updating profile:' + error ;
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 ;
2024-05-31 21:29:18 +02:00
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 ] ) ;
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 ] ) ;
}
2024-05-23 21:58:22 +02:00
try {
if ( type === 'spiel' ) {
2024-05-26 18:25:15 +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-05-26 18:25:15 +02:00
await pool . query ( 'UPDATE trainings SET aufwaermen = $1 WHERE id = $2' , [ spielId , trainingId ] ) ;
2024-05-23 21:58:22 +02:00
}
2024-05-31 21:29:18 +02:00
req . session . message = [ title = '' , body = '' , type = 'none' ] ;
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 ;
res . render ( 'error' , { session : req . session , message } ) ;
2024-05-23 21:58:22 +02:00
}
} ) ;
2024-05-28 16:19:59 +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-05-31 21:29:18 +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 ;
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-05-27 20:37:35 +02:00
app . post ( '/new-member' , requireAuth , requireAdmin , async ( req , res ) => {
2024-05-30 17:43:11 +02:00
const { vorname , nachname , geburt , riege , adresse } = req . body ;
const name = vorname + ' ' + nachname ;
console . log ( name + ', ' + geburt + ', ' + riege + ', ' + adresse ) ;
2024-05-27 20:37:35 +02:00
try {
2024-05-30 17:43:11 +02:00
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 ) ;
2024-05-27 20:37:35 +02:00
res . redirect ( '/riege' ) ;
2024-05-29 20:55:02 +02:00
} catch ( error ) {
const message = 'Error:' + error ;
res . render ( 'error' , { session : req . session , message } ) ;
2024-05-27 20:37:35 +02:00
}
} )
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 ;
let selectedDate ;
if ( dateParam ) {
selectedDate = moment ( dateParam , 'DD.MM.YYYY' ) . toDate ( ) ;
} else {
selectedDate = moment ( ) . toDate ( ) ;
}
const training = await getTraining ( selectedDate ) ;
2024-05-23 20:49:34 +02:00
const trainingsResult = await pool . query ( 'SELECT datum FROM trainings ORDER BY datum ASC' ) ;
2024-05-31 18:42:27 +02:00
const anwesendResult = await pool . query ( 'SELECT * FROM anwesend WHERE fid_training = $1' , [ training . id ] ) ;
anwesend = anwesendResult . rows ;
2024-05-23 20:49:34 +02:00
const trainingsDates = trainingsResult . rows . map ( tr => ( {
datum : formatDate ( tr . datum ) ,
rawDatum : tr . datum
} ) ) ;
2024-05-26 18:25:15 +02:00
// 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 ;
2024-05-31 18:42:27 +02:00
// 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
} ) ;
} ) ;
2024-05-23 20:49:34 +02:00
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
2024-05-26 18:25:15 +02:00
session : req . session ,
previousTraining ,
nextTraining ,
2024-05-31 18:42:27 +02:00
riegen ,
2024-05-31 21:29:18 +02:00
activeRiege : req . session . activeRiege ,
activeTab : req . session . activeTab ,
2024-05-26 18:25:15 +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 ;
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-05-31 21:29:18 +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 {
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 } ) ;
2024-05-29 20:55:02 +02:00
} catch ( error ) {
console . error ( error ) ;
2024-05-31 21:29:18 +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 {
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 ] ) ;
const riege = riegeResult . rows [ 0 ] . riegennummer ;
2024-05-31 21:29:18 +02:00
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 ] ) ;
2024-05-27 20:37:35 +02:00
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 )
} ) )
res . render ( 'mitglied' , {
id ,
mitglied : mitglied [ 0 ] ,
2024-05-27 20:37:35 +02:00
numbers ,
2024-05-27 22:14:35 +02:00
riege ,
2024-05-31 21:45:21 +02:00
anwesend ,
2024-05-23 20:49:34 +02:00
session : req . session
} ) ;
} else {
2024-05-31 21:29:18 +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-05-31 21:29:18 +02:00
req . session . message = [ 'Error' , 'Mitglied existiert nicht' , 'error' ] ;
res . redirect ( '/teilnehmer' ) ;
2024-05-23 20:49:34 +02:00
}
} ) ;
2024-05-27 20:37:35 +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 ) => {
2024-05-27 22:14:35 +02:00
const { type , id , telid , adresse , name , verbindung , nummer } = req . body ;
2024-05-27 20:37:35 +02:00
try {
2024-05-27 22:14:35 +02:00
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 ) ;
2024-05-29 20:55:02 +02:00
} catch ( error ) {
console . error ( error ) ;
2024-05-31 21:29:18 +02:00
req . session . message = [ 'Error' , error , 'error' ] ;
res . redirect ( '/mitglied/' + id ) ;
2024-05-27 20:37:35 +02:00
}
} ) ;
2024-05-23 20:49:34 +02:00
// Login und Registrierung anzeigen
app . get ( '/login' , ( req , res ) => {
2024-05-31 21:29:18 +02:00
req . session . message = [ '' , '' , 'none' ] ;
2024-05-23 20:49:34 +02:00
res . render ( 'login' , { session : req . session } ) ; // Stelle sicher, dass es eine login.ejs gibt
} ) ;
2024-05-28 16:19:59 +02:00
// Registrierung
2024-05-23 20:49:34 +02:00
app . get ( '/register' , ( req , res ) => {
2024-05-28 15:33:59 +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-05-31 21:29:18 +02:00
req . session . message = [ 'Error' , error , 'error' ] ;
res . render ( 'spiele' , { spiele , session : req . session } ) ;
2024-05-28 00:17:57 +02:00
}
} )
2024-05-30 18:29:14 +02:00
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' ) ;
} )
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 ] ) ;
2024-05-31 21:29:18 +02:00
if ( spieleResult . rows . length > 0 ) {
2024-05-28 00:17:57 +02:00
const spiel = spieleResult . rows [ 0 ] ;
res . render ( 'spiel' , { spiel , session : req . session } ) ;
2024-05-31 21:29:18 +02:00
} else {
req . session . message = [ 'Error' , 'Spiel existiert nicht' , 'error' ] ;
res . redirect ( '/spiele' ) ;
}
2024-05-28 00:17:57 +02:00
} catch ( error ) {
2024-05-31 21:29:18 +02:00
console . error ( 'Error in Spiele:' , error ) ;
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-05-30 18:16:36 +02:00
const { material , dauer , regeln , variationen , type , id } = req . body ;
2024-05-28 00:17:57 +02:00
try {
2024-05-30 18:16:36 +02:00
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 ] ) ;
2024-05-31 21:29:18 +02:00
req . session . message = [ 'Erfolg' , 'Das Spiel wurde gespeichert' , 'success' ] ;
2024-05-28 00:17:57 +02:00
res . redirect ( '/spiel/' + id ) ;
} catch ( error ) {
2024-05-29 20:55:02 +02:00
console . error ( 'Error in edit Spiel:' , error ) ;
2024-05-31 21:29:18 +02:00
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 ) => {
2024-05-31 21:29:18 +02:00
req . session . message = [ '' , '' , 'none' ]
2024-05-28 16:19:59 +02:00
res . render ( 'index' , { session : req . session } ) ;
} ) ;
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-05-31 21:29:18 +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-05-31 21:29:18 +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 ] ) ;
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 ) ;
2024-05-31 21:29:18 +02:00
req . session . message = [ 'Error' , error , 'error' ] ;
res . render ( 'changelog' , { changes , session : req . session } ) ;
2024-05-30 19:24:40 +02:00
}
} )
2024-05-31 18:42:27 +02:00
app . post ( '/anwesend' , requireAuth , async ( req , res ) => {
2024-05-31 21:29:18 +02:00
const { anw , trainingId , riege } = req . body ;
req . session . activeTab = 'anwesend' ;
req . session . message = [ title = 'Erfolg' , body = 'Die Anwesenheit wurde gespeichert' , type = 'success' ] ;
2024-05-31 18:42:27 +02:00
try {
for ( const teilnehmer of anw ) {
2024-05-31 21:45:21 +02:00
const resultAnw = await pool . query ( 'Select * FROM anwesend WHERE fid_teilnehmer = $1 AND fid_training = $2' , [ teilnehmer , trainingId ] ) ;
if ( resultAnw . rows . length == 0 ) {
2024-05-31 18:42:27 +02:00
await pool . query ( 'INSERT INTO anwesend (fid_teilnehmer, fid_training) VALUES ($1, $2)' , [ teilnehmer , trainingId ] ) ;
2024-05-31 21:45:21 +02:00
} }
2024-05-31 21:29:18 +02:00
req . session . activeRiege = riege ;
2024-05-31 18:42:27 +02:00
res . redirect ( '/training' ) ;
} catch ( error ) {
console . error ( 'Error:' , error ) ;
2024-05-31 21:29:18 +02:00
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-05-31 22:21:44 +02:00
log . Info ( ` Server is running on ${ process . env . HOST } : ${ port } / ` ) ;
2024-05-23 20:49:34 +02:00
} ) ;
2024-05-28 00:17:57 +02:00