← back to Norma

app/api/grants/[id]/proposals/[pid]/send/route.ts

99 lines

import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { auditLog } from '@/lib/audit';
import { getBrand } from '@/lib/brand';
import { getOrgId } from '@/lib/orgId';

type Params = Promise<{ id: string; pid: string }>;

/**
 * POST /api/grants/[id]/proposals/[pid]/send
 * Send the proposal via email (through George Gmail proxy or direct SMTP).
 */
export async function POST(request: NextRequest, { params }: { params: Params }) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  const { pid } = await params;

  try {
    // Fetch proposal
    const result = await query(`SELECT * FROM grant_proposals WHERE id = $1`, [pid]);
    if (result.rows.length === 0) {
      return NextResponse.json({ error: 'Proposal not found' }, { status: 404 });
    }
    const proposal = result.rows[0];

    if (!proposal.recipient_email) {
      return NextResponse.json({ error: 'Recipient email is required before sending' }, { status: 400 });
    }

    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
    const brand = await getBrand(orgId ?? undefined);

    // Try George Gmail agent first
    const georgeUrl = process.env.GEORGE_URL;
    const georgeAuth = process.env.GEORGE_AUTH;
    let sent = false;

    if (georgeUrl && georgeAuth) {
      try {
        const authHeader = 'Basic ' + Buffer.from(georgeAuth).toString('base64');
        const georgeRes = await fetch(`${georgeUrl}/api/send`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            Authorization: authHeader,
          },
          body: JSON.stringify({
            to: proposal.recipient_email,
            subject: proposal.subject,
            html: proposal.body_html,
            from_name: brand.name,
          }),
        });

        if (georgeRes.ok) {
          sent = true;
        } else {
          console.warn('[proposal/send] George agent failed:', georgeRes.status);
        }
      } catch (err) {
        console.warn('[proposal/send] George agent unreachable:', (err as Error).message);
      }
    }

    // Fallback: SMTP if configured
    if (!sent && process.env.SMTP_HOST) {
      // Nodemailer would go here — for now, flag as needing Gmail integration
      return NextResponse.json({
        error: 'Email sending requires Gmail integration. Use Export PDF to submit manually.',
      }, { status: 503 });
    }

    if (!sent) {
      return NextResponse.json({
        error: 'Email sending is not configured yet. Gmail integration is needed. Use Export PDF instead.',
      }, { status: 503 });
    }

    // Update proposal status
    await query(
      `UPDATE grant_proposals SET status = 'sent', sent_at = NOW() WHERE id = $1`,
      [pid],
    );

    const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || undefined;
    await auditLog('proposal.sent', 'grant_proposal', pid, {
      to: proposal.recipient_email,
      subject: proposal.subject,
    }, ip);

    return NextResponse.json({ success: true, message: 'Proposal sent successfully' });
  } catch (err) {
    console.error('[proposal/send] error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to send proposal' }, { status: 500 });
  }
}