const express = require('express'); const router = express.Router(); const { body, validationResult } = require('express-validator'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const db = require('../db'); const requireRole = require('../middleware/requireRole'); // Register a new user router.post('/register', [ body('email').isEmail().normalizeEmail(), body('password').isLength({ min: 8 }), body('name').notEmpty() ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { email, password, name } = req.body; try { // Check if user already exists const existingUser = await db.query('SELECT id FROM users WHERE email = $1', [email]); if (existingUser.rows.length > 0) { return res.status(409).json({ error: 'User already exists' }); } // Hash password const hashedPassword = await bcrypt.hash(password, 12); // Insert new user with default role 'user' const newUser = await db.query( 'INSERT INTO users (email, password_hash, name, role) VALUES ($1, $2, $3, $4) RETURNING id, email, name, role', [email, hashedPassword, name, 'user'] ); res.status(201).json({ user: newUser.rows[0] }); } catch (err) { console.error(err); res.status(500).json({ error: 'Internal server error' }); } }); // Login user router.post('/login', [ body('email').isEmail().normalizeEmail(), body('password').notEmpty() ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { email, password } = req.body; try { // Find user by email const user = await db.query('SELECT id, email, password_hash, name, role FROM users WHERE email = $1', [email]); if (user.rows.length === 0) { return res.status(401).json({ error: 'Invalid credentials' }); } // Compare passwords const isValidPassword = await bcrypt.compare(password, user.rows[0].password_hash); if (!isValidPassword) { return res.status(401).json({ error: 'Invalid credentials' }); } // Generate JWT token with role const token = jwt.sign( { userId: user.rows[0].id, email: user.rows[0].email, role: user.rows[0].role }, process.env.JWT_SECRET || 'default_secret', { expiresIn: '24h' } ); res.json({ token, user: { id: user.rows[0].id, email: user.rows[0].email, name: user.rows[0].name, role: user.rows[0].role } }); } catch (err) { console.error(err); res.status(500).json({ error: 'Internal server error' }); } }); // Get current user profile (requires authentication) router.get('/profile', requireRole(['user', 'moderator', 'admin']), async (req, res) => { try { const user = await db.query('SELECT id, email, name, role FROM users WHERE id = $1', [req.user.userId]); if (user.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } res.json({ user: user.rows[0] }); } catch (err) { console.error(err); res.status(500).json({ error: 'Internal server error' }); } }); // Update current user profile (requires authentication) router.put('/profile', requireRole(['user', 'moderator', 'admin']), [ body('name').optional().notEmpty() ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } try { const { name } = req.body; const userId = req.user.userId; // Update user profile const updatedUser = await db.query( 'UPDATE users SET name = $1 WHERE id = $2 RETURNING id, email, name, role', [name, userId] ); if (updatedUser.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } res.json({ user: updatedUser.rows[0] }); } catch (err) { console.error(err); res.status(500).json({ error: 'Internal server error' }); } }); module.exports = router;