Erste Versuche mut Login - geht noch nicht ( duplicate error an der Mongo

This commit is contained in:
2025-08-12 15:23:48 +00:00
parent 7556c0792a
commit 2a9bcb50f7
6 changed files with 737 additions and 91 deletions

220
server.js
View File

@@ -2,14 +2,31 @@ require('dotenv').config();
const express = require('express');
const cors = require('cors');
const { MongoClient, ObjectId } = require('mongodb');
const session = require('express-session');
const bcrypt = require('bcrypt');
const SESSION_SECRET = process.env.SESSION_SECRET || 'supersecret';
const app = express();
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
// Statische Dateien (z.B. global.js, CSS) ausliefern
app.use(express.static('public'));
// Session Middleware einrichten (vor allen Routes)
app.use(session({
secret: SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { maxAge: 24 * 60 * 60 * 1000 } // 1 Tag
}));
// User Collection
let usersCollection;
// Pug als Template Engine einrichten
app.set('view engine', 'pug');
app.set('views', './views');
@@ -22,81 +39,170 @@ let db, entriesCollection;
// MongoDB-Verbindung herstellen
async function initMongo() {
const client = new MongoClient(MONGO_URI);
await client.connect();
db = client.db(DB_NAME);
entriesCollection = db.collection('entries');
console.log(`MongoDB verbunden: ${MONGO_URI}/${DB_NAME}`);
const client = new MongoClient(MONGO_URI);
await client.connect();
db = client.db(DB_NAME);
entriesCollection = db.collection('entries');
usersCollection = db.collection('users');
// Ensure unique index on email for users collection
await usersCollection.createIndex({ email: 1 }, { unique: true });
console.log(`MongoDB verbunden: ${MONGO_URI}/${DB_NAME}`);
}
initMongo().catch(err => {
console.error('MongoDB Verbindungsfehler:', err);
process.exit(1);
console.error('MongoDB Verbindungsfehler:', err);
process.exit(1);
});
function formatDate(date) {
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// --- Web-Seite (Pug) rendern ---
app.get('/', (req, res) => {
res.render('index');
// Middleware: geschützte Seiten nur wenn angemeldet
function requireLogin(req, res, next) {
if (req.session.userId) {
next();
} else {
res.redirect('/login');
}
}
// Register-Seite (Pug)
app.get('/register', (req, res) => {
res.render('register', { error: null });
});
app.post('/register', async (req, res) => {
try {
let { email, password } = req.body;
if (!email || !password) {
return res.render('register', { error: 'Bitte Email und Passwort angeben.' });
}
email = email.trim().toLowerCase();
// Basic email format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return res.render('register', { error: 'Ungültiges Email-Format.' });
}
// Basic password strength validation (min 8 chars, at least one number and one letter)
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
if (!passwordRegex.test(password)) {
return res.render('register', { error: 'Passwort muss mindestens 8 Zeichen lang sein und mindestens eine Zahl und einen Buchstaben enthalten.' });
}
const existingUser = await usersCollection.findOne({ email });
if (existingUser) {
const hash = await bcrypt.hash(password, 10);
await usersCollection.insertOne({
email,
hashedPassword: hash,
createdAt: new Date()
});
res.redirect('/login');
}
} catch (err) {
console.error(err);
res.render('register', { error: 'Serverfehler.' });
}
});
// Login-Seite (Pug)
app.get('/login', (req, res) => {
res.render('login', { error: null });
});
app.post('/login', async (req, res) => {
let { email, password } = req.body;
if (!email || !password) {
return res.render('login', { error: 'Bitte Email und Passwort angeben.' });
}
email = email.toLowerCase();
try {
const user = await usersCollection.findOne({ email });
if (!user) {
const match = await bcrypt.compare(password, user.hashedPassword);
if (!match) {
return res.render('login', { error: 'Falsche Email oder Passwort.' });
}
req.session.userId = user._id;
res.redirect('/');
req.session.userId = user._id;
res.redirect('/');
}
} catch (err) {
console.error(err);
res.render('login', { error: 'Serverfehler.' });
}
});
// Logout
app.get('/logout', (req, res) => {
req.session.destroy(() => {
res.redirect('/login');
});
});
// Hauptseite jetzt mit Login-Schutz
app.get('/', requireLogin, (req, res) => {
res.render('index');
});
// --- API ---
app.post('/api/save', async (req, res) => {
const { espId, sensorNumber } = req.body;
if (!espId || !sensorNumber) {
return res.status(400).json({ ok: false, error: 'ESP-ID und Sensornummer sind erforderlich' });
}
try {
const doc = {
espId: String(espId).trim(),
sensorNumber: String(sensorNumber).trim(),
createdAt: new Date()
};
const result = await entriesCollection.insertOne(doc);
return res.json({ ok: true, id: result.insertedId, entry: doc });
} catch (err) {
console.error(err);
return res.status(500).json({ ok: false, error: 'DB Fehler' });
}
const { espId, sensorNumber } = req.body;
if (!espId || !sensorNumber) {
return res.status(400).json({ ok: false, error: 'ESP-ID und Sensornummer sind erforderlich' });
}
try {
const doc = {
espId: String(espId).trim(),
sensorNumber: String(sensorNumber).trim(),
createdAt: new Date()
};
const result = await entriesCollection.insertOne(doc);
return res.json({ ok: true, id: result.insertedId, entry: doc });
} catch (err) {
console.error(err);
return res.status(500).json({ ok: false, error: 'DB Fehler' });
}
});
app.get('/api/list', async (req, res) => {
const page = Math.max(1, parseInt(req.query.page) || 1);
const limit = Math.max(1, Math.min(100, parseInt(req.query.limit) || 50));
try {
const total = await entriesCollection.countDocuments();
const rawItems = await entriesCollection.find({})
.sort({ createdAt: -1 })
.skip((page - 1) * limit)
.limit(limit)
.toArray();
const items = rawItems.map(it => ({
...it,
createdAt: formatDate(it.createdAt)
}));
return res.json({ ok: true, page, limit, total, items });
} catch (err) {
console.error(err);
return res.status(500).json({ ok: false, error: 'DB Fehler' });
}
const page = Math.max(1, parseInt(req.query.page) || 1);
const limit = Math.max(1, Math.min(100, parseInt(req.query.limit) || 50));
try {
const total = await entriesCollection.countDocuments();
const rawItems = await entriesCollection.find({})
.sort({ createdAt: -1 })
.skip((page - 1) * limit)
.limit(limit)
.toArray();
const items = rawItems.map(it => ({
...it,
createdAt: formatDate(it.createdAt)
}));
return res.json({ ok: true, page, limit, total, items });
} catch (err) {
console.error(err);
return res.status(500).json({ ok: false, error: 'DB Fehler' });
}
});
app.delete('/api/entry/:id', async (req, res) => {
try {
await entriesCollection.deleteOne({ _id: new ObjectId(req.params.id) });
return res.json({ ok: true });
} catch (err) {
console.error(err);
return res.status(500).json({ ok: false });
}
try {
await entriesCollection.deleteOne({ _id: new ObjectId(req.params.id) });
return res.json({ ok: true });
} catch (err) {
console.error(err);
return res.status(500).json({ ok: false });
}
});
app.listen(PORT, () => {
console.log(`Server läuft auf http://localhost:${PORT}`);
console.log(`Server läuft auf http://localhost:${PORT}`);
});