import { Router } from 'express'; import bcrypt from 'bcryptjs'; import { requireTeacher } from './auth.js'; import { findUserByUsername, createUser, listStudents } from './db.js'; const router = Router(); const BCRYPT_ROUNDS = 8; const USERNAME_RE = /^[a-zA-Z0-9_.-]{3,64}$/; const WORDS_A = ['red', 'blue', 'green', 'happy', 'sunny', 'brave', 'tiny', 'swift', 'kind', 'bright']; const WORDS_B = ['cat', 'dog', 'fox', 'duck', 'frog', 'bear', 'star', 'moon', 'kite', 'fish']; const WORDS_C = ['jump', 'play', 'run', 'smile', 'spin', 'dance', 'wave', 'clap', 'sing', 'grow']; function sanitizeStudent(row) { return { id: row.id, username: row.username, role: row.role, createdAt: row.created_at, }; } function randomItem(list) { return list[Math.floor(Math.random() * list.length)]; } function candidateUsername() { const useThree = Math.random() < 0.45; const first = randomItem(WORDS_A); const second = randomItem(WORDS_B); if (!useThree) return `${first}${second}`; const third = randomItem(WORDS_C); return `${first}${second}${third}`; } async function generateUniqueUsername() { for (let i = 0; i < 40; i += 1) { const candidate = candidateUsername(); const existing = await findUserByUsername(candidate); if (!existing) return candidate; } return `${candidateUsername()}${Math.floor(100 + Math.random() * 900)}`; } router.get('/students', requireTeacher, async (_req, res) => { try { const students = (await listStudents()).map(sanitizeStudent); res.json({ students }); } catch (err) { res.status(500).json({ error: err.message }); } }); router.get('/students/suggest-username', requireTeacher, async (_req, res) => { try { const username = await generateUniqueUsername(); res.json({ username }); } catch (err) { res.status(500).json({ error: err.message }); } }); router.post('/students', requireTeacher, async (req, res) => { let { username } = req.body || {}; try { username = username ? String(username).trim() : ''; if (!username) username = await generateUniqueUsername(); if (!USERNAME_RE.test(username)) { return res.status(400).json({ error: 'username must be 3-64 chars, letters/digits/._-' }); } const existing = await findUserByUsername(username); if (existing) return res.status(409).json({ error: 'username already taken' }); // Requested behavior: default password equals username. const hash = await bcrypt.hash(username, BCRYPT_ROUNDS); const user = await createUser({ username, passwordHash: hash, role: 'student' }); res.json({ student: sanitizeStudent(user), defaultPassword: username }); } catch (err) { res.status(500).json({ error: err.message }); } }); export default router;