/** * Data Export API * GET /api/transparency/export - Export transparency data in various formats * * Provides data export capabilities for users and compliance. */ import type { NextApiRequest, NextApiResponse } from 'next'; import { getTransparencyDashboard, getAuditLog, getEventStream, getSignatureManager } from '../../../lib/transparency'; import * as fs from 'fs'; import * as path from 'path'; type ExportType = 'dashboard' | 'audit' | 'events' | 'plants' | 'transport' | 'signatures' | 'full'; type ExportFormat = 'json' | 'csv' | 'summary'; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== 'GET') { return res.status(405).json({ error: 'Method not allowed' }); } const { type = 'dashboard', format = 'json', startDate, endDate, plantId, userId } = req.query; try { const exportType = type as ExportType; const exportFormat = format as ExportFormat; let data: any; let filename: string; switch (exportType) { case 'dashboard': data = await exportDashboard(exportFormat); filename = 'transparency-dashboard'; break; case 'audit': data = await exportAudit(exportFormat, startDate as string, endDate as string); filename = 'audit-log'; break; case 'events': data = await exportEvents(exportFormat, startDate as string, endDate as string); filename = 'event-stream'; break; case 'plants': data = await exportPlants(exportFormat, plantId as string); filename = plantId ? `plant-${plantId}` : 'plants'; break; case 'transport': data = await exportTransport(exportFormat, plantId as string); filename = 'transport-history'; break; case 'signatures': data = await exportSignatures(exportFormat); filename = 'signatures'; break; case 'full': data = await exportFull(exportFormat); filename = 'full-transparency-export'; break; default: return res.status(400).json({ success: false, error: `Invalid export type: ${type}. Supported: dashboard, audit, events, plants, transport, signatures, full` }); } // Set appropriate headers based on format const timestamp = new Date().toISOString().split('T')[0]; if (exportFormat === 'csv') { res.setHeader('Content-Type', 'text/csv'); res.setHeader('Content-Disposition', `attachment; filename=${filename}-${timestamp}.csv`); return res.status(200).send(data); } if (exportFormat === 'summary') { res.setHeader('Content-Type', 'text/plain'); res.setHeader('Content-Disposition', `attachment; filename=${filename}-${timestamp}.txt`); return res.status(200).send(data); } // JSON format res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Disposition', `attachment; filename=${filename}-${timestamp}.json`); return res.status(200).json({ success: true, exportedAt: new Date().toISOString(), type: exportType, data }); } catch (error) { console.error('[API] Export error:', error); return res.status(500).json({ success: false, error: 'Failed to export data' }); } } async function exportDashboard(format: ExportFormat): Promise { const dashboard = getTransparencyDashboard(); return await dashboard.exportData(format); } async function exportAudit(format: ExportFormat, startDate?: string, endDate?: string): Promise { const auditLog = getAuditLog(); return auditLog.export(format, { startDate, endDate, limit: 10000 }); } async function exportEvents(format: ExportFormat, startDate?: string, endDate?: string): Promise { const eventStream = getEventStream(); const events = startDate && endDate ? eventStream.getByTimeRange(startDate, endDate, { limit: 10000 }) : eventStream.getRecent(10000); if (format === 'csv') { const headers = ['ID', 'Type', 'Priority', 'Timestamp', 'Source', 'Data']; const rows = events.map(e => [ e.id, e.type, e.priority, e.timestamp, e.source, JSON.stringify(e.data).replace(/,/g, ';') ]); return [headers.join(','), ...rows.map(r => r.join(','))].join('\n'); } if (format === 'summary') { const stats = eventStream.getStats(); return ` EVENT STREAM EXPORT =================== Exported: ${new Date().toISOString()} Total Events: ${stats.totalEvents} Events Last 24h: ${stats.eventsLast24h} Active Subscriptions: ${stats.activeSubscriptions} Active Webhooks: ${stats.activeWebhooks} Events by Type: ${Object.entries(stats.eventsByType).map(([t, c]) => ` ${t}: ${c}`).join('\n')} Events by Priority: ${Object.entries(stats.eventsByPriority).map(([p, c]) => ` ${p}: ${c}`).join('\n')} `.trim(); } return events; } async function exportPlants(format: ExportFormat, plantId?: string): Promise { const dataDir = path.join(process.cwd(), 'data'); const chainFile = path.join(dataDir, 'plantchain.json'); if (!fs.existsSync(chainFile)) { return format === 'json' ? [] : 'No plant data available'; } const chainData = JSON.parse(fs.readFileSync(chainFile, 'utf-8')); let plants = chainData.chain ?.filter((b: any) => b.plant) .map((b: any) => ({ ...b.plant, blockIndex: b.index, blockHash: b.hash, timestamp: b.timestamp })) || []; if (plantId) { plants = plants.filter((p: any) => p.id === plantId); } if (format === 'csv') { if (plants.length === 0) return 'ID,Name,Variety,Owner,Location,Generation,Timestamp\n'; const headers = ['ID', 'Name', 'Variety', 'Owner', 'Location', 'Generation', 'Timestamp']; const rows = plants.map((p: any) => [ p.id, p.name || '', p.variety || '', p.ownerId || '', p.location?.region || '', p.generation || 1, p.timestamp ]); return [headers.join(','), ...rows.map((r: any) => r.join(','))].join('\n'); } if (format === 'summary') { return ` PLANT EXPORT ============ Total Plants: ${plants.length} ${plantId ? `Filtered by Plant ID: ${plantId}` : ''} Sample Data: ${plants.slice(0, 5).map((p: any) => ` - ${p.name || 'Unknown'} (${p.variety || 'Unknown'}) - Gen ${p.generation || 1}` ).join('\n')} `.trim(); } return plants; } async function exportTransport(format: ExportFormat, plantId?: string): Promise { // Transport data would come from transport blockchain // For now, return placeholder if (format === 'csv') { return 'PlantID,EventType,From,To,Distance,Carbon,Timestamp\n'; } if (format === 'summary') { return 'TRANSPORT EXPORT\n================\nNo transport data available'; } return []; } async function exportSignatures(format: ExportFormat): Promise { const signatureManager = getSignatureManager(); const stats = signatureManager.getStats(); const identities = signatureManager.getAllIdentities(); if (format === 'csv') { const headers = ['ID', 'Name', 'Type', 'Verified', 'Created']; const rows = identities.map(i => [ i.id, i.name, i.type, i.verified ? 'Yes' : 'No', i.createdAt ]); return [headers.join(','), ...rows.map(r => r.join(','))].join('\n'); } if (format === 'summary') { return ` SIGNATURES EXPORT ================= Total Identities: ${stats.totalIdentities} Verified Identities: ${stats.verifiedIdentities} Total Signatures: ${stats.totalSignatures} Pending Multi-Sigs: ${stats.pendingMultiSigs} Completed Multi-Sigs: ${stats.completedMultiSigs} Signatures by Type: ${Object.entries(stats.signaturesByType).map(([t, c]) => ` ${t}: ${c}`).join('\n') || ' None'} `.trim(); } return { stats, identities }; } async function exportFull(format: ExportFormat): Promise { const dashboard = await exportDashboard('json'); const audit = await exportAudit('json'); const events = await exportEvents('json'); const plants = await exportPlants('json'); const transport = await exportTransport('json'); const signatures = await exportSignatures('json'); if (format === 'summary') { return ` FULL TRANSPARENCY EXPORT ======================== Exported: ${new Date().toISOString()} This export contains all transparency data from LocalGreenChain. Sections Included: - Dashboard metrics - Audit log entries - Event stream data - Plant registry - Transport history - Digital signatures Use JSON format for complete data export. `.trim(); } if (format === 'csv') { return 'Full export not available in CSV format. Use JSON instead.'; } return { dashboard, audit, events, plants, transport, signatures }; }