19c6facf71
Ersetzt das manuelle E-Mail-Eingabefeld für den Passwort-Reset durch eine Liste aller angemeldeten User. Pro User stehen zwei Aktionen zur Verfügung: Passwort zurücksetzen (nutzt die bestehende /api/resetPassword-Route) und Löschen (neue DELETE /api/users/:id-Route, admin-only, verhindert Löschen des eigenen Accounts). Neue GET /api/users-Route liefert Email/Rolle aller User (admin-only).
156 lines
5.8 KiB
JavaScript
156 lines
5.8 KiB
JavaScript
import { MongoAPIError, ObjectId } from 'mongodb';
|
|
import bcrypt from 'bcrypt';
|
|
import { getCollections, update_pflux } from '../db/mongo.js';
|
|
|
|
export function registerApiRoutes(app, requireLogin) {
|
|
const { usersCollection, propCollection } = getCollections();
|
|
|
|
app.get('/api/check-email', async (req, res) => {
|
|
const email = (req.query.email || '').toLowerCase().trim();
|
|
if (!email) return res.json({ exists: false });
|
|
try {
|
|
const existingUser = await usersCollection.findOne({ email:`${email}` });
|
|
res.json({ exists: !!existingUser });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Fehler bei der E-Mail-Prüfung' });
|
|
}
|
|
});
|
|
|
|
app.post('/api/save', requireLogin, async (req, res) => {
|
|
let { espId, sensorNumber, name, description} = req.body;
|
|
if (!espId || !sensorNumber) {
|
|
return res.json({ error: 'ESP-ID und Sensornummer sind Pflichtfelder' });
|
|
}
|
|
sensorNumber = parseInt(sensorNumber, 10);
|
|
try {
|
|
const doc = {
|
|
id: espId,
|
|
name: name || '',
|
|
description: description || '',
|
|
lastUpdatedAt: new Date()
|
|
};
|
|
await update_pflux(sensorNumber, doc)
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Fehler beim Speichern' });
|
|
}
|
|
});
|
|
|
|
|
|
app.get('/api/list', requireLogin, async (req, res) => {
|
|
const { id } = req.query;
|
|
if (id) {
|
|
try {
|
|
const item = await propCollection.findOne({ _id: parseInt(id) });
|
|
if (item) return res.json([item]);
|
|
return res.json([]);
|
|
} catch (err) {
|
|
console.error(err);
|
|
return res.status(500).json({ error: 'Fehler beim Laden' });
|
|
}
|
|
}
|
|
|
|
let gesamtZahl = 0
|
|
try {
|
|
gesamtZahl = await propCollection.countDocuments({chip: {$exists: true}})
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
const page = parseInt(req.query.page) || 1;
|
|
const limit = parseInt(req.query.limit) || 50;
|
|
const skip = (page - 1) * limit;
|
|
try {
|
|
const items = await propCollection.find({chip: {$exists: true}})
|
|
.sort({ "chip.lastUpdatedAt": -1 })
|
|
.skip(skip)
|
|
.limit(limit)
|
|
.toArray();
|
|
const data = {items: items, anzahl: gesamtZahl}
|
|
res.json(data);
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Fehler beim Laden' });
|
|
}
|
|
});
|
|
|
|
app.delete('/api/delete/:id', requireLogin, async (req, res) => {
|
|
await propCollection.deleteOne({ _id: parseInt(req.params.id) });
|
|
res.json({ success: true });
|
|
});
|
|
|
|
app.post('/api/createUser', requireLogin, async (req, res) => {
|
|
if (!req.session.isAdmin) return res.status(403).json({ error: 'Nur Admins erlaubt' });
|
|
const { username, password, role } = req.body;
|
|
if (!username || !password) return res.status(400).json({ error: 'Benutzername und Passwort erforderlich' });
|
|
try {
|
|
const hash = await bcrypt.hash(password, 10);
|
|
await usersCollection.insertOne({ email: username.toLowerCase(), passwordHash: hash, role: role || 'user' });
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Fehler beim Anlegen' });
|
|
}
|
|
});
|
|
|
|
app.post('/api/changePassword', requireLogin, async (req, res) => {
|
|
const { currentPassword, newPassword } = req.body;
|
|
if (!currentPassword || !newPassword) {
|
|
return res.status(400).json({ error: 'Aktuelles und neues Passwort erforderlich' });
|
|
}
|
|
try {
|
|
const user = await usersCollection.findOne({ _id: new ObjectId(req.session.userId) });
|
|
if (!user) return res.status(404).json({ error: 'User nicht gefunden' });
|
|
const match = await bcrypt.compare(currentPassword, user.passwordHash);
|
|
if (!match) return res.status(403).json({ error: 'Aktuelles Passwort ist falsch' });
|
|
const hash = await bcrypt.hash(newPassword, 10);
|
|
await usersCollection.updateOne({ _id: user._id }, { $set: { passwordHash: hash } });
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Fehler beim Ändern des Passworts' });
|
|
}
|
|
});
|
|
|
|
app.post('/api/resetPassword', requireLogin, async (req, res) => {
|
|
if (!req.session.isAdmin) return res.status(403).json({ error: 'Nur Admins erlaubt' });
|
|
const { email, newPassword } = req.body;
|
|
if (!email || !newPassword) return res.status(400).json({ error: 'Email und neues Passwort erforderlich' });
|
|
try {
|
|
const hash = await bcrypt.hash(newPassword, 10);
|
|
const result = await usersCollection.updateOne(
|
|
{ email: email.toLowerCase() },
|
|
{ $set: { passwordHash: hash } }
|
|
);
|
|
if (result.matchedCount === 0) return res.status(404).json({ error: 'User nicht gefunden' });
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Fehler beim Zurücksetzen' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/users', requireLogin, async (req, res) => {
|
|
if (!req.session.isAdmin) return res.status(403).json({ error: 'Nur Admins erlaubt' });
|
|
try {
|
|
const users = await usersCollection.find({}, { projection: { email: 1, role: 1 } }).sort({ email: 1 }).toArray();
|
|
res.json(users);
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Fehler beim Laden der User' });
|
|
}
|
|
});
|
|
|
|
app.delete('/api/users/:id', requireLogin, async (req, res) => {
|
|
if (!req.session.isAdmin) return res.status(403).json({ error: 'Nur Admins erlaubt' });
|
|
const { id } = req.params;
|
|
if (id === String(req.session.userId)) {
|
|
return res.status(400).json({ error: 'Der eigene Account kann nicht gelöscht werden' });
|
|
}
|
|
try {
|
|
const result = await usersCollection.deleteOne({ _id: new ObjectId(id) });
|
|
if (result.deletedCount === 0) return res.status(404).json({ error: 'User nicht gefunden' });
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Fehler beim Löschen' });
|
|
}
|
|
});
|
|
}
|