From cb562870da7c9655266e1fcf196416a5df59ae79 Mon Sep 17 00:00:00 2001 From: klaas Date: Sat, 7 Sep 2024 16:34:15 +0200 Subject: [PATCH] projekte --- app.js | 423 ++++++++++++++++++++++++-------------- views/partials/header.ejs | 4 + 2 files changed, 272 insertions(+), 155 deletions(-) diff --git a/app.js b/app.js index d5adc9a..8893813 100644 --- a/app.js +++ b/app.js @@ -1,53 +1,54 @@ -const express = require('express'); -const session = require('express-session'); -const bcrypt = require('bcrypt'); -const crypto = require('crypto'); -const nodemailer = require('nodemailer'); -const { Pool } = require('pg'); -const path = require('path'); -const moment = require('moment'); -require('dotenv').config(); -const log = require('node-file-logger'); +const express = require("express"); +const session = require("express-session"); +const bcrypt = require("bcrypt"); +const crypto = require("crypto"); +const nodemailer = require("nodemailer"); +const { Pool } = require("pg"); +const path = require("path"); +const moment = require("moment"); +require("dotenv").config(); +const log = require("node-file-logger"); const app = express(); const port = process.env.PORT; const options = { - folderPath: './logs/', + folderPath: "./logs/", dateBasedFileNaming: true, - fileNamePrefix: 'DailyLogs_', - fileNameExtension: '.log', - dateFormat: 'YYYY_MM_D', - timeFormat: 'h:mm:ss A', -} + 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.static(path.join(__dirname, "public"))); app.use(express.json()); -app.set('view engine', 'ejs'); +app.set("view engine", "ejs"); app.use(express.urlencoded({ extended: false })); // Session-Konfiguration -app.use(session({ - secret: process.env.SESSIONSECRET, - resave: false, - saveUninitialized: true, - cookie: { maxAge: 1000 * 60 * 60 * 24 * 2 } -})); +app.use( + session({ + secret: process.env.SESSIONSECRET, + resave: false, + saveUninitialized: true, + cookie: { maxAge: 1000 * 60 * 60 * 24 * 2 }, + }) +); // Authentifizierungs-Middleware const requireAuth = (req, res, next) => { if (!req.session.userId) { - return res.redirect('/login'); + return res.redirect("/login"); } next(); }; const requireAdmin = (req, res, next) => { - if (req.session.role !== 'admin') { - return res.status(403).send('Access denied'); + if (req.session.role !== "admin") { + return res.status(403).send("Access denied"); } next(); }; @@ -59,53 +60,58 @@ const transporter = nodemailer.createTransport({ secure: true, auth: { user: process.env.MAILUSER, - pass: process.env.MAILPASS - } + pass: process.env.MAILPASS, + }, }); // Datenbankverbindung const pool = new Pool({ - connectionString: process.env.DATABASE_URL + connectionString: process.env.DATABASE_URL, }); - // Registrierung -app.post('/register', async (req, res) => { +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'; + 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` + 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 }); + 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 }); - + 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 }); + 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) => { +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]); + 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); @@ -114,224 +120,331 @@ app.post('/login', async (req, res) => { 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'; + 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('/'); + res.redirect("/"); } else { - res.redirect('/freischaltung') + res.redirect("/freischaltung"); } } else { - const message = 'Falscher Benutzername oder falsches Passwort'; - res.render('login', { session: req.session, username, message }); + 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 }); + 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 }); + 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 }); -}) +app.get("/freischaltung", async (req, res) => { + res.render("freischaltung", { session: req.session }); +}); // Logout -app.get('/logout', (req, res) => { - req.session.destroy(err => { +app.get("/logout", (req, res) => { + req.session.destroy((err) => { if (err) { - return res.status(500).send('Internal Server Error'); + return res.status(500).send("Internal Server Error"); } - res.redirect('/'); + res.redirect("/"); }); }); // Benutzer freischalten (nur Admin) -app.post('/userrights', requireAuth, requireAdmin, async (req, res) => { +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 (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.` + 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 }); + 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 === "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]); } - 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'); + res.redirect("/admin"); } catch (error) { - console.error('Error activating user:', error); - const message = 'Error activating user:' + error; - res.render('error', { session: req.session, message }); + 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) => { +app.post("/send-password", async (req, res) => { const { email } = req.body; try { - const userResult = await pool.query('SELECT * FROM users WHERE email = $1', [email]); + 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 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]); + 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}` + 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 }); + 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 }); + 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 }); + 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 }); + 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 }) -}) +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) => { +app.get("/reset-password/:token", async (req, res) => { const { token } = req.params; try { - const userResult = await pool.query('SELECT * FROM users WHERE reset_password_token = $1 AND reset_password_expires > $2', [token, Date.now()]); + const userResult = await pool.query( + "SELECT * 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 + 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 }); + 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 }); + 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) => { +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()]); + 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'); + 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 }); + 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 }); + 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.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) => { +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]); + 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]); + await pool.query("UPDATE users SET password = $1 WHERE id = $2", [ + hashedPassword, + req.session.userId, + ]); } - res.redirect('/profile'); + res.redirect("/profile"); } catch (error) { - console.error('Error updating profile:', error); - const message = 'Error updating profile:' + error; - res.render('error', { session: req.session, message }); + console.error("Error updating profile:", error); + const message = "Error updating profile:" + error; + res.render("error", { session: req.session, message }); } }); +// Route für die Projektliste +app.get("/projects", async (req, res) => { + req.session.message = ["", "", "none"]; + try { + const result = await pool.query( + "SELECT id, name, beschreibung FROM projects" + ); + const projekte = result.rows; + res.render("projects", { projekte, session: req.session }); + } catch (err) { + console.error(err); + res.send(err); + } +}); + +app.post("/projects", async (req, res) => { + const { name, beschreibung } = req.body; + req.session.message = ["", "", "none"]; + try { + await pool.query( + "INSERT INTO projects (name, beschreibung) VALUES ($1, $2)", + [name, beschreibung] + ); + } catch (err) { + console.error(err); + res.send(err); + } + try { + const result = await pool.query( + "SELECT id, name, beschreibung FROM projects" + ); + const projekte = result.rows; + res.render("projects", { projekte, session: req.session }); + } catch (err) { + console.error(err); + res.send(err); + } +}); + +app.get("/project/:id", async (req, res) => { + req.session.message = ["", "", "none"]; + try { + const { id } = req.params; + const result = await pool.query("SELECT * FROM projects WHERE id = $1", [ + id, + ]); + const projekt = result.rows[0]; + + if (!projekt) { + return res.status(404).send("Projekt nicht gefunden"); + } + + res.render("project", { projekt, session: req.session }); + } catch (err) { + console.error(err); + res.send("Fehler beim Abrufen des Projekts"); + } +}); + +app.post("/projectedit", async (req, res) => { + req.session.message = ["", "", "none"]; + const { id, name, beschreibung } = req.body; + try { + await pool.query( + "UPDATE projects SET name = $1, beschreibung = $2 WHERE id = $3", + [name, beschreibung, id] + ); + } catch (err) { + console.error(err); + res.send(err); + } + res.redirect("/project/" + id); +}); + // 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.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 }); // 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 +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 +app.get("/register", (req, res) => { + res.render("register", { session: req.session }); // Stelle sicher, dass es eine register.ejs gibt }); // Startseite -app.get('/', (req, res) => { - req.session.message = ['', '', 'none'] - res.render('index', { session: req.session }); +app.get("/", (req, res) => { + req.session.message = ["", "", "none"]; + res.render("index", { session: req.session }); }); //Datenschutz und Impressum -app.get('/impressum', (req, res) => { - req.session.message = ['', '', 'none'] - res.render('impressum', { session: req.session }); +app.get("/impressum", (req, res) => { + req.session.message = ["", "", "none"]; + res.render("impressum", { session: req.session }); }); -const server = app.listen(port, '0.0.0.0', () => { +const server = app.listen(port, "0.0.0.0", () => { log.Info(`Server is running on ${process.env.HOST}:${port}/`); -}); \ No newline at end of file +}); diff --git a/views/partials/header.ejs b/views/partials/header.ejs index fb3b7ad..268a000 100644 --- a/views/partials/header.ejs +++ b/views/partials/header.ejs @@ -36,6 +36,10 @@ <% } %> + + + Projekte + <% if (session && session.role === 'admin') { %> <% } %>