← back to Norma

app/api/gmail/contacts/route.ts

73 lines

import { NextRequest, NextResponse } from 'next/server';
import { requireRole } from '@/lib/require-role';
import { query } from '@/lib/db';

export async function GET(req: NextRequest) {
  const auth = requireRole(req, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;
  const sp = req.nextUrl.searchParams;
  const type = sp.get('type') || 'all'; // journalists, congress, organizations, all
  const search = sp.get('q') || '';
  const state = sp.get('state') || '';
  const party = sp.get('party') || '';
  const limit = Math.min(parseInt(sp.get('limit') || '100'), 500);

  const results: Record<string, unknown[]> = {};
  const searchFilter = search ? `%${search}%` : null;

  // Journalists
  if (type === 'all' || type === 'journalists') {
    let jSql = `SELECT id, name, outlet, beat, email, twitter_handle, photo_url, tags, bio, is_active FROM journalists WHERE is_active = true`;
    const jParams: unknown[] = [];
    if (searchFilter) {
      jParams.push(searchFilter, searchFilter, searchFilter);
      jSql += ` AND (name ILIKE $1 OR outlet ILIKE $2 OR beat ILIKE $3)`;
    }
    jSql += ` ORDER BY name LIMIT ${limit}`;
    const jRes = await query(jSql, jParams);
    results.journalists = jRes.rows;
  }

  // Congress / Politicians
  if (type === 'all' || type === 'congress') {
    let pSql = `SELECT id, name, title, party, state, district, office_level, phone, email, website, photo_url, committees, position_student_debt, seniority FROM politicians WHERE 1=1`;
    const pParams: unknown[] = [];
    let pi = 1;
    if (searchFilter) {
      pSql += ` AND (name ILIKE $${pi} OR state ILIKE $${pi + 1} OR title ILIKE $${pi + 2})`;
      pParams.push(searchFilter, searchFilter, searchFilter);
      pi += 3;
    }
    if (state) {
      pSql += ` AND state = $${pi}`;
      pParams.push(state);
      pi++;
    }
    if (party) {
      pSql += ` AND party = $${pi}`;
      pParams.push(party);
      pi++;
    }
    pSql += ` ORDER BY office_level, state, name LIMIT ${limit}`;
    const pRes = await query(pSql, pParams);
    results.congress = pRes.rows;
  }

  // Organizations
  if (type === 'all' || type === 'organizations') {
    let oSql = `SELECT id, name, type, category, state, city, email, phone, website, description FROM organizations WHERE 1=1`;
    const oParams: unknown[] = [];
    let oi = 1;
    if (searchFilter) {
      oSql += ` AND (name ILIKE $${oi} OR category ILIKE $${oi + 1} OR state ILIKE $${oi + 2})`;
      oParams.push(searchFilter, searchFilter, searchFilter);
      oi += 3;
    }
    oSql += ` ORDER BY name LIMIT ${limit}`;
    const oRes = await query(oSql, oParams);
    results.organizations = oRes.rows;
  }

  return NextResponse.json(results);
}