← back to Norma

app/api/social/posts/route.ts

141 lines

import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';

/**
 * GET /api/social/posts?limit=20&status=draft&platform=twitter
 * Returns social posts, newest first.
 */
export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  const { searchParams } = new URL(request.url);
  const limit = Math.min(parseInt(searchParams.get('limit') || '50', 10), 200);
  const status = searchParams.get('status');
  const platform = searchParams.get('platform');

  const conditions: string[] = [];
  const values: unknown[] = [];
  let idx = 1;

  if (status) {
    conditions.push(`p.status = $${idx++}`);
    values.push(status);
  }
  if (platform) {
    conditions.push(`p.platform = $${idx++}`);
    values.push(platform);
  }

  const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

  const result = await query(
    `SELECT p.*, a.account_name, a.display_name
     FROM social_posts p
     LEFT JOIN social_accounts a ON p.account_id = a.id
     ${where}
     ORDER BY p.created_at DESC
     LIMIT $${idx}`,
    [...values, limit]
  );

  return NextResponse.json({ posts: result.rows, count: result.rows.length });
}

/**
 * POST /api/social/posts
 * Create a new social post (draft by default).
 */
export async function POST(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  const body = await request.json();
  const {
    platforms = [],
    post_type = 'post',
    body: postBody,
    link_url,
    hashtags = [],
    mentions = [],
    media_urls = [],
    cross_post_group,
  } = body;

  if (!postBody || platforms.length === 0) {
    return NextResponse.json({ error: 'body and platforms[] required' }, { status: 400 });
  }

  // Get account IDs for each platform
  const accountResult = await query(
    `SELECT id, platform FROM social_accounts WHERE platform = ANY($1) AND status = 'connected'`,
    [platforms]
  );

  const accountMap = new Map(accountResult.rows.map((r: { id: string; platform: string }) => [r.platform, r.id]));
  const groupId = cross_post_group || (platforms.length > 1 ? crypto.randomUUID() : null);

  const created: unknown[] = [];

  for (const platform of platforms) {
    const accountId = accountMap.get(platform);
    if (!accountId) continue;

    const result = await query(
      `INSERT INTO social_posts
         (account_id, platform, post_type, body, link_url, hashtags, mentions, media_urls, cross_post_group, status)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, 'draft')
       RETURNING *`,
      [accountId, platform, post_type, postBody, link_url || null, hashtags, mentions, JSON.stringify(media_urls), groupId]
    );
    created.push(result.rows[0]);
  }

  return NextResponse.json({ posts: created, count: created.length });
}

/**
 * PATCH /api/social/posts
 * Update a post (edit body, status, etc.)
 */
export async function PATCH(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  const { id, body: postBody, status, hashtags, link_url } = await request.json();
  if (!id) return NextResponse.json({ error: 'id required' }, { status: 400 });

  const sets: string[] = ['updated_at = NOW()'];
  const values: unknown[] = [];
  let idx = 1;

  if (postBody !== undefined) { sets.push(`body = $${idx++}`); values.push(postBody); }
  if (status !== undefined) { sets.push(`status = $${idx++}`); values.push(status); }
  if (hashtags !== undefined) { sets.push(`hashtags = $${idx++}`); values.push(hashtags); }
  if (link_url !== undefined) { sets.push(`link_url = $${idx++}`); values.push(link_url); }

  values.push(id);
  const result = await query(
    `UPDATE social_posts SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`,
    values
  );

  return NextResponse.json({ post: result.rows[0] });
}

/**
 * DELETE /api/social/posts
 * Delete a draft post.
 */
export async function DELETE(request: NextRequest) {
  const auth = requireRole(request, 'admin');
  if (auth instanceof NextResponse) return auth;

  const { id } = await request.json();
  if (!id) return NextResponse.json({ error: 'id required' }, { status: 400 });

  await query(`DELETE FROM social_posts WHERE id = $1 AND status = 'draft'`, [id]);
  return NextResponse.json({ deleted: true });
}