← back to Norma
app/api/news/tags/route.ts
76 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { getOrgId } from '@/lib/orgId';
/**
* GET /api/news/tags
* Returns distinct tags with article counts, sorted by frequency (most common first).
*
* Optional query params:
* ?date_range=month — scope counts to a date window
* ?outlet=CNN — scope counts to a specific outlet
*
* Response: { tags: [{ tag: string, count: number }] }
*/
export async function GET(request: NextRequest) {
const auth = requireRole(request, 'admin', 'staff');
if (auth instanceof NextResponse) return auth;
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
try {
const { searchParams } = new URL(request.url);
const dateRange = searchParams.get('date_range');
const outlet = searchParams.get('outlet');
const conditions: string[] = ['tags IS NOT NULL', "array_length(tags, 1) > 0"];
const values: unknown[] = [];
let paramIndex = 1;
if (orgId) {
conditions.push(`org_id = $${paramIndex}`);
values.push(orgId);
paramIndex++;
}
// Date range filter to scope tag counts
if (dateRange === 'today') {
conditions.push(`published_at >= CURRENT_DATE`);
} else if (dateRange === 'week') {
conditions.push(`published_at >= CURRENT_DATE - INTERVAL '7 days'`);
} else if (dateRange === 'month') {
conditions.push(`published_at >= CURRENT_DATE - INTERVAL '30 days'`);
} else if (dateRange === '3months') {
conditions.push(`published_at >= CURRENT_DATE - INTERVAL '90 days'`);
} else if (dateRange === '6months') {
conditions.push(`published_at >= CURRENT_DATE - INTERVAL '180 days'`);
}
if (outlet) {
conditions.push(`outlet = $${paramIndex}`);
values.push(outlet);
paramIndex++;
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
const result = await query(
`SELECT tag, COUNT(*)::int AS count
FROM (
SELECT unnest(tags) AS tag
FROM news_items
${whereClause}
) sub
GROUP BY tag
ORDER BY count DESC, tag ASC`,
values
);
return NextResponse.json({ tags: result.rows });
} catch (err) {
console.error('[api/news/tags] GET error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to fetch tags' }, { status: 500 });
}
}