Skip to content

Commit fda8d1d

Browse files
committed
feat: add export as csv option to results
1 parent f67e1a2 commit fda8d1d

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

src/routes/results.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PrismaClient } from '@prisma/client';
22
import { Express } from 'express';
3-
import { getEndedSeasons, getSeasonResults } from '../utils';
3+
import { getEndedSeasons, getSeasonResults, RANKING_MAX } from '../utils';
44

55
export const setupResultsRoutes = function(app: Express, prisma: PrismaClient): void {
66
app.get('/results', async (req, res) => {
@@ -29,4 +29,55 @@ export const setupResultsRoutes = function(app: Express, prisma: PrismaClient):
2929
rankings,
3030
});
3131
});
32+
33+
app.get('/results/:bloc_deadline_id/coalitions/:coalition_slug.csv', async (req, res) => {
34+
const endedSeasons = await getEndedSeasons(prisma);
35+
const season = endedSeasons.find(season => season.id === parseInt(req.params.bloc_deadline_id, 10));
36+
if (!season) {
37+
return res.status(404).send('Season not found or has not ended yet.');
38+
}
39+
40+
const { seasonResults } = await getSeasonResults(prisma, season.id, RANKING_MAX);
41+
const seasonResult = seasonResults.find(result => result.coalition.intra_coalition.slug === req.params.coalition_slug);
42+
if (!seasonResult) {
43+
return res.status(404).send('Coalition not found for this season.');
44+
}
45+
46+
// Generate CSV
47+
let csv = 'Coalition,Rank,User,Score\n';
48+
seasonResult.scores.forEach((entry, index) => {
49+
csv += `"${seasonResult.coalition.intra_coalition.name}",${entry.coalition_rank},"${entry.user.intra_user.login}",${entry.score}\n`;
50+
});
51+
52+
res.setHeader('Content-Disposition', `attachment; filename="${seasonResult.coalition.intra_coalition.slug}-leaderboard-season-${season.id}.csv"`);
53+
res.setHeader('Content-Type', 'text/csv');
54+
return res.send(csv);
55+
});
56+
57+
app.get('/results/:bloc_deadline_id/rankings/:ranking_type.csv', async (req, res) => {
58+
const endedSeasons = await getEndedSeasons(prisma);
59+
const season = endedSeasons.find(season => season.id === parseInt(req.params.bloc_deadline_id, 10));
60+
if (!season) {
61+
return res.status(404).send('Season not found or has not ended yet.');
62+
}
63+
64+
const { seasonResults, rankings } = await getSeasonResults(prisma, season.id, RANKING_MAX);
65+
const ranking = rankings.find(r => r.type === req.params.ranking_type);
66+
if (!ranking) {
67+
return res.status(404).send('Ranking not found for this season.');
68+
}
69+
70+
// Generate CSV
71+
let csv = 'Ranking,Coalition,Rank,User,Score\n';
72+
ranking.results.forEach((entry) => {
73+
const userCoalition = seasonResults.find(sr => sr.coalition.id === entry.coalition_id);
74+
const coalitionName = userCoalition ? userCoalition.coalition.intra_coalition.name : 'N/A';
75+
csv += `"${ranking.name}","${coalitionName}",${entry.rank},"${entry.user.intra_user.login}",${entry.score}\n`;
76+
});
77+
78+
79+
res.setHeader('Content-Disposition', `attachment; filename="ranking-${ranking.type}-season-${season.id}.csv"`);
80+
res.setHeader('Content-Type', 'text/csv');
81+
return res.send(csv);
82+
});
3283
};

src/sync/results.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,13 @@ export const calculateResults = async function(api: Fast42): Promise<void> {
6767
});
6868

6969
// Individual user scores
70-
const usersScores = await getUsersScores(prisma, coalition.id, season.end_at, RANKING_MAX);
70+
const userCount = await prisma.intraCoalitionUser.count({
71+
where: {
72+
coalition_id: coalition.id,
73+
},
74+
});
75+
console.log(` - Found ${userCount} users in coalition ${coalition.name}`);
76+
const usersScores = await getUsersScores(prisma, coalition.id, season.end_at, userCount);
7177
console.log(` - Calculating individual results for ${usersScores.length} users in coalition ${coalition.name}...`);
7278
let rank = 0;
7379
let lastScore = Infinity;

templates/results.njk

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
<div class="card w-100 mb-4" id="leaderboards" style="overflow: hidden;">
5555
<div class="card-header pe-2 d-flex align-items-center" style="background-color: {{ seasonResult.coalition.intra_coalition.color | rgba(0.5) }};">
5656
<h4 class="d-inline-block pe-3 lh-lg flex-grow-1 text-white">{{ seasonResult.coalition.intra_coalition.name | striptags(true) | escape }} Leaderboards</h4>
57-
<div class="d-inline-block">
58-
57+
<div class="d-inline-flex align-content-center">
58+
<a href="/results/{{ seasonId }}/coalitions/{{ seasonResult.coalition.intra_coalition.slug }}.csv" class="btn btn-sm btn-outline-light">Export CSV</a>
5959
</div>
6060
</div>
6161
<div class="">
@@ -104,8 +104,8 @@
104104
<div class="card w-100 mb-4" id="ranking-{{ ranking.type }}">
105105
<div class="card-header pe-2 d-flex align-items-center" style="background-color: #6c757d;">
106106
<h4 class="d-inline-block pe-3 lh-lg flex-grow-1 text-white">{{ ranking.name | striptags(true) | escape }}</h4>
107-
<div class="d-inline-block">
108-
107+
<div class="d-inline-flex align-content-center">
108+
<a href="/results/{{ seasonId }}/rankings/{{ ranking.type }}.csv" class="btn btn-sm btn-outline-light">Export CSV</a>
109109
</div>
110110
</div>
111111
<div class="card-body p-0">

0 commit comments

Comments
 (0)