← back to Norma

app/api/settings/route.ts

91 lines

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

/**
 * GET /api/settings
 * Return all app settings as a merged object.
 */
export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin');
  if (auth instanceof NextResponse) return auth;

  try {
    const result = await query(`SELECT key, value FROM app_settings ORDER BY key`);

    const settings: Record<string, unknown> = {};
    for (const row of result.rows) {
      settings[row.key] = row.value;
    }

    // Also get data stats (scoped by org where possible)
    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
    const statsQueries = await Promise.all([
      query(`SELECT COUNT(*)::int AS count FROM drafts WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
      query(`SELECT COUNT(*)::int AS count FROM news_items WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
      query(`SELECT COUNT(*)::int AS count FROM collaborations WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
      query(`SELECT COUNT(*)::int AS count FROM partners WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
      query(`SELECT COUNT(*)::int AS count FROM old_leads WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
    ]);

    settings.data_stats = {
      total_drafts: statsQueries[0].rows[0]?.count || 0,
      total_news: statsQueries[1].rows[0]?.count || 0,
      total_collaborations: statsQueries[2].rows[0]?.count || 0,
      total_partners: statsQueries[3].rows[0]?.count || 0,
      total_leads: statsQueries[4].rows[0]?.count || 0,
      last_backup: new Date().toISOString(),
    };

    return NextResponse.json({ settings });
  } catch (err) {
    console.error('[api/settings] GET error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to fetch settings' }, { status: 500 });
  }
}

/**
 * PATCH /api/settings
 * Update one or more settings sections.
 * Body: { org_profile?: {...}, email_config?: {...}, ai_config?: {...}, integrations?: {...} }
 */
export async function PATCH(request: NextRequest) {
  const auth = requireRole(request, 'admin');
  if (auth instanceof NextResponse) return auth;

  try {
    const body = await request.json();
    const allowedKeys = ['org_profile', 'email_config', 'ai_config', 'integrations', 'alert_preferences'];
    let updated = 0;

    for (const key of allowedKeys) {
      if (key in body && body[key] !== undefined) {
        await query(
          `INSERT INTO app_settings (key, value, updated_at)
           VALUES ($1, $2, now())
           ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = now()`,
          [key, JSON.stringify(body[key])]
        );
        updated++;
      }
    }

    if (updated === 0) {
      return NextResponse.json({ error: 'No valid settings to update' }, { status: 400 });
    }

    // Re-fetch all settings
    const result = await query(`SELECT key, value FROM app_settings ORDER BY key`);
    const settings: Record<string, unknown> = {};
    for (const row of result.rows) {
      settings[row.key] = row.value;
    }

    return NextResponse.json({ settings, updated });
  } catch (err) {
    console.error('[api/settings] PATCH error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to update settings' }, { status: 500 });
  }
}