const express = require('express'); const { db } = require('../database/db'); const { adminAuth } = require('../middleware/auth'); const router = express.Router(); // Get dashboard statistics router.get('/stats', adminAuth, async (req, res) => { try { // Get active events count const activeEvents = await db('events') .where('is_active', true) .where('is_archived', false) .count('id as count') .first(); // Get events expiring within 7 days const expiringEvents = await db('events') .where('is_active', true) .where('is_archived', false) .whereRaw('expires_at <= datetime("now", "+7 days")') .whereRaw('expires_at > datetime("now")') .count('id as count') .first(); // Get total photos count const totalPhotos = await db('photos') .count('id as count') .first(); // Get storage usage (sum of all photo sizes) const storageUsed = await db('photos') .sum('size_bytes as total') .first(); // Get total views (last 30 days) const totalViews = await db('access_logs') .where('action', 'view') .whereRaw('timestamp >= datetime("now", "-30 days")') .count('id as count') .first(); // Get total downloads (last 30 days) const totalDownloads = await db('access_logs') .where('action', 'download') .whereRaw('timestamp >= datetime("now", "-30 days")') .count('id as count') .first(); // Calculate trends (compare with previous 30 days) const previousViews = await db('access_logs') .where('action', 'view') .whereRaw('timestamp >= datetime("now", "-60 days")') .whereRaw('timestamp < datetime("now", "-30 days")') .count('id as count') .first(); const previousDownloads = await db('access_logs') .where('action', 'download') .whereRaw('timestamp >= datetime("now", "-60 days")') .whereRaw('timestamp < datetime("now", "-30 days")') .count('id as count') .first(); // Calculate trend percentages const viewsTrend = previousViews.count > 0 ? ((totalViews.count - previousViews.count) / previousViews.count) * 100 : 0; const downloadsTrend = previousDownloads.count > 0 ? ((totalDownloads.count - previousDownloads.count) / previousDownloads.count) * 100 : 0; res.json({ activeEvents: activeEvents.count || 0, expiringEvents: expiringEvents.count || 0, totalPhotos: totalPhotos.count || 0, storageUsed: storageUsed.total || 0, totalViews: totalViews.count || 0, totalDownloads: totalDownloads.count || 0, viewsTrend: Math.round(viewsTrend * 10) / 10, downloadsTrend: Math.round(downloadsTrend * 10) / 10 }); } catch (error) { console.error('Dashboard stats error:', error); res.status(500).json({ error: 'Failed to fetch dashboard statistics' }); } }); // Get recent activity router.get('/activity', adminAuth, async (req, res) => { try { const limit = parseInt(req.query.limit) || 10; const activities = await db('activity_logs') .select('activity_logs.*', 'events.event_name') .leftJoin('events', 'activity_logs.event_id', 'events.id') .orderBy('activity_logs.created_at', 'desc') .limit(limit); // Format activities const formattedActivities = activities.map(activity => ({ id: activity.id, type: activity.activity_type, actorType: activity.actor_type, actorName: activity.actor_name, eventName: activity.event_name, metadata: activity.metadata ? JSON.parse(activity.metadata) : {}, createdAt: activity.created_at })); res.json(formattedActivities); } catch (error) { console.error('Activity log error:', error); res.status(500).json({ error: 'Failed to fetch activity log' }); } }); // Get analytics data for charts router.get('/analytics', adminAuth, async (req, res) => { try { const days = parseInt(req.query.days) || 7; // Generate date range const dates = []; for (let i = days - 1; i >= 0; i--) { dates.push({ date: new Date(Date.now() - i * 24 * 60 * 60 * 1000).toISOString().split('T')[0], views: 0, downloads: 0, uniqueVisitors: 0 }); } // Get views per day const viewsData = await db('access_logs') .select(db.raw('DATE(timestamp) as date'), db.raw('COUNT(*) as count')) .where('action', 'view') .whereRaw(`timestamp >= datetime("now", "-${days} days")`) .groupByRaw('DATE(timestamp)'); // Get downloads per day const downloadsData = await db('access_logs') .select(db.raw('DATE(timestamp) as date'), db.raw('COUNT(*) as count')) .where('action', 'download') .whereRaw(`timestamp >= datetime("now", "-${days} days")`) .groupByRaw('DATE(timestamp)'); // Get unique visitors per day const visitorsData = await db('access_logs') .select(db.raw('DATE(timestamp) as date'), db.raw('COUNT(DISTINCT ip_address) as count')) .whereRaw(`timestamp >= datetime("now", "-${days} days")`) .groupByRaw('DATE(timestamp)'); // Merge data into dates array viewsData.forEach(row => { const dateObj = dates.find(d => d.date === row.date); if (dateObj) dateObj.views = row.count; }); downloadsData.forEach(row => { const dateObj = dates.find(d => d.date === row.date); if (dateObj) dateObj.downloads = row.count; }); visitorsData.forEach(row => { const dateObj = dates.find(d => d.date === row.date); if (dateObj) dateObj.uniqueVisitors = row.count; }); // Get top galleries by views const topGalleries = await db('access_logs') .select('events.event_name', 'events.slug') .select(db.raw('COUNT(*) as views')) .join('events', 'access_logs.event_id', 'events.id') .where('access_logs.action', 'view') .whereRaw(`access_logs.timestamp >= datetime("now", "-${days} days")`) .groupBy('events.id') .orderBy('views', 'desc') .limit(5); // Get device breakdown (simplified - based on user agent) const deviceData = await db('access_logs') .select( db.raw(` CASE WHEN user_agent LIKE '%Mobile%' THEN 'mobile' WHEN user_agent LIKE '%Tablet%' OR user_agent LIKE '%iPad%' THEN 'tablet' ELSE 'desktop' END as device_type `), db.raw('COUNT(*) as count') ) .whereRaw(`timestamp >= datetime("now", "-${days} days")`) .groupBy('device_type'); const totalDevices = deviceData.reduce((sum, d) => sum + d.count, 0); const devices = { desktop: 0, mobile: 0, tablet: 0 }; deviceData.forEach(d => { devices[d.device_type] = Math.round((d.count / totalDevices) * 100); }); res.json({ chartData: dates, topGalleries, devices }); } catch (error) { console.error('Analytics error:', error); res.status(500).json({ error: 'Failed to fetch analytics data' }); } }); module.exports = router;