180 lines
5.9 KiB
JavaScript
180 lines
5.9 KiB
JavaScript
// routes/reports.js
|
|
const express = require('express');
|
|
require('dotenv').config();
|
|
|
|
const router = express.Router();
|
|
const nodemailer = require('nodemailer');
|
|
const GameSession = require('../models/GameSession');
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
service: 'gmail',
|
|
auth: {
|
|
user: process.env.EMAIL_USER,
|
|
pass: process.env.EMAIL_PASS
|
|
}
|
|
});
|
|
|
|
router.post('/generate-report', async (req, res) => {
|
|
const { username, email } = req.body;
|
|
|
|
if (!username || !email) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'Username and email are required'
|
|
});
|
|
}
|
|
|
|
try {
|
|
// Fetch all sessions for the user
|
|
const sessions = await GameSession.find({ username }).sort({ createdAt: -1 });
|
|
|
|
if (sessions.length === 0) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: 'No session data found for this user'
|
|
});
|
|
}
|
|
|
|
// Generate report content
|
|
const report = generateReportContent(username, sessions);
|
|
|
|
// Email configuration
|
|
const mailOptions = {
|
|
from: 'shiharahimalshi@gmail.com',
|
|
to: email,
|
|
subject: `Game Session Report for ${username}`,
|
|
html: report
|
|
};
|
|
|
|
// Send email
|
|
await transporter.sendMail(mailOptions);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Report sent successfully to ' + email
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error('Report generation error:', err);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to generate report',
|
|
error: err.message
|
|
});
|
|
}
|
|
});
|
|
|
|
|
|
function generateReportContent(username, sessions) {
|
|
// Calculate statistics
|
|
const totalSessions = sessions.length;
|
|
const totalPlayTime = sessions.reduce((sum, session) => sum + session.durationSeconds, 0);
|
|
const averagePlayTime = Math.round(totalPlayTime / totalSessions);
|
|
const levelsPlayed = [...new Set(sessions.map(s => s.levelNumber))].sort((a, b) => a - b);
|
|
|
|
// Format play time
|
|
const formatTime = (seconds) => {
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
const secs = seconds % 60;
|
|
return `${hours}h ${minutes}m ${secs}s`;
|
|
};
|
|
|
|
// Generate professional report-style HTML
|
|
let html = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<style>
|
|
body { font-family: 'Segoe UI', Arial, sans-serif; margin: 30px; background: #fff; color: #000; line-height: 1.6; }
|
|
.header { text-align: center; margin-bottom: 30px; }
|
|
.header h1 { margin: 0; font-size: 28px; font-weight: bold; }
|
|
.header h2 { margin: 5px 0; font-size: 20px; font-weight: normal; }
|
|
.header p { margin: 0; font-size: 14px; color: #555; }
|
|
.section { margin-bottom: 30px; }
|
|
.section h3 { border-bottom: 2px solid #333; padding-bottom: 5px; margin-bottom: 15px; font-size: 18px; }
|
|
.stat-item { margin: 6px 0; font-size: 15px; }
|
|
.level-container { display: flex; flex-wrap: wrap; gap: 20px; }
|
|
.level-card { flex: 1 1 200px; border: 1px solid #ddd; padding: 12px; border-radius: 6px; background: #f9f9f9; }
|
|
table { width: 100%; border-collapse: collapse; margin-top: 15px; font-size: 14px; }
|
|
th, td { border: 1px solid #ddd; padding: 10px; text-align: center; }
|
|
th { background: #f2f2f2; font-weight: bold; }
|
|
tr:nth-child(even) { background: #fafafa; }
|
|
.footer { text-align: center; margin-top: 40px; font-size: 13px; color: #555; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<h1>Game Session Report</h1>
|
|
<h2>Player: ${username}</h2>
|
|
<p>Generated on: ${new Date().toLocaleDateString()}</p>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Overall Statistics</h3>
|
|
<div class="stat-item"><strong>Total Sessions:</strong> ${totalSessions}</div>
|
|
<div class="stat-item"><strong>Total Play Time:</strong> ${formatTime(totalPlayTime)}</div>
|
|
<div class="stat-item"><strong>Average Session Time:</strong> ${formatTime(averagePlayTime)}</div>
|
|
<div class="stat-item"><strong>Levels Played:</strong> ${levelsPlayed.join(', ')}</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Level Statistics</h3>
|
|
<div class="level-container">`;
|
|
|
|
// Level-specific stats
|
|
levelsPlayed.forEach(level => {
|
|
const levelSessions = sessions.filter(s => s.levelNumber === level);
|
|
const levelTotalTime = levelSessions.reduce((sum, s) => sum + s.durationSeconds, 0);
|
|
const levelAvgTime = Math.round(levelTotalTime / levelSessions.length);
|
|
|
|
html += `
|
|
<div class="level-card">
|
|
<strong>Level ${level}</strong><br>
|
|
Sessions: ${levelSessions.length}<br>
|
|
Total Time: ${formatTime(levelTotalTime)}<br>
|
|
Average Time: ${formatTime(levelAvgTime)}
|
|
</div>`;
|
|
});
|
|
|
|
html += `
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Detailed Session History</h3>
|
|
<table>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Level</th>
|
|
<th>Duration</th>
|
|
<th>Performance</th>
|
|
</tr>`;
|
|
|
|
sessions.forEach(session => {
|
|
const date = session.createdAt ? new Date(session.createdAt).toLocaleDateString() : 'N/A';
|
|
const performance = session.durationSeconds < averagePlayTime ? 'Above Average' : 'Average';
|
|
|
|
html += `
|
|
<tr>
|
|
<td>${date}</td>
|
|
<td>Level ${session.levelNumber}</td>
|
|
<td>${formatTime(session.durationSeconds)}</td>
|
|
<td>${performance}</td>
|
|
</tr>`;
|
|
});
|
|
|
|
html += `
|
|
</table>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<p>This report was generated automatically by the game system.</p>
|
|
</div>
|
|
</body>
|
|
</html>`;
|
|
|
|
return html;
|
|
}
|
|
|
|
module.exports = router; |