Skip to content

Commit

Permalink
view packet after finishing geoword
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffrey-wu committed Jul 9, 2023
1 parent 71510c1 commit f9007f1
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 9 deletions.
75 changes: 75 additions & 0 deletions client/geoword/packet.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!doctype html>
<html lang="en">

<head>
<title>QB Reader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/apple-touch-icon-precomposed.png" rel="apple-touch-icon-precomposed">
<link type="image/x-icon" href="/favicon.ico" rel="icon">

<link href="/bootstrap/light.css" rel="stylesheet">
<link href="/bootstrap/dark.css" rel="stylesheet" id="custom-css">
<script src="/apply-theme.js"></script>
</head>

<body>
<nav class="navbar navbar-light navbar-expand-lg bg-custom" id="navbar" style="z-index: 10">
<div class="container-fluid">
<a class="navbar-brand ms-1 py-0" id="logo" href="/">
<span class="logo-prefix">QB</span><span class="logo-suffix">Reader</span>
</a>
<button class="navbar-toggler" data-bs-target="#navbarSupportedContent" data-bs-toggle="collapse" type="button"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/tossups">Tossups</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/bonuses">Bonuses</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/multiplayer">Multiplayer</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/db">Database</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/geoword">Geoword</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/api-docs">API</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about">About</a>
</li>
</ul>
<div class="d-flex">
<ul class="navbar-nav mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/user/login" id="login-link">Log in</a>
</li>
</ul>
</div>
</div>
</div>
</nav>

<div class="container-xl mt-3 mb-5 pb-5">
<p class="text-center lead"><span id="packet-name"></span> Tossups:</p>
<div id="packet"></div>
</div>

<script src="/bootstrap/bootstrap.bundle.min.js"></script>
<script src="/script.js"></script>

<script src="/geoword/script.js"></script>
<script src="/geoword/packet.js"></script>
</body>

</html>
27 changes: 27 additions & 0 deletions client/geoword/packet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const division = decodeURIComponent(window.location.search.slice(1));
const packetName = window.location.pathname.split('/').pop();
const packetTitle = titleCase(packetName);

document.getElementById('packet-name').textContent = packetTitle;

fetch('/api/geoword/packet?' + new URLSearchParams({ packetName, division }))
.then(response => {
if (response.status === 403) {
document.getElementById('packet').textContent = 'You do not have permission to view this packet. Either you have not paid for it, or you have not finished playing it. Please contact the administrator if you believe this is an error.';
} else {
return response.json();
}
})
.then(data => {
const { packet } = data;
let innerHTML = '';

for (const tossup of packet) {
innerHTML += `<div>${tossup.questionNumber}. ${tossup.question}</div>`;
innerHTML += `<div>ANSWER: ${tossup.formatted_answer ?? tossup.answer}</div>`;
innerHTML += `<p>&lt;${tossup.category} / ${tossup.subcategory}&gt;</p>`;
innerHTML += '<hr class="my-3"></hr>';
}

document.getElementById('packet').innerHTML += innerHTML;
});
3 changes: 3 additions & 0 deletions client/geoword/stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
<p>
View the leaderboard for this packet: <span id="leaderboard-links"></span>
</p>
<p>
View the tossups from this packet: <span id="packet-links"></span>
</p>
<div id="stats"></div>
</div>

Expand Down
26 changes: 19 additions & 7 deletions client/geoword/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,23 @@ fetch('/api/geoword/get-divisions?' + new URLSearchParams({ packetName }))
.then(data => {
const { divisions } = data;
const leaderboardLinks = document.getElementById('leaderboard-links');
divisions.forEach(division => {
const a = document.createElement('a');
a.href = `/geoword/leaderboard/${packetName}?${encodeURIComponent(division)}`;
a.textContent = division;
leaderboardLinks.appendChild(a);
leaderboardLinks.appendChild(document.createTextNode(' '));
});
const packetLinks = document.getElementById('packet-links');
for (const index in divisions) {
const division = divisions[index];
const a1 = document.createElement('a');
a1.href = `/geoword/leaderboard/${packetName}?${encodeURIComponent(division)}`;
a1.textContent = division;

const a2 = document.createElement('a');
a2.href = `/geoword/packet/${packetName}?${encodeURIComponent(division)}`;
a2.textContent = division;

if (index > 0) {
leaderboardLinks.appendChild(document.createTextNode(' | '));
packetLinks.appendChild(document.createTextNode(' | '));
}

leaderboardLinks.appendChild(a1);
packetLinks.appendChild(a2);
}
});
19 changes: 18 additions & 1 deletion database/geoword.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ async function getLeaderboard(packetName, division, limit=100) {
return result;
}

async function getPacket(packetName, division) {
const packet = await tossups.find(
{ packetName, division },
{ sort: { questionNumber: 1 } },
).toArray();

return packet;
}

async function getPacketList() {
const list = await packets.find({ test: { $exists: false } }, {
sort: { order: 1 },
Expand Down Expand Up @@ -215,7 +224,14 @@ async function getProtests(packetName, division) {
return { protests, packet };
}


async function getQuestionCount(packetName, division) {
if (division === undefined) {
const packet = await packets.findOne({ name: packetName });
const count = await tossups.countDocuments({ packetName });
return Math.round(count / packet.divisions.length);
}

return await tossups.countDocuments({ packetName, division });
}

Expand Down Expand Up @@ -379,8 +395,9 @@ export {
getDivisionChoice,
getDivisions,
getLeaderboard,
getPacketStatus,
getPacket,
getPacketList,
getPacketStatus,
getProgress,
getProtests,
getQuestionCount,
Expand Down
27 changes: 26 additions & 1 deletion routes/api/geoword.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as geoword from '../../database/geoword.js';
import { getUserId } from '../../database/users.js';
import { getUserId, isAdmin } from '../../database/users.js';
import { checkToken } from '../../server/authentication.js';
import checkAnswer from '../../server/checkAnswer.js';

Expand Down Expand Up @@ -67,6 +67,31 @@ router.get('/leaderboard', async (req, res) => {
res.json({ leaderboard });
});

router.get('/packet', async (req, res) => {
const { username, token } = req.session;
if (!checkToken(username, token)) {
delete req.session;
res.redirect('/geoword/login');
return;
}

const { packetName, division } = req.query;

const [admin, buzzCount, questionCount] = await Promise.all([
isAdmin(username),
geoword.getBuzzCount(packetName, username),
geoword.getQuestionCount(packetName),
]);

if (!admin && buzzCount < questionCount) {
res.sendStatus(403);
return;
}

const packet = await geoword.getPacket(packetName, division);
res.json({ packet });
});

router.get('/packet-list', async (req, res) => {
const packetList = await geoword.getPacketList();
res.json({ packetList });
Expand Down
14 changes: 14 additions & 0 deletions routes/geoword.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ router.get('/leaderboard/:packetName', (req, res) => {
res.sendFile('leaderboard.html', { root: './client/geoword' });
});

router.get('/packet/:packetName', async (req, res) => {
const { username } = req.session;
const packetName = req.params.packetName;

const paid = await geoword.checkPayment({ packetName, username });

if (paid) {
res.sendFile('packet.html', { root: './client/geoword' });
return;
}

res.redirect('/geoword/payment/' + packetName);
});

router.get('/payment/:packetName', async (req, res) => {
const { username } = req.session;
const packetName = req.params.packetName;
Expand Down

0 comments on commit f9007f1

Please sign in to comment.