← back to Norma
app/api/settings/news-watch-people/route.ts
133 lines
import { NextRequest, NextResponse } from 'next/server';
import { requireRole } from '@/lib/require-role';
import { query } from '@/lib/db';
import { getOrgId } from '@/lib/orgId';
import { auditLog } from '@/lib/audit';
interface WatchPerson {
id: number;
org_id: string | null;
person_name: string;
title: string | null;
keywords: string[] | null;
is_active: boolean;
created_at: string;
}
/**
* GET /api/settings/news-watch-people — List all watch people for the org
*/
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;
const result = await query<WatchPerson>(
`SELECT id, org_id, person_name, title, keywords, is_active, created_at
FROM news_watch_people
WHERE ($1::uuid IS NULL OR org_id = $1::uuid)
ORDER BY created_at DESC`,
[orgId],
);
return NextResponse.json({ people: result.rows });
}
/**
* POST /api/settings/news-watch-people — Add a new watch person
*/
export async function POST(request: NextRequest) {
const auth = requireRole(request, 'admin');
if (auth instanceof NextResponse) return auth;
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
const body = await request.json();
const personName = (body.person_name || '').trim();
if (!personName) {
return NextResponse.json({ error: 'person_name is required' }, { status: 400 });
}
const title = (body.title || '').trim() || null;
const keywords: string[] = Array.isArray(body.keywords)
? body.keywords.filter((k: string) => typeof k === 'string' && k.trim())
: [];
const result = await query<WatchPerson>(
`INSERT INTO news_watch_people (org_id, person_name, title, keywords)
VALUES ($1, $2, $3, $4)
RETURNING *`,
[orgId, personName, title, keywords.length > 0 ? keywords : null],
);
await auditLog('news_watch_people.created', 'news_watch_people', String(result.rows[0].id), {
person_name: personName,
org_id: orgId,
});
return NextResponse.json({ person: result.rows[0] }, { status: 201 });
}
/**
* PATCH /api/settings/news-watch-people — Toggle active/inactive
* Body: { id: number, is_active: boolean }
*/
export async function PATCH(request: NextRequest) {
const auth = requireRole(request, 'admin');
if (auth instanceof NextResponse) return auth;
const body = await request.json();
const { id, is_active } = body;
if (typeof id !== 'number' || typeof is_active !== 'boolean') {
return NextResponse.json({ error: 'id (number) and is_active (boolean) required' }, { status: 400 });
}
const result = await query<WatchPerson>(
`UPDATE news_watch_people SET is_active = $1 WHERE id = $2 RETURNING *`,
[is_active, id],
);
if (result.rowCount === 0) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
await auditLog('news_watch_people.toggled', 'news_watch_people', String(id), {
is_active,
});
return NextResponse.json({ person: result.rows[0] });
}
/**
* DELETE /api/settings/news-watch-people — Remove a watch person
* Body: { id: number }
*/
export async function DELETE(request: NextRequest) {
const auth = requireRole(request, 'admin');
if (auth instanceof NextResponse) return auth;
const body = await request.json();
const { id } = body;
if (typeof id !== 'number') {
return NextResponse.json({ error: 'id (number) required' }, { status: 400 });
}
const result = await query(
`DELETE FROM news_watch_people WHERE id = $1 RETURNING person_name`,
[id],
);
if (result.rowCount === 0) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
await auditLog('news_watch_people.deleted', 'news_watch_people', String(id), {
person_name: result.rows[0].person_name,
});
return NextResponse.json({ success: true });
}