Michi 0ebe7fa13d
Some checks failed
🚀 Continuous Integration / 🔧 Backend Tests (18.x) (push) Has been cancelled
🚀 Continuous Integration / 🔧 Backend Tests (20.x) (push) Has been cancelled
🚀 Continuous Integration / 🎨 Frontend Tests (18.x) (push) Has been cancelled
🚀 Continuous Integration / 🎨 Frontend Tests (20.x) (push) Has been cancelled
🚀 Continuous Integration / 🔍 Code Quality (push) Has been cancelled
🚀 Continuous Integration / 🔒 Security Checks (push) Has been cancelled
🚀 Continuous Integration / 🎨 Theme Tests (push) Has been cancelled
🚀 Continuous Integration / ♿ Accessibility Tests (push) Has been cancelled
🚀 Continuous Integration / 📱 Cross-Browser Tests (push) Has been cancelled
🚀 Continuous Integration / 🏗️ Build Tests (push) Has been cancelled
🚀 Continuous Integration / 📊 Performance Tests (push) Has been cancelled
🚀 Continuous Integration / 🎯 Integration Tests (push) Has been cancelled
🚀 Continuous Integration / ✅ All Tests Passed (push) Has been cancelled
Initial commit: ToDo Kids v1.0.0
2025-08-04 15:46:08 +02:00

336 lines
8.3 KiB
JavaScript

const express = require('express');
const jwt = require('jsonwebtoken');
const { body, validationResult } = require('express-validator');
const User = require('../models/User');
const { auth } = require('../middleware/auth');
const router = express.Router();
// @route POST /api/auth/register
// @desc Registriere neuen Eltern-Account
// @access Public
router.post('/register', [
body('email')
.isEmail()
.normalizeEmail()
.withMessage('Bitte gib eine gültige E-Mail-Adresse ein'),
body('password')
.isLength({ min: 6 })
.withMessage('Passwort muss mindestens 6 Zeichen lang sein'),
body('familyName')
.trim()
.isLength({ min: 2, max: 50 })
.withMessage('Familienname muss zwischen 2 und 50 Zeichen lang sein'),
body('parentName')
.trim()
.isLength({ min: 2, max: 50 })
.withMessage('Elternname muss zwischen 2 und 50 Zeichen lang sein')
], async (req, res) => {
try {
// Validierungsfehler prüfen
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: 'Validierungsfehler',
errors: errors.array()
});
}
const { email, password, familyName, parentName } = req.body;
// Prüfen ob Benutzer bereits existiert
let user = await User.findOne({ email });
if (user) {
return res.status(400).json({
success: false,
message: 'Ein Account mit dieser E-Mail-Adresse existiert bereits'
});
}
// Neuen Benutzer erstellen
user = new User({
email,
password,
familyName,
parentName
});
await user.save();
// JWT Token erstellen
const payload = {
user: {
id: user.id,
email: user.email,
role: user.role
}
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: '7d' },
(err, token) => {
if (err) throw err;
res.status(201).json({
success: true,
message: `Willkommen bei Familien-Held, ${parentName}! 🎉`,
token,
user: {
id: user.id,
email: user.email,
familyName: user.familyName,
parentName: user.parentName,
role: user.role,
createdAt: user.createdAt
}
});
}
);
} catch (error) {
console.error('Registrierungsfehler:', error.message);
res.status(500).json({
success: false,
message: 'Server-Fehler bei der Registrierung'
});
}
});
// @route POST /api/auth/login
// @desc Eltern-Login
// @access Public
router.post('/login', [
body('email')
.isEmail()
.normalizeEmail()
.withMessage('Bitte gib eine gültige E-Mail-Adresse ein'),
body('password')
.exists()
.withMessage('Passwort ist erforderlich')
], async (req, res) => {
try {
// Validierungsfehler prüfen
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: 'Validierungsfehler',
errors: errors.array()
});
}
const { email, password } = req.body;
// Benutzer finden
const user = await User.findOne({ email, isActive: true });
if (!user) {
return res.status(400).json({
success: false,
message: 'Ungültige Anmeldedaten'
});
}
// Passwort prüfen
const isMatch = await user.comparePassword(password);
if (!isMatch) {
return res.status(400).json({
success: false,
message: 'Ungültige Anmeldedaten'
});
}
// Letzten Login aktualisieren
user.lastLogin = new Date();
await user.save();
// JWT Token erstellen
const payload = {
user: {
id: user.id,
email: user.email,
role: user.role
}
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: '7d' },
(err, token) => {
if (err) throw err;
res.json({
success: true,
message: `Willkommen zurück, ${user.parentName}! 👋`,
token,
user: {
id: user.id,
email: user.email,
familyName: user.familyName,
parentName: user.parentName,
role: user.role,
lastLogin: user.lastLogin
}
});
}
);
} catch (error) {
console.error('Login-Fehler:', error.message);
res.status(500).json({
success: false,
message: 'Server-Fehler beim Login'
});
}
});
// @route GET /api/auth/me
// @desc Aktuellen Benutzer abrufen
// @access Private
router.get('/me', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
if (!user) {
return res.status(404).json({
success: false,
message: 'Benutzer nicht gefunden'
});
}
res.json({
success: true,
user
});
} catch (error) {
console.error('Benutzer-Abruf-Fehler:', error.message);
res.status(500).json({
success: false,
message: 'Server-Fehler beim Abrufen der Benutzerdaten'
});
}
});
// @route PUT /api/auth/profile
// @desc Profil aktualisieren
// @access Private
router.put('/profile', [
auth,
body('familyName')
.optional()
.trim()
.isLength({ min: 2, max: 50 })
.withMessage('Familienname muss zwischen 2 und 50 Zeichen lang sein'),
body('parentName')
.optional()
.trim()
.isLength({ min: 2, max: 50 })
.withMessage('Elternname muss zwischen 2 und 50 Zeichen lang sein')
], async (req, res) => {
try {
// Validierungsfehler prüfen
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: 'Validierungsfehler',
errors: errors.array()
});
}
const { familyName, parentName, preferences } = req.body;
const updateFields = {};
if (familyName) updateFields.familyName = familyName;
if (parentName) updateFields.parentName = parentName;
if (preferences) updateFields.preferences = { ...preferences };
const user = await User.findByIdAndUpdate(
req.user.id,
{ $set: updateFields },
{ new: true, runValidators: true }
).select('-password');
res.json({
success: true,
message: 'Profil erfolgreich aktualisiert! ✅',
user
});
} catch (error) {
console.error('Profil-Update-Fehler:', error.message);
res.status(500).json({
success: false,
message: 'Server-Fehler beim Aktualisieren des Profils'
});
}
});
// @route PUT /api/auth/password
// @desc Passwort ändern
// @access Private
router.put('/password', [
auth,
body('currentPassword')
.exists()
.withMessage('Aktuelles Passwort ist erforderlich'),
body('newPassword')
.isLength({ min: 6 })
.withMessage('Neues Passwort muss mindestens 6 Zeichen lang sein')
], async (req, res) => {
try {
// Validierungsfehler prüfen
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: 'Validierungsfehler',
errors: errors.array()
});
}
const { currentPassword, newPassword } = req.body;
// Benutzer mit Passwort abrufen
const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({
success: false,
message: 'Benutzer nicht gefunden'
});
}
// Aktuelles Passwort prüfen
const isMatch = await user.comparePassword(currentPassword);
if (!isMatch) {
return res.status(400).json({
success: false,
message: 'Aktuelles Passwort ist falsch'
});
}
// Neues Passwort setzen
user.password = newPassword;
await user.save();
res.json({
success: true,
message: 'Passwort erfolgreich geändert! 🔒'
});
} catch (error) {
console.error('Passwort-Änderungs-Fehler:', error.message);
res.status(500).json({
success: false,
message: 'Server-Fehler beim Ändern des Passworts'
});
}
});
// @route POST /api/auth/logout
// @desc Logout (Token invalidieren - clientseitig)
// @access Private
router.post('/logout', auth, (req, res) => {
res.json({
success: true,
message: 'Erfolgreich abgemeldet! Bis bald! 👋'
});
});
module.exports = router;