/opt/canhelp/apps/api/src/routes
Edit: /opt/canhelp/apps/api/src/routes/reports.ts (2007B)
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
import { eq, desc, count } from 'drizzle-orm'
import { db } from '../db.js'
import { reports } from '@canhelp/db'
import { requireAuth, requireAdmin, type AuthVariables } from '../middleware/auth.js'
const app = new Hono<{ Variables: AuthVariables }>()
// POST /reports
app.post(
'/',
requireAuth,
zValidator(
'json',
z.object({
targetType: z.enum(['task', 'user']),
targetId: z.string(),
reason: z.enum(['spam', 'inappropriate', 'fraud', 'duplicate', 'other']),
description: z.string().max(2000).optional(),
}),
),
async (c) => {
const user = c.get('user')
const body = c.req.valid('json')
const [report] = await db
.insert(reports)
.values({
reporterId: user.id,
...body,
})
.returning()
return c.json(report, 201)
},
)
// GET /reports — admin only
app.get('/', requireAdmin, async (c) => {
const page = Number(c.req.query('page') || 1)
const limit = Math.min(Number(c.req.query('limit') || 20), 100)
const offset = (page - 1) * limit
const rows = await db
.select()
.from(reports)
.where(eq(reports.status, 'pending'))
.orderBy(desc(reports.createdAt))
.limit(limit)
.offset(offset)
const [{ total }] = await db
.select({ total: count() })
.from(reports)
.where(eq(reports.status, 'pending'))
return c.json({ data: rows, total, page, limit })
})
// PATCH /reports/:id/status — admin only
app.patch(
'/:id/status',
requireAdmin,
zValidator('json', z.object({ status: z.enum(['reviewed', 'dismissed']) })),
async (c) => {
const body = c.req.valid('json')
const [updated] = await db
.update(reports)
.set({ status: body.status })
.where(eq(reports.id, c.req.param('id')))
.returning()
if (!updated) return c.json({ error: 'Not found' }, 404)
return c.json(updated)
},
)
export default app