← 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 });
  }
}