const express = require('express'); const bcrypt = require('bcryptjs'); const { getDb, getOrCreateSupportGroup } = require('../models/db'); const { generateToken, authMiddleware, setActiveSession, clearActiveSession } = require('../middleware/auth'); module.exports = function(io) { const router = express.Router(); // Login router.post('/login', (req, res) => { const { email, password, rememberMe } = req.body; const db = getDb(); const user = db.prepare('SELECT * FROM users WHERE email = ?').get(email); if (!user) return res.status(401).json({ error: 'Invalid credentials' }); if (user.status === 'suspended') { const adminUser = db.prepare('SELECT email FROM users WHERE is_default_admin = 1').get(); return res.status(403).json({ error: 'suspended', adminEmail: adminUser?.email }); } if (user.status === 'deleted') return res.status(403).json({ error: 'Account not found' }); const valid = bcrypt.compareSync(password, user.password); if (!valid) return res.status(401).json({ error: 'Invalid credentials' }); const token = generateToken(user.id); const ua = req.headers['user-agent'] || ''; const device = setActiveSession(user.id, token, ua); // displaces prior session on same device class // Kick any live socket on the same device class — it now holds a stale token if (io) { io.to(`user:${user.id}`).emit('session:displaced', { device }); } const { password: _, ...userSafe } = user; res.json({ token, user: userSafe, mustChangePassword: !!user.must_change_password, rememberMe: !!rememberMe }); }); // Change password router.post('/change-password', authMiddleware, (req, res) => { const { currentPassword, newPassword } = req.body; const db = getDb(); const user = db.prepare('SELECT * FROM users WHERE id = ?').get(req.user.id); if (!bcrypt.compareSync(currentPassword, user.password)) { return res.status(400).json({ error: 'Current password is incorrect' }); } if (newPassword.length < 8) return res.status(400).json({ error: 'Password must be at least 8 characters' }); const hash = bcrypt.hashSync(newPassword, 10); db.prepare("UPDATE users SET password = ?, must_change_password = 0, updated_at = datetime('now') WHERE id = ?").run(hash, req.user.id); res.json({ success: true }); }); // Get current user router.get('/me', authMiddleware, (req, res) => { const { password, ...user } = req.user; res.json({ user }); }); // Logout — clear active session for this device class only router.post('/logout', authMiddleware, (req, res) => { clearActiveSession(req.user.id, req.device); res.json({ success: true }); }); // Public support contact form — no auth required router.post('/support', (req, res) => { const { name, email, message } = req.body; if (!name?.trim() || !email?.trim() || !message?.trim()) { return res.status(400).json({ error: 'All fields are required' }); } if (message.trim().length > 2000) { return res.status(400).json({ error: 'Message too long (max 2000 characters)' }); } const db = getDb(); // Get or create the Support group const groupId = getOrCreateSupportGroup(); if (!groupId) return res.status(500).json({ error: 'Support group unavailable' }); // Find a system/admin user to post as (default admin) const admin = db.prepare('SELECT id FROM users WHERE is_default_admin = 1').get(); if (!admin) return res.status(500).json({ error: 'No admin configured' }); // Format the support message const content = `📬 **Support Request** **Name:** ${name.trim()} **Email:** ${email.trim()} ${message.trim()}`; const msgResult = db.prepare(` INSERT INTO messages (group_id, user_id, content, type) VALUES (?, ?, ?, 'text') `).run(groupId, admin.id, content); // Emit socket event so online admins see the message immediately const newMsg = db.prepare(` SELECT m.*, u.name as user_name, u.display_name as user_display_name, u.avatar as user_avatar FROM messages m JOIN users u ON m.user_id = u.id WHERE m.id = ? `).get(msgResult.lastInsertRowid); if (newMsg) { newMsg.reactions = []; io.to(`group:${groupId}`).emit('message:new', newMsg); } // Notify each admin via their user channel so they can reload groups if needed const admins = db.prepare("SELECT id FROM users WHERE role = 'admin' AND status = 'active'").all(); for (const a of admins) { io.to(`user:${a.id}`).emit('notification:new', { type: 'support', groupId }); } console.log(`[Support] Message from ${email} posted to Support group`); res.json({ success: true }); }); return router; };