/** * AppGate sync API * * POST /api/appgate/sync — trigger a sync (body: { syncType, triggeredBy }) * GET /api/appgate/sync — last-sync status + record counts * * No auth gate: webhook-style entrypoint hit by the in-process scheduler * (same pattern as `/api/qbo/sync`). Make sure it's listed in * `middleware.ts`'s public path array. */ import { NextRequest, NextResponse } from 'next/server'; import postgresClient from '@/lib/services/postgres-client'; import { getAppgateSyncService } from '@/lib/services/appgate-sync-service'; import { isAppgateConfigured } from '@/lib/services/appgate-factory'; export async function POST(request: NextRequest) { try { if (!isAppgateConfigured()) { return NextResponse.json( { error: 'AppGate not configured — set APPGATE_URL/USERNAME/PASSWORD/DEVICE_ID env vars' }, { status: 503 }, ); } const body = await request.json().catch(() => ({})); const syncType: 'sessions' | 'daily' = body.syncType === 'daily' ? 'daily' : 'sessions'; const triggeredBy = typeof body.triggeredBy === 'string' ? body.triggeredBy : 'api'; const svc = getAppgateSyncService(); if (svc.isSyncInProgress()) { return NextResponse.json({ error: 'AppGate sync already in progress' }, { status: 409 }); } (syncType === 'daily' ? svc.dailySync(triggeredBy) : svc.sessionsSync(triggeredBy)) .catch((e) => console.error('[AppgateSync API] sync failed:', e)); return NextResponse.json({ message: `AppGate ${syncType} sync started`, triggeredBy }); } catch (err) { const msg = err instanceof Error ? err.message : String(err); return NextResponse.json({ error: msg }, { status: 500 }); } } export async function GET() { try { const [sessions, devices, appliances, licenseUsers, snapshots, lastSync] = await Promise.all([ postgresClient.query<{ count: string }>(`SELECT COUNT(*)::text as count FROM appgate_active_sessions`), postgresClient.query<{ count: string; deleted: string }>( `SELECT COUNT(*) FILTER (WHERE is_deleted=false)::text as count, COUNT(*) FILTER (WHERE is_deleted=true)::text as deleted FROM appgate_devices`), postgresClient.query<{ count: string }>(`SELECT COUNT(*) FILTER (WHERE is_deleted=false)::text as count FROM appgate_appliances`), postgresClient.query<{ count: string }>(`SELECT COUNT(*)::text as count FROM appgate_license_users`), postgresClient.query<{ snapshot_date: string; max_users: number; used_users: number; expiration: string | null }>( `SELECT snapshot_date, max_users, used_users, expiration FROM appgate_license_snapshots ORDER BY snapshot_date DESC LIMIT 1`), postgresClient.query<{ sync_id: string; sync_type: string; status: string; started_at: string; completed_at: string | null; last_error: string | null; }>( `SELECT sync_id, sync_type, status, started_at, completed_at, last_error FROM appgate_sync_history ORDER BY started_at DESC LIMIT 1`), ]); return NextResponse.json({ configured: isAppgateConfigured(), counts: { active_sessions: parseInt(sessions.rows[0]?.count ?? '0', 10), devices: parseInt(devices.rows[0]?.count ?? '0', 10), devices_tombstoned: parseInt(devices.rows[0]?.deleted ?? '0', 10), appliances: parseInt(appliances.rows[0]?.count ?? '0', 10), license_users: parseInt(licenseUsers.rows[0]?.count ?? '0', 10), }, latest_license: snapshots.rows[0] ?? null, last_sync: lastSync.rows[0] ?? null, }); } catch (err) { const msg = err instanceof Error ? err.message : String(err); return NextResponse.json({ error: msg }, { status: 500 }); } }