import express from 'express'; import jwt from 'jsonwebtoken'; import bcrypt from 'bcryptjs'; import prisma from '../lib/prisma'; import { validate } from '../middleware/validate'; import { loginSchema, registerSchema, changePasswordSchema, updateProfileSchema } from '../schemas/auth'; const router = express.Router(); const JWT_SECRET = process.env.JWT_SECRET || 'secret'; // Get Current User router.get('/me', async (req, res) => { try { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); const decoded = jwt.verify(token, JWT_SECRET) as any; const user = await prisma.user.findUnique({ where: { id: decoded.userId }, include: { profile: true } }); if (!user) { return res.status(404).json({ error: 'User not found' }); } const { password: _, ...userSafe } = user; res.json({ success: true, user: userSafe }); } catch (error) { res.status(401).json({ error: 'Invalid token' }); } }); // Login router.post('/login', validate(loginSchema), async (req, res) => { try { const { email, password } = req.body; const user = await prisma.user.findUnique({ where: { email }, include: { profile: true } }); if (!user) { return res.status(400).json({ error: 'Invalid credentials' }); } if (user.isBlocked) { return res.status(403).json({ error: 'Account is blocked' }); } const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) { return res.status(400).json({ error: 'Invalid credentials' }); } const token = jwt.sign({ userId: user.id, role: user.role }, JWT_SECRET); const { password: _, ...userSafe } = user; res.json({ success: true, user: userSafe, token }); } catch (error) { console.error('Login error:', error); res.status(500).json({ error: 'Server error' }); } }); // Register router.post('/register', validate(registerSchema), async (req, res) => { try { const { email, password } = req.body; // Check if user already exists const existingUser = await prisma.user.findUnique({ where: { email } }); if (existingUser) { return res.status(400).json({ error: 'User already exists' }); } const hashedPassword = await bcrypt.hash(password, 10); const user = await prisma.user.create({ data: { email, password: hashedPassword, role: 'USER', profile: { create: { weight: 70 } } }, include: { profile: true } }); const token = jwt.sign({ userId: user.id, role: user.role }, JWT_SECRET); const { password: _, ...userSafe } = user; res.json({ success: true, user: userSafe, token }); } catch (error) { console.error(error); res.status(500).json({ error: 'Server error' }); } }); // Change Password router.post('/change-password', validate(changePasswordSchema), async (req, res) => { try { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); const { userId, newPassword } = req.body; // Verify token const decoded = jwt.verify(token, JWT_SECRET) as any; if (decoded.userId !== userId) { return res.status(403).json({ error: 'Forbidden' }); } const hashed = await bcrypt.hash(newPassword, 10); await prisma.user.update({ where: { id: userId }, data: { password: hashed, isFirstLogin: false } }); res.json({ success: true }); } catch (error) { console.error(error); res.status(500).json({ error: 'Server error' }); } }); // Update Profile router.patch('/profile', validate(updateProfileSchema), async (req, res) => { try { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); // const { userId, profile } = req.body; // Convert birthDate from timestamp to Date object if needed if (req.body.birthDate) { // Handle both number (timestamp) and string (ISO) req.body.birthDate = new Date(req.body.birthDate); } // Verify token const decoded = jwt.verify(token, JWT_SECRET) as any; const userId = decoded.userId; // Update or create profile await prisma.userProfile.upsert({ where: { userId: userId }, update: { ...req.body }, create: { userId: userId, ...req.body } }); res.json({ success: true }); } catch (error) { console.error(error); res.status(500).json({ error: 'Server error' }); } }); // Admin: Get All Users router.get('/users', async (req, res) => { try { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); const decoded = jwt.verify(token, JWT_SECRET) as any; if (decoded.role !== 'ADMIN') { return res.status(403).json({ error: 'Admin access required' }); } const users = await prisma.user.findMany({ select: { id: true, email: true, role: true, isBlocked: true, isFirstLogin: true, profile: true } }); res.json({ success: true, users }); } catch (error) { console.error(error); res.status(500).json({ error: 'Server error' }); } }); // Admin: Delete User router.delete('/users/:id', async (req, res) => { try { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); const decoded = jwt.verify(token, JWT_SECRET) as any; if (decoded.role !== 'ADMIN') { return res.status(403).json({ error: 'Admin access required' }); } const { id } = req.params; // Prevent deleting self if (id === decoded.userId) { return res.status(400).json({ error: 'Cannot delete yourself' }); } await prisma.user.delete({ where: { id } }); res.json({ success: true }); } catch (error) { console.error(error); res.status(500).json({ error: 'Server error' }); } }); // Admin: Toggle Block User router.patch('/users/:id/block', async (req, res) => { try { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); const decoded = jwt.verify(token, JWT_SECRET) as any; if (decoded.role !== 'ADMIN') { return res.status(403).json({ error: 'Admin access required' }); } const { id } = req.params; const { block } = req.body; // Prevent blocking self if (id === decoded.userId) { return res.status(400).json({ error: 'Cannot block yourself' }); } await prisma.user.update({ where: { id }, data: { isBlocked: block } }); res.json({ success: true }); } catch (error) { console.error(error); res.status(500).json({ error: 'Server error' }); } }); export default router;