|
|
@@ -0,0 +1,82 @@
|
|
|
+const router = require('express').Router();
|
|
|
+const { requireAuth } = require('../middleware/auth');
|
|
|
+const { Track } = require('../models');
|
|
|
+
|
|
|
+function getWeek(date) {
|
|
|
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
|
+ const dayNum = d.getUTCDay() || 7;
|
|
|
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
|
|
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
|
+ return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
|
|
+}
|
|
|
+
|
|
|
+router.get('/', requireAuth, async (req, res) => {
|
|
|
+ try {
|
|
|
+ const tracks = await Track.findAll({
|
|
|
+ where: { userId: req.user.id },
|
|
|
+ attributes: ['totalDistance', 'trackDate', 'uploadDate'],
|
|
|
+ });
|
|
|
+
|
|
|
+ const byYear = {}, byMonth = {}, byWeek = {};
|
|
|
+
|
|
|
+ for (const t of tracks) {
|
|
|
+ const d = t.trackDate ? new Date(t.trackDate) : (t.uploadDate ? new Date(t.uploadDate) : null);
|
|
|
+ if (!d || isNaN(d.getTime())) continue;
|
|
|
+
|
|
|
+ const year = d.getFullYear();
|
|
|
+ const month = d.getMonth() + 1;
|
|
|
+ const week = getWeek(d);
|
|
|
+ const dist = t.totalDistance || 0;
|
|
|
+
|
|
|
+ byYear[year] = (byYear[year] || 0) + dist;
|
|
|
+ const mk = `${year}-${String(month).padStart(2,'0')}`;
|
|
|
+ byMonth[mk] = (byMonth[mk] || 0) + dist;
|
|
|
+ const wk = `${year}-W${String(week).padStart(2,'0')}`;
|
|
|
+ byWeek[wk] = (byWeek[wk] || 0) + dist;
|
|
|
+ }
|
|
|
+
|
|
|
+ res.json({
|
|
|
+ byYear: Object.entries(byYear).map(([year, distance]) => ({ year: parseInt(year), distance })).sort((a,b) => a.year - b.year),
|
|
|
+ byMonth: Object.entries(byMonth).map(([key, distance]) => {
|
|
|
+ const [year, month] = key.split('-');
|
|
|
+ return { year: parseInt(year), month: parseInt(month), distance };
|
|
|
+ }).sort((a,b) => a.year - b.year || a.month - b.month),
|
|
|
+ byWeek: Object.entries(byWeek).map(([key, distance]) => {
|
|
|
+ const [year, week] = key.split('-W');
|
|
|
+ return { year: parseInt(year), week: parseInt(week), distance };
|
|
|
+ }).sort((a,b) => a.year - b.year || a.week - b.week),
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ res.status(500).json({ error: 'Server error' });
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// Overview stats for a directory (including subdirectories)
|
|
|
+router.get('/directory/:id', requireAuth, async (req, res) => {
|
|
|
+ try {
|
|
|
+ const { Directory, Track } = require('../models');
|
|
|
+ const { Op } = require('sequelize');
|
|
|
+
|
|
|
+ // Collect all subdir IDs
|
|
|
+ async function collectIds(dirId) {
|
|
|
+ const children = await Directory.findAll({ where: { parentId: dirId, userId: req.user.id } });
|
|
|
+ let ids = [dirId];
|
|
|
+ for (const c of children) ids = ids.concat(await collectIds(c.id));
|
|
|
+ return ids;
|
|
|
+ }
|
|
|
+
|
|
|
+ const allIds = await collectIds(parseInt(req.params.id));
|
|
|
+ const tracks = await Track.findAll({
|
|
|
+ where: { directoryId: { [Op.in]: allIds }, userId: req.user.id },
|
|
|
+ attributes: ['id', 'name', 'totalDistance', 'trackDate', 'uploadDate', 'pointCount', 'directoryId'],
|
|
|
+ order: [['trackDate', 'DESC'], ['uploadDate', 'DESC']],
|
|
|
+ });
|
|
|
+
|
|
|
+ const totalDistance = tracks.reduce((s, t) => s + (t.totalDistance || 0), 0);
|
|
|
+ res.json({ tracks, totalDistance, trackCount: tracks.length });
|
|
|
+ } catch (e) {
|
|
|
+ res.status(500).json({ error: 'Server error' });
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+module.exports = router;
|