- Added Duo card to sync overview grid (category: 2FA/MFA, green) - Shows accounts, users, phones, auth logs counts + bypass/disabled warning - Created /admin/sync/duo detail page with: - Stat cards (accounts, users, phones, auth logs, groups, integrations) - Parent account summary - Child accounts table with user counts, matched company, sync time - Sync Now button with polling for completion - Created GET /api/duo/status endpoint (counts + last sync + bypass count) - Added duo.ico logo
42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { postgresClient } from '@/lib/services/postgres-client';
|
|
import { duoSyncService } from '@/lib/services/duo-sync-service';
|
|
|
|
export async function GET() {
|
|
try {
|
|
const [accounts, users, phones, authLogs, groups, integrations, lastSync] = await Promise.all([
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_accounts WHERE is_parent = false`),
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_users`),
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_phones`),
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_auth_logs`),
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_groups`),
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_integrations`),
|
|
postgresClient.query(`SELECT MAX(synced_at) as last_sync FROM duo_accounts`),
|
|
]);
|
|
|
|
const bypassed = await postgresClient.query(
|
|
`SELECT COUNT(*) as cnt FROM duo_users WHERE status IN ('bypass', 'disabled')`
|
|
);
|
|
|
|
return NextResponse.json({
|
|
connected: true,
|
|
syncing: duoSyncService.isSyncInProgress(),
|
|
lastSync: lastSync.rows[0]?.last_sync ?? null,
|
|
counts: {
|
|
accounts: Number(accounts.rows[0].cnt),
|
|
users: Number(users.rows[0].cnt),
|
|
phones: Number(phones.rows[0].cnt),
|
|
authLogs: Number(authLogs.rows[0].cnt),
|
|
groups: Number(groups.rows[0].cnt),
|
|
integrations: Number(integrations.rows[0].cnt),
|
|
bypassed: Number(bypassed.rows[0].cnt),
|
|
},
|
|
});
|
|
} catch (error: any) {
|
|
return NextResponse.json({
|
|
connected: false,
|
|
error: error.message,
|
|
counts: {},
|
|
});
|
|
}
|
|
}
|