import { and, asc, eq, or } from 'drizzle-orm' import { Hono } from 'hono' import { z } from 'zod' import type { SavedView } from '../../shared/api-types.ts' import { hasRole } from '../../shared/enums.ts' import { savedViewSchema } from '../../shared/schemas.ts' import { requireAuth } from '../auth/middleware.ts' import { savedViews } from '../db/schema.ts' import { currentUser, fail, validate, type AppEnv } from '../lib/http.ts' const toView = (row: typeof savedViews.$inferSelect, userId: string): SavedView => ({ id: row.id, page: row.page as SavedView['page'], name: row.name, filters: row.filters, shared: row.shared, mine: row.userId === userId, }) /** Saved filter sets. Supervisors and above can share views with the whole organization. */ export const viewRoutes = new Hono() .get('/', requireAuth, validate('query', z.object({ page: z.enum(['analytics', 'incidents']) })), async (c) => { const me = currentUser(c) const rows = await c .get('db') .select() .from(savedViews) .where(and(eq(savedViews.organizationId, me.organizationId), eq(savedViews.page, c.req.valid('query').page), or(eq(savedViews.userId, me.id), eq(savedViews.shared, true)))) .orderBy(asc(savedViews.name)) return c.json({ views: rows.map((row) => toView(row, me.id)) }) }) .post('/', requireAuth, validate('json', savedViewSchema), async (c) => { const me = currentUser(c) const input = c.req.valid('json') if (input.shared && !hasRole(me.role, 'supervisor')) throw fail(403, 'Only supervisors and above can share views') const [row] = await c .get('db') .insert(savedViews) .values({ ...input, organizationId: me.organizationId, userId: me.id }) .returning() return c.json({ view: toView(row, me.id) }, 201) }) .delete('/:id', requireAuth, validate('param', z.object({ id: z.uuid() })), async (c) => { const me = currentUser(c) const db = c.get('db') const [row] = await db .select() .from(savedViews) .where(and(eq(savedViews.id, c.req.valid('param').id), eq(savedViews.organizationId, me.organizationId))) if (!row || (!row.shared && row.userId !== me.id)) throw fail(404, 'View not found') if (row.userId !== me.id && me.role !== 'admin') throw fail(403, 'Only the owner or an admin can delete this view') await db.delete(savedViews).where(eq(savedViews.id, row.id)) return c.body(null, 204) })