← back to Norma
app/api/email-analyzer/drafts/route.ts
178 lines
/**
* GET /api/email-analyzer/drafts — list recent analyzer sessions (grouped by session_id)
* POST /api/email-analyzer/drafts — save a new version
* DELETE /api/email-analyzer/drafts?session_id=X — delete ALL versions of a session
*/
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { getOrgId } from '@/lib/orgId';
export async function GET(request: NextRequest) {
const auth = requireRole(request, 'admin', 'staff');
if (auth instanceof NextResponse) return auth;
try {
const { searchParams } = new URL(request.url);
const sessionId = searchParams.get('session_id');
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
let limitParam = parseInt(searchParams.get('limit') || '20', 10);
if (isNaN(limitParam) || limitParam < 1) limitParam = 20;
if (limitParam > 100) limitParam = 100;
if (sessionId) {
// Get all versions for a specific session
const conditions: string[] = ['session_id = $1'];
const values: unknown[] = [sessionId];
let paramIdx = 2;
if (orgId) {
conditions.push(`org_id = $${paramIdx}`);
values.push(orgId);
paramIdx++;
}
const result = await query(
`SELECT * FROM email_analyzer_drafts
WHERE ${conditions.join(' AND ')}
ORDER BY version_number ASC`,
values,
);
return NextResponse.json({ drafts: result.rows });
}
// List recent sessions (latest version per session)
const conditions: string[] = [];
const values: unknown[] = [];
let paramIdx = 1;
if (orgId) {
conditions.push(`org_id = $${paramIdx}`);
values.push(orgId);
paramIdx++;
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
const result = await query(
`SELECT DISTINCT ON (session_id)
id, org_id, session_id, version_number, label, tone,
paragraph_count, word_count, created_by, created_at,
LEFT(original_email, 200) AS original_preview
FROM email_analyzer_drafts
${whereClause}
ORDER BY session_id, version_number DESC`,
values,
);
// Sort by created_at DESC and limit
const sorted = result.rows
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
.slice(0, limitParam);
return NextResponse.json({ sessions: sorted });
} catch (err) {
console.error('[email-analyzer/drafts] GET error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to fetch analyzer drafts' }, { status: 500 });
}
}
export async function POST(request: NextRequest) {
const auth = requireRole(request, 'admin', 'staff');
if (auth instanceof NextResponse) return auth;
try {
const body = await request.json();
const {
originalEmail,
currentVersion,
versionNumber,
label,
tone,
paragraphCount,
wordCount,
chatHistory,
sessionId,
isFavorite,
notes,
subjectLine,
score,
} = body;
if (!originalEmail || !currentVersion || !sessionId) {
return NextResponse.json(
{ error: 'originalEmail, currentVersion, and sessionId are required' },
{ status: 400 },
);
}
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
const result = await query(
`INSERT INTO email_analyzer_drafts
(org_id, original_email, current_version, version_number, label, tone,
paragraph_count, word_count, chat_history, session_id, created_by,
is_favorite, notes, subject_line, score)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
RETURNING *`,
[
orgId,
originalEmail,
currentVersion,
versionNumber || 1,
label || null,
tone || null,
paragraphCount || null,
wordCount || null,
JSON.stringify(chatHistory || []),
sessionId,
auth.username,
Boolean(isFavorite),
notes || null,
subjectLine || null,
typeof score === 'number' ? Math.max(0, Math.min(100, Math.round(score))) : null,
],
);
return NextResponse.json({ draft: result.rows[0] }, { status: 201 });
} catch (err) {
console.error('[email-analyzer/drafts] POST error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to save analyzer draft' }, { status: 500 });
}
}
export async function DELETE(request: NextRequest) {
const auth = requireRole(request, 'admin', 'staff');
if (auth instanceof NextResponse) return auth;
try {
const { searchParams } = new URL(request.url);
const sessionId = searchParams.get('session_id');
if (!sessionId) {
return NextResponse.json({ error: 'session_id is required' }, { status: 400 });
}
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
const conditions: string[] = ['session_id = $1'];
const values: unknown[] = [sessionId];
if (orgId) {
conditions.push('org_id = $2');
values.push(orgId);
}
const result = await query(
`DELETE FROM email_analyzer_drafts WHERE ${conditions.join(' AND ')} RETURNING id`,
values,
);
return NextResponse.json({ deleted: result.rows.length });
} catch (err) {
console.error('[email-analyzer/drafts] DELETE error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to delete analyzer session' }, { status: 500 });
}
}