import type { FastifyPluginAsync } from 'fastify'; import { z } from 'zod'; import { prisma } from '../db.js'; import { requireAuth } from '../plugins/session.js'; export const directoryRoutes: FastifyPluginAsync = async (app) => { // Public route to list companies app.get('/api/v1/directory/companies', async (req) => { const companies = await prisma.companyProfile.findMany({ orderBy: { name: 'asc' }, include: { claims: { where: { status: 'approved' }, include: { user: { select: { name: true } } } } } }); return { companies }; }); app.get('/api/v1/directory/companies/:slug', async (req, reply) => { const { slug } = req.params as { slug: string }; const company = await prisma.companyProfile.findUnique({ where: { slug }, include: { claims: { where: { status: 'approved' }, include: { user: { select: { name: true, username: true } } } } } }); if (!company) return reply.code(404).send({ error: 'not_found' }); return { company }; }); // Authenticated route to claim a company app.register(async (authApp) => { authApp.addHook('preHandler', requireAuth()); authApp.post('/api/v1/directory/companies/:companyId/claim', async (req, reply) => { const { companyId } = req.params as { companyId: string }; const schema = z.object({ documentsUrl: z.string().url().optional() }); const parsed = schema.safeParse(req.body); if (!parsed.success) return reply.code(400).send({ error: 'invalid_input' }); const company = await prisma.companyProfile.findUnique({ where: { id: companyId } }); if (!company) return reply.code(404).send({ error: 'not_found' }); const claim = await prisma.companyClaim.create({ data: { companyId, userId: req.session!.userId, documentsUrl: parsed.data.documentsUrl, } }); return { success: true, claim }; }); }); // Admin routes app.register(async (adminApp) => { adminApp.addHook('preHandler', async (req, reply) => { if (req.session?.role !== 'admin' && req.session?.role !== 'editor') { return reply.code(403).send({ error: 'forbidden' }); } }); adminApp.get('/api/v1/admin/directory/claims', async () => { const claims = await prisma.companyClaim.findMany({ where: { status: 'pending' }, include: { company: true, user: { select: { name: true, email: true } } }, orderBy: { createdAt: 'desc' } }); return { claims }; }); adminApp.patch('/api/v1/admin/directory/claims/:id', async (req, reply) => { const { id } = req.params as { id: string }; const parsed = z.object({ status: z.enum(['approved', 'rejected']) }).safeParse(req.body); if (!parsed.success) return reply.code(400).send({ error: 'invalid_input' }); const claim = await prisma.companyClaim.update({ where: { id }, data: { status: parsed.data.status, reviewedById: req.session!.userId } }); return { success: true, claim }; }); }); };