Bypass = security risk (MFA not enforced) — shown in red, expandable panel
Disabled = locked out, no threat — shown in muted gray, separate expandable panel
- Split /api/duo/status counts into bypass and disabled separately
- /api/duo/users/flagged returns { bypass: [], disabled: [] } instead of flat list
- Overview card: only bypass triggers red warning icon (disabled does not)
- Detail page: two separate expandable sections with distinct severity styling
- Both sections include user, email, account name, enrolled status, last login, notes
- Covers all accounts (parent + children)
44 lines
1.8 KiB
TypeScript
44 lines
1.8 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 [bypassRes, disabledRes] = await Promise.all([
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_users WHERE status = 'bypass'`),
|
|
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_users WHERE status = '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),
|
|
bypass: Number(bypassRes.rows[0].cnt),
|
|
disabled: Number(disabledRes.rows[0].cnt),
|
|
},
|
|
});
|
|
} catch (error: any) {
|
|
return NextResponse.json({
|
|
connected: false,
|
|
error: error.message,
|
|
counts: {},
|
|
});
|
|
}
|
|
}
|