← back to Norma

app/api/social/posts/approve/route.ts

109 lines

import { NextRequest, NextResponse } from 'next/server';
import { query, getClient } from '@/lib/db';

export const dynamic = 'force-dynamic';

/**
 * POST /api/social/posts/approve
 * Body: { post_id, action: 'approve'|'reject', approver, reason?, scheduled_at? }
 */
export async function POST(request: NextRequest) {
  let body: {
    post_id?: string;
    action?: 'approve' | 'reject';
    approver?: string;
    reason?: string;
    scheduled_at?: string;
  };
  try {
    body = await request.json();
  } catch {
    return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 });
  }

  const { post_id, action, approver, reason, scheduled_at } = body;

  if (!post_id || !action || !approver) {
    return NextResponse.json(
      { error: 'post_id, action, and approver are required' },
      { status: 400 },
    );
  }
  if (action !== 'approve' && action !== 'reject') {
    return NextResponse.json(
      { error: "action must be 'approve' or 'reject'" },
      { status: 400 },
    );
  }

  const client = await getClient();
  try {
    await client.query('BEGIN');

    if (action === 'approve') {
      const newStatus = scheduled_at ? 'scheduled' : 'draft';
      const updateResult = await client.query(
        `UPDATE social_posts
         SET status = $1,
             approved_by = $2,
             approved_at = NOW(),
             rejection_reason = NULL,
             updated_at = NOW()
         WHERE id = $3
         RETURNING *`,
        [newStatus, approver, post_id],
      );

      if (updateResult.rowCount === 0) {
        await client.query('ROLLBACK');
        return NextResponse.json({ error: 'Post not found' }, { status: 404 });
      }

      if (scheduled_at) {
        await client.query(
          `INSERT INTO social_schedule (post_id, scheduled_at, status, next_run_at)
           VALUES ($1, $2, 'pending', $2)`,
          [post_id, scheduled_at],
        );
      }

      await client.query('COMMIT');
      return NextResponse.json({ post: updateResult.rows[0] });
    }

    // reject
    const updateResult = await client.query(
      `UPDATE social_posts
       SET status = 'draft',
           rejection_reason = $1,
           approved_by = $2,
           approved_at = NOW(),
           updated_at = NOW()
       WHERE id = $3
       RETURNING *`,
      [reason ?? null, approver, post_id],
    );

    if (updateResult.rowCount === 0) {
      await client.query('ROLLBACK');
      return NextResponse.json({ error: 'Post not found' }, { status: 404 });
    }

    await client.query('COMMIT');
    return NextResponse.json({ post: updateResult.rows[0] });
  } catch (err) {
    try {
      await client.query('ROLLBACK');
    } catch {
      /* ignore rollback error */
    }
    console.error('[posts/approve] error:', (err as Error).message);
    return NextResponse.json(
      { error: 'Failed to process approval' },
      { status: 500 },
    );
  } finally {
    client.release();
  }
}