릴리스: v0.1.12 작성 권한과 회원 관리 보강
This commit is contained in:
@@ -279,6 +279,27 @@ async function updateUserProfile({ id, nickname, avatarSrc }) {
|
||||
return findUserById(id)
|
||||
}
|
||||
|
||||
async function listUsers() {
|
||||
const rows = await query(
|
||||
'SELECT id, email, nickname, is_admin, avatar_src, created_at FROM users ORDER BY created_at ASC, email ASC'
|
||||
)
|
||||
return rows.map(mapUserRow)
|
||||
}
|
||||
|
||||
async function adminUpdateUser({ id, email, nickname, isAdmin }) {
|
||||
await query('UPDATE users SET email = ?, nickname = ?, is_admin = ? WHERE id = ?', [
|
||||
email,
|
||||
nickname || '',
|
||||
isAdmin ? 1 : 0,
|
||||
id,
|
||||
])
|
||||
return findUserById(id)
|
||||
}
|
||||
|
||||
async function adminDeleteUser(id) {
|
||||
await query('DELETE FROM users WHERE id = ?', [id])
|
||||
}
|
||||
|
||||
async function listGames() {
|
||||
const rows = await query(
|
||||
'SELECT id, name, thumbnail_src, created_at FROM games WHERE id <> ? ORDER BY created_at ASC, name ASC',
|
||||
@@ -516,6 +537,9 @@ module.exports = {
|
||||
findUserById,
|
||||
createUser,
|
||||
updateUserProfile,
|
||||
listUsers,
|
||||
adminUpdateUser,
|
||||
adminDeleteUser,
|
||||
listGames,
|
||||
findGameById,
|
||||
listGameItems,
|
||||
|
||||
@@ -4,6 +4,7 @@ const multer = require('multer')
|
||||
const { z } = require('zod')
|
||||
const { nanoid } = require('nanoid')
|
||||
const {
|
||||
findUserById,
|
||||
findGameById,
|
||||
createGame,
|
||||
updateGameThumbnail,
|
||||
@@ -11,6 +12,9 @@ const {
|
||||
deleteGameItem,
|
||||
deleteGame,
|
||||
listCustomItems,
|
||||
listUsers,
|
||||
adminUpdateUser,
|
||||
adminDeleteUser,
|
||||
} = require('../db')
|
||||
const { requireAdmin } = require('../middleware/auth')
|
||||
|
||||
@@ -83,4 +87,53 @@ router.get('/custom-items', requireAdmin, async (req, res) => {
|
||||
res.json({ items })
|
||||
})
|
||||
|
||||
router.get('/users', requireAdmin, async (req, res) => {
|
||||
const users = await listUsers()
|
||||
res.json({ users })
|
||||
})
|
||||
|
||||
router.patch('/users/:userId', requireAdmin, async (req, res) => {
|
||||
const schema = z.object({
|
||||
email: z.string().email(),
|
||||
nickname: z.string().trim().max(40).default(''),
|
||||
isAdmin: z.boolean(),
|
||||
})
|
||||
const parsed = schema.safeParse(req.body)
|
||||
if (!parsed.success) return res.status(400).json({ error: 'bad_request' })
|
||||
|
||||
if (req.params.userId === req.session.userId && !parsed.data.isAdmin) {
|
||||
return res.status(400).json({ error: 'self_admin_required' })
|
||||
}
|
||||
|
||||
const user = await findUserById(req.params.userId)
|
||||
if (!user) return res.status(404).json({ error: 'not_found' })
|
||||
|
||||
try {
|
||||
const updated = await adminUpdateUser({
|
||||
id: user.id,
|
||||
email: parsed.data.email,
|
||||
nickname: parsed.data.nickname,
|
||||
isAdmin: parsed.data.isAdmin,
|
||||
})
|
||||
res.json({ user: updated })
|
||||
} catch (e) {
|
||||
if (e && e.code === 'ER_DUP_ENTRY') {
|
||||
return res.status(409).json({ error: 'email_taken' })
|
||||
}
|
||||
throw e
|
||||
}
|
||||
})
|
||||
|
||||
router.delete('/users/:userId', requireAdmin, async (req, res) => {
|
||||
if (req.params.userId === req.session.userId) {
|
||||
return res.status(400).json({ error: 'cannot_delete_self' })
|
||||
}
|
||||
|
||||
const user = await findUserById(req.params.userId)
|
||||
if (!user) return res.status(404).json({ error: 'not_found' })
|
||||
|
||||
await adminDeleteUser(user.id)
|
||||
res.json({ ok: true })
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
||||
Reference in New Issue
Block a user