← back to Grant
app/api/news/route.ts
78 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { verifyAuthWithOrg, resolveOrgId } from '@/lib/auth';
/* ─── GET /api/news ───────────────────────────────────────────────────────── */
export async function GET(request: NextRequest) {
const session = verifyAuthWithOrg(request);
if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
try {
const url = new URL(request.url);
const search = url.searchParams.get('search');
const sourceType = url.searchParams.get('source_type');
const orgId = await resolveOrgId(session);
if (!orgId) return NextResponse.json({ rows: [] });
let sql = 'SELECT id, org_id, headline, outlet, url, published_at, summary, tags, relevance_score, author_name, source_type, created_at, updated_at FROM news_items WHERE org_id = $1';
const params: unknown[] = [orgId];
let paramIdx = 2;
if (search) {
sql += ` AND (headline ILIKE $${paramIdx} OR summary ILIKE $${paramIdx} OR outlet ILIKE $${paramIdx})`;
params.push(`%${search}%`);
paramIdx++;
}
if (sourceType && sourceType !== 'all') {
sql += ` AND source_type = $${paramIdx}`;
params.push(sourceType);
paramIdx++;
}
sql += ' ORDER BY published_at DESC NULLS LAST, created_at DESC';
const result = await query(sql, params);
return NextResponse.json({ rows: result.rows });
} catch (err) {
console.error('[news GET]', err);
return NextResponse.json({ error: 'Failed to fetch news' }, { status: 500 });
}
}
/* ─── POST /api/news ──────────────────────────────────────────────────────── */
export async function POST(request: NextRequest) {
const session = verifyAuthWithOrg(request);
if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
try {
const body = await request.json();
const orgId = await resolveOrgId(session);
if (!orgId) return NextResponse.json({ error: 'No organization found' }, { status: 400 });
const result = await query(
`INSERT INTO news_items (org_id, headline, outlet, url, published_at, summary, tags, relevance_score, author_name, source_type)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id, org_id, headline, outlet, url, published_at, summary, tags, relevance_score, author_name, source_type, created_at, updated_at`,
[
orgId,
body.headline,
body.outlet || null,
body.url || null,
body.published_at || null,
body.summary || null,
body.tags || [],
body.relevance_score || null,
body.author_name || null,
body.source_type || 'manual',
],
);
return NextResponse.json(result.rows[0], { status: 201 });
} catch (err) {
console.error('[news POST]', err);
return NextResponse.json({ error: 'Failed to create news item' }, { status: 500 });
}
}