const express = require('express'); const { authenticate, authenticate_noerror } = require('../middleware/authenticate'); const router = express.Router(); const PageView = require('../models/PageView'); const multer = require('multer'); const XLSX = require('xlsx'); const upload = multer({ dest: 'uploads/' }); 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, referrer } = req.body; const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown'; try { const pageView = new PageView({ url, ip, idapp, referrer, 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 }]; const today = startOfDay(new Date()); const weekAgo = startOfDay(subDays(new Date(), 7)); const monthAgo = startOfDay(subDays(new Date(), 30)); // Funzione dinamica per creare pipeline di conteggio const countStage = (date) => { const match = { timestamp: { $gte: date } }; if (!unique) { return [{ $match: match }, { $count: 'count' }]; } return [ { $match: match }, { $group: { _id: { url: '$url', user: { $ifNull: ['$userId', '$ip'] }, date: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } }, }, }, }, { $count: 'count' }, ]; }; // Pipeline completa const timeStatsPipeline = [ ...basePipeline, { $facet: { total: !unique ? [{ $count: 'count' }] : [ { $group: { _id: { url: '$url', user: { $ifNull: ['$userId', '$ip'] }, date: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } }, }, }, }, { $count: 'count' }, ], today: countStage(today), week: countStage(weekAgo), month: countStage(monthAgo), }, }, ]; // 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' }); } }); router.post('/api/convert-csv-to-xls', upload.single('csv'), (req, res) => { try { const csvFilePath = req.file.path; // Leggi il CSV con SheetJS const csvData = fs.readFileSync(csvFilePath, 'utf-8'); const worksheet = XLSX.utils.csv_to_sheet(csvData); // Crea un file Excel const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); // Imposta la risposta come file XLS const xlsFilePath = path.join(__dirname, 'converted', 'output.xls'); XLSX.writeFile(workbook, xlsFilePath); // Restituisci il file XLS al frontend come risposta res.download(xlsFilePath, 'converted-file.xls', (err) => { if (err) { console.error('Errore nel download del file:', err); res.status(500).send('Errore nel download del file'); } // Pulisci il file temporaneo fs.unlinkSync(csvFilePath); fs.unlinkSync(xlsFilePath); }); } catch (error) { console.error("Errore nella conversione del file:", error); res.status(500).send('Errore nella conversione del file'); } }); module.exports = router;