const express = require('express'); const { authenticate, authenticate_noerror } = require('../middleware/authenticate'); const router = express.Router(); const PageView = require('../models/PageView'); router.post('/test-lungo', authenticate, (req, res) => { const timeout = req.body.timeout; console.log(`🕙 Richiesta iniziata con timeout=${timeout}`); // Simuliamo un'elaborazione lunga const durataMs = timeout - 2000; setTimeout(() => { console.log(`✅ Elaborazione completata di ${durataMs} ms`); res.json({ ok: true, message: `✅ Richiesta completata con successo! (${durataMs})` }); }, durataMs); // Verifico se la richiesta va a buon fine setTimeout(() => { if (!res.headersSent) { res.status(500).json({ ok: false, message: "❌ Errore durante l'elaborazione della richiesta!" }); } }, durataMs + 1000); }); router.post('/track-pageview', authenticate_noerror, async (req, res) => { const { url, userAgent, idapp } = req.body; const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown'; try { const pageView = new PageView({ url, ip, idapp, userId: req.user ? req.user._id : '', username: req.user ? req.user.username : '', userAgent, }); await pageView.save(); res.status(200).json({ message: 'Visita registrata' }); } catch (error) { console.error('Errore nel salvataggio della visita:', error); res.status(500).json({ error: 'Impossibile registrare la visita' }); } }); router.get('/pageviews/stats', authenticate_noerror, async (req, res) => { const { userId, idapp, unique } = req.query; try { const matchStage = { idapp }; if (userId) { matchStage.$or = [{ userId }, { username: userId }]; } // Definiamo la base della pipeline const basePipeline = [{ $match: matchStage }]; // Pipeline per statistiche temporali (oggi, settimana, mese) const timeStatsPipeline = [ ...basePipeline, { $facet: { total: [{ $count: 'total' }], today: [{ $match: { timestamp: { $gte: startOfDay(new Date()) } } }, { $count: 'count' }], week: [{ $match: { timestamp: { $gte: startOfDay(subDays(new Date(), 7)) } } }, { $count: 'count' }], month: [{ $match: { timestamp: { $gte: startOfDay(subDays(new Date(), 30)) } } }, { $count: 'count' }], }, }, ]; // Eseguiamo solo la parte delle statistiche temporali const timeStatsResult = await PageView.aggregate(timeStatsPipeline); // Ora costruiamo la pipeline completa per topPages (con o senza unique) let topPagesPipeline = [...basePipeline]; if (unique) { topPagesPipeline = [ ...topPagesPipeline, { $group: { _id: { url: '$url', userId: { $ifNull: ['$userId', '$ip'] }, date: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp', }, }, }, }, }, { $replaceRoot: { newRoot: '$_id' } }, ]; } // Aggiungi il group finale per contare le pagine const topPagesResult = await PageView.aggregate([ ...topPagesPipeline, { $group: { _id: '$url', count: { $sum: 1 }, }, }, { $sort: { count: -1 } }, { $limit: 10 }, ]); // Formattazione dei risultati const formatCount = (arr) => (arr && arr.length > 0 ? arr[0].count || 0 : 0); const stats = { total: formatCount(timeStatsResult[0]?.total), today: formatCount(timeStatsResult[0]?.today), week: formatCount(timeStatsResult[0]?.week), month: formatCount(timeStatsResult[0]?.month), topPages: topPagesResult, }; res.json(stats); } catch (err) { console.error(err); res.status(500).json({ error: 'Errore nel calcolo delle statistiche' }); } }); function startOfDay(date) { return new Date(date.getFullYear(), date.getMonth(), date.getDate()); } function subDays(date, days) { const newDate = new Date(date); newDate.setDate(newDate.getDate() - days); return newDate; } router.get('/pageviews/users', authenticate_noerror, async (req, res) => { try { const { idapp } = req.query; // Trova tutte le entry con idapp e prendi userId e username const usersData = await PageView.find({ idapp }, { userId: 1, username: 1, _id: 0 }).lean(); // Usa un Map per garantire unicità basata su userId const uniqueUsersMap = new Map(); usersData.forEach(({ userId, username }) => { if (userId && !uniqueUsersMap.has(userId)) { uniqueUsersMap.set(userId, { userId, username }); } }); // Converte la Map in array const uniqueUsers = Array.from(uniqueUsersMap.values()); res.json(uniqueUsers); } catch (err) { console.error(err); res.status(500).json({ error: 'Errore nel recupero degli utenti' }); } }); router.get('/pageviews/weekly-top-pages', authenticate_noerror, async (req, res) => { const { idapp, userId, unique, year, week } = req.query; try { const matchStage = { idapp }; if (userId) { matchStage.$or = [{ userId }, { username: userId }]; } const pipeline = []; // Filtro base pipeline.push({ $match: matchStage }); // Estrai settimana e anno pipeline.push({ $addFields: { week: { $isoWeek: '$timestamp' }, year: { $isoWeekYear: '$timestamp' }, }, }); // Filtra per settimana e anno se specificati if (year && week) { pipeline.push({ $match: { year: parseInt(year), week: parseInt(week), }, }); } if (unique === 'true') { // Visite uniche: 1 per utente/giorno/pagina pipeline.push({ $group: { _id: { url: '$url', user: { $ifNull: ['$userId', '$ip'] }, day: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } }, }, }, }); // Riformatta per conteggio pipeline.push({ $group: { _id: '$_id.url', count: { $sum: 1 }, }, }); } else { // Visite totali: tutte le occorrenze pipeline.push({ $group: { _id: '$url', count: { $sum: 1 }, }, }); } // Ordina per numero visite pipeline.push({ $sort: { count: -1 } }); // Aggiungi metadati settimana/anno se presenti if (year && week) { pipeline.push({ $addFields: { year: parseInt(year), week: parseInt(week), }, }); } const result = await PageView.aggregate(pipeline); res.json( result.map((r) => ({ url: r._id, count: r.count, year: r.year, week: r.week, })) ); } catch (err) { console.error(err); res.status(500).json({ error: 'Errore nel calcolo delle statistiche settimanali' }); } }); module.exports = router;