- Login now uses username instead of email - DB migration renames email -> username on existing databases - Users can change their own password from the Stories page - Admin can reset any user's password from the admin panel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
47 lines
1.5 KiB
JavaScript
47 lines
1.5 KiB
JavaScript
import { Router } from 'express'
|
|
import bcrypt from 'bcryptjs'
|
|
import db from '../db.js'
|
|
import { adminAuth } from '../middleware/auth.js'
|
|
|
|
const router = Router()
|
|
router.use(adminAuth)
|
|
|
|
router.get('/users', (req, res) => {
|
|
const users = db.prepare(
|
|
'SELECT id, name, username, created_at FROM users ORDER BY created_at DESC'
|
|
).all()
|
|
res.json(users)
|
|
})
|
|
|
|
router.post('/users', (req, res) => {
|
|
const { name, username, password } = req.body || {}
|
|
if (!name || !username || !password)
|
|
return res.status(400).json({ error: 'Name, username, and password are all required' })
|
|
|
|
try {
|
|
const hash = bcrypt.hashSync(password, 10)
|
|
const { lastInsertRowid } = db.prepare(
|
|
'INSERT INTO users (name, username, password) VALUES (?, ?, ?)'
|
|
).run(name, username.toLowerCase(), hash)
|
|
res.json({ id: lastInsertRowid, name, username })
|
|
} catch {
|
|
res.status(400).json({ error: 'That username is already taken' })
|
|
}
|
|
})
|
|
|
|
router.put('/users/:id/password', (req, res) => {
|
|
const { password } = req.body || {}
|
|
if (!password) return res.status(400).json({ error: 'Password required' })
|
|
if (password.length < 6) return res.status(400).json({ error: 'Password must be at least 6 characters' })
|
|
|
|
db.prepare('UPDATE users SET password = ? WHERE id = ?').run(bcrypt.hashSync(password, 10), req.params.id)
|
|
res.json({ ok: true })
|
|
})
|
|
|
|
router.delete('/users/:id', (req, res) => {
|
|
db.prepare('DELETE FROM users WHERE id = ?').run(req.params.id)
|
|
res.json({ ok: true })
|
|
})
|
|
|
|
export default router
|