릴리스: v1.3.69 관리자 티어표 집계와 아이템 UI 정리

This commit is contained in:
2026-04-02 15:21:03 +09:00
parent a16b1e1025
commit badf250967
9 changed files with 140 additions and 72 deletions

View File

@@ -2026,6 +2026,50 @@ async function listAdminTierLists({ queryText = '', page = 1, limit = 50, curren
}
}
async function summarizeAdminTierLists({ queryText = '', gameId = '' } = {}) {
const hasQuery = !!(queryText || '').trim()
const hasGameId = !!(gameId || '').trim()
const search = `%${(queryText || '').trim()}%`
const whereParts = []
const params = []
if (hasGameId) {
whereParts.push('t.game_id = ?')
params.push((gameId || '').trim())
}
if (hasQuery) {
whereParts.push(`(
t.title LIKE ?
OR g.name LIKE ?
OR g.id LIKE ?
OR u.email LIKE ?
OR u.nickname LIKE ?
)`)
params.push(search, search, search, search, search)
}
const whereClause = whereParts.length ? `WHERE ${whereParts.join(' AND ')}` : ''
const rows = await query(
`
SELECT t.is_public
FROM tierlists t
INNER JOIN users u ON u.id = t.author_id
INNER JOIN games g ON g.id = t.game_id
${whereClause}
`,
params
)
const total = rows.length
const publicCount = rows.filter((row) => Number(row.is_public) === 1).length
return {
total,
publicCount,
privateCount: Math.max(0, total - publicCount),
}
}
async function findTierListById(id, currentUserId = '') {
const rows = await query(
`
@@ -2408,6 +2452,7 @@ module.exports = {
listFavoriteTierLists,
listUserTierLists,
listAdminTierLists,
summarizeAdminTierLists,
findTierListById,
favoriteTierList,
unfavoriteTierList,

View File

@@ -31,6 +31,7 @@ const {
listUsers,
findPrimaryAdminUser,
listAdminTierLists,
summarizeAdminTierLists,
findTierListById,
listAdminTemplateRequests,
findTemplateRequestById,
@@ -310,6 +311,21 @@ router.get('/tierlists', requireAdmin, async (req, res) => {
res.json(result)
})
router.get('/tierlists/stats', requireAdmin, async (req, res) => {
const schema = z.object({
q: z.string().trim().max(120).optional().default(''),
gameId: z.string().trim().max(120).optional().default(''),
})
const parsed = schema.safeParse(req.query)
if (!parsed.success) return res.status(400).json({ error: 'bad_request' })
const result = await summarizeAdminTierLists({
queryText: parsed.data.q,
gameId: parsed.data.gameId,
})
res.json(result)
})
router.get('/template-requests', requireAdmin, async (req, res) => {
const requests = await listAdminTemplateRequests({ statuses: ['pending', 'reviewing'] })
res.json({ requests })