diff --git a/client/geoword/compare.html b/client/geoword/compare.html new file mode 100644 index 000000000..a6352160c --- /dev/null +++ b/client/geoword/compare.html @@ -0,0 +1,85 @@ + + + +
++ Compare your stats on () against another player. +
+ + +View the tossups from this packet:
++ Compare your stats against another player by clicking here. +
diff --git a/client/geoword/stats.js b/client/geoword/stats.js index ff97e4f54..ead09c1b6 100644 --- a/client/geoword/stats.js +++ b/client/geoword/stats.js @@ -1,6 +1,7 @@ const packetName = window.location.pathname.split('/').pop(); const packetTitle = titleCase(packetName); +document.getElementById('compare-link').href = `/geoword/compare/${packetName}`; document.getElementById('packet-name').textContent = packetTitle; fetch('/api/geoword/stats?' + new URLSearchParams({ packetName })) diff --git a/database/geoword.js b/database/geoword.js index 168743a6c..43f139773 100644 --- a/database/geoword.js +++ b/database/geoword.js @@ -98,6 +98,50 @@ async function getAnswer(packetName, division, questionNumber) { } } +/** + * + * @param {String} packetName + * @param {String} division + * @param {ObjectId} user_id + * @param {Boolean} protests - whether to include protests (default: false) + */ +async function getBuzzes(packetName, division, user_id, protests=false) { + const projection = { + _id: 0, + celerity: 1, + points: 1, + questionNumber: 1, + answer: '$tossup.answer', + formatted_answer: '$tossup.formatted_answer', + givenAnswer: 1, + }; + + if (protests) { + projection.pendingProtest = 1; + projection.decision = 1; + projection.reason = 1; + } + + return await buzzes.aggregate([ + { $match: { packetName, division, user_id } }, + { $sort: { questionNumber: 1 } }, + { $lookup: { + from: 'tossups', + let: { questionNumber: '$questionNumber', packetName, division }, + pipeline: [ + { $match: { $expr: { $and: [ + { $eq: ['$questionNumber', '$$questionNumber'] }, + { $eq: ['$packetName', '$$packetName'] }, + { $eq: ['$division', '$$division'] }, + ] } } }, + ], + as: 'tossup', + } }, + { $unwind: '$tossup' }, + { $project: projection }, + ]).toArray(); +} + async function getBuzzCount(packetName, username) { const user_id = await getUserId(username); return await buzzes.countDocuments({ packetName, user_id }); @@ -236,42 +280,12 @@ async function getQuestionCount(packetName, division) { } /** - * @param {Object} params - * @param {String} params.packetName + * @param {String} packetName * @param {ObjectId} user_id */ -async function getUserStats({ packetName, user_id }) { +async function getUserStats(packetName, user_id) { const division = await getDivisionChoiceById(packetName, user_id); - - const buzzArray = await buzzes.aggregate([ - { $match: { packetName, user_id } }, - { $sort: { questionNumber: 1 } }, - { $lookup: { - from: 'tossups', - let: { questionNumber: '$questionNumber', packetName, division }, - pipeline: [ - { $match: { $expr: { $and: [ - { $eq: ['$questionNumber', '$$questionNumber'] }, - { $eq: ['$packetName', '$$packetName'] }, - { $eq: ['$division', '$$division'] }, - ] } } }, - ], - as: 'tossup', - } }, - { $unwind: '$tossup' }, - { $project: { - _id: 0, - celerity: 1, - pendingProtest: 1, - points: 1, - questionNumber: 1, - answer: '$tossup.answer', - formatted_answer: '$tossup.formatted_answer', - givenAnswer: 1, - decision: 1, - reason: 1, - } }, - ]).toArray(); + const buzzArray = await getBuzzes(packetName, division, user_id, true); const leaderboard = await buzzes.aggregate([ { $match: { packetName, division, active: true } }, @@ -391,6 +405,7 @@ export { getAdminStats, getAnswer, getBuzzCount, + getBuzzes, getCost, getDivisionChoice, getDivisions, diff --git a/routes/api/geoword.js b/routes/api/geoword.js index 9a7728eae..4ce9f1ab6 100644 --- a/routes/api/geoword.js +++ b/routes/api/geoword.js @@ -9,6 +9,21 @@ import stripeClass from 'stripe'; const router = Router(); const stripe = new stripeClass(process.env.STRIPE_SECRET_KEY); +router.get('/compare', async (req, res) => { + const { username, token } = req.session; + if (!checkToken(username, token)) { + delete req.session; + res.redirect('/geoword/login'); + return; + } + + const { packetName, division, opponent } = req.query; + const myBuzzes = await geoword.getBuzzes(packetName, division, await getUserId(username)); + const opponentBuzzes = (await geoword.getBuzzes(packetName, division, await getUserId(opponent))).slice(0, myBuzzes.length); + + return res.json({ myBuzzes, opponentBuzzes }); +}); + router.post('/create-payment-intent', async (req, res) => { const { username, token } = req.session; if (!checkToken(username, token)) { @@ -42,6 +57,20 @@ router.get('/check-answer', async (req, res) => { res.json({ actualAnswer: answer, directive, directedPrompt }); }); +router.get('/division-choice', async (req, res) => { + const { username, token } = req.session; + if (!checkToken(username, token)) { + delete req.session; + res.redirect('/geoword/login'); + return; + } + + const { packetName } = req.query; + const division = await geoword.getDivisionChoice(packetName, username); + + res.json({ division }); +}); + router.get('/get-progress', async (req, res) => { const { username, token } = req.session; if (!checkToken(username, token)) { @@ -173,7 +202,7 @@ router.get('/stats', async (req, res) => { const user_id = await getUserId(username); const { packetName } = req.query; - const { buzzArray, division, leaderboard } = await geoword.getUserStats({ packetName, user_id }); + const { buzzArray, division, leaderboard } = await geoword.getUserStats(packetName, user_id); res.json({ buzzArray, division, leaderboard }); }); diff --git a/routes/geoword.js b/routes/geoword.js index b89330724..9fe72194d 100644 --- a/routes/geoword.js +++ b/routes/geoword.js @@ -62,6 +62,19 @@ router.use('/*/:packetName', async (req, res, next) => { next(); }); +router.get('/compare/:packetName', async (req, res) => { + const { username } = req.session; + const packetName = req.params.packetName; + const paid = await geoword.checkPayment({ packetName, username }); + + if (!paid) { + res.redirect('/geoword/payment/' + packetName); + return; + } + + res.sendFile('compare.html', { root: './client/geoword' }); +}); + router.get('/division/:packetName', async (req, res) => { const { username } = req.session; const packetName = req.params.packetName;