diff --git a/backend/api/controllers/result.js b/backend/api/controllers/result.js index baa0be15f..f86527444 100644 --- a/backend/api/controllers/result.js +++ b/backend/api/controllers/result.js @@ -191,6 +191,27 @@ class ResultController { next(e); } } + + static async getLeaderboard(req, res, next) { + try { + const { type, mode, mode2 } = req.params; + const results = await ResultDAO.getLeaderboard(type, mode, mode2); + return res.status(200).json(results); + } catch (e) { + next(e); + } + } + + static async checkLeaderboardQualification(req, res, next) { + try { + const { uid } = req.decodedToken; + const { result } = req.body; + const data = await ResultDAO.checkLeaderboardQualification(uid, result); + return res.status(200).json(data); + } catch (e) { + next(e); + } + } } module.exports = ResultController; diff --git a/backend/api/routes/result.js b/backend/api/routes/result.js index bf2f261ab..7ad23bdd9 100644 --- a/backend/api/routes/result.js +++ b/backend/api/routes/result.js @@ -12,4 +12,15 @@ router.post("/updateTags", authenticateRequest, ResultController.updateTags); router.post("/deleteAll", authenticateRequest, ResultController.deleteAll); +router.get( + "/getLeaderboard/:type/:mode/:mode2", + ResultController.getLeaderboard +); + +router.post( + "/checkLeaderboardQualification", + authenticateRequest, + ResultController.checkLeaderboardQualification +); + module.exports = router; diff --git a/backend/dao/result.js b/backend/dao/result.js index 53f5384e4..6fda9c756 100644 --- a/backend/dao/result.js +++ b/backend/dao/result.js @@ -60,6 +60,116 @@ class ResultDAO { if (!result) throw new MonkeyError(404, "Result not found"); return result; } + + static async getLeaderboard(type, mode, mode2) { + let count; + let startDate = new Date(); + let start = 0; + if (type == "global") count = 999; + else if (type == "daily") { + count = 100; + startDate.setUTCHours(0, 0, 0, 0); // next midnight UTC + start = startDate.getTime(); + } + const leaders = await mongoDB() + .collection("results") + .aggregate([ + { + $match: { + mode: mode, + mode2: parseInt(mode2), + timestamp: { $gt: start }, + }, + }, + { $sort: { wpm: -1 } }, + { + $group: { + _id: "$name", + doc: { $first: "$$ROOT" }, + }, + }, + { + $replaceRoot: { + newRoot: "$doc", + }, + }, + { $limit: count }, + ]) + .toArray(); + let board = []; + leaders.forEach((entry) => { + board.push({ + name: entry.name, + wpm: entry.wpm, + acc: entry.acc, + raw: entry.rawWpm, + consistency: entry.consistency, + mode: entry.mode, + mode2: entry.mode2, + timestamp: entry.timestamp, + }); + }); + board.sort((a, b) => { + return b.wpm - a.wpm; + }); + let leaderboard = { + type: type, + size: board.length, + board: board, + }; + if (type == "daily") { + var d = new Date(); + d.setUTCHours(24, 0, 0, 0); // next midnight UTC + leaderboard.resetTime = d; + } + return leaderboard; + } + + static async checkLeaderboardQualification(uid, result) { + function processLb(user, lb, result) { + let board = lb.board; + let data = {}; + data.foundAt = board.indexOf( + board.find((entry) => entry.name === user.name) + ); + let maxSize = 100; + if (lb.type === "global") maxSize = 999; + if ( + result.wpm < board[board.length - 1].wpm && + board.length === maxSize + ) { + data.insertedAt = -1; + } else { + for (let i = board.length - 1; i > 0; i--) { + if (result.wpm < board[i].wpm) { + data.insertedAt = i + 1; + break; + } + } + if (data.insertedAt === undefined) data.insertedAt = 0; + } + return data; + } + + const user = await mongoDB().collection("users").findOne({ uid: uid }); + //might need to check if email is verified with firebase + if (user.emailVerified === false) return { needsToVerifyEmail: true }; + if (user.name === undefined) return { noName: true }; + if (user.banned) return { banned: true }; + const globalLb = await this.getLeaderboard( + "global", + result.mode, + result.mode2 + ); + const dailyLb = await this.getLeaderboard( + "daily", + result.mode, + result.mode2 + ); + const globalData = processLb(user, globalLb, result); + const dailyData = processLb(user, dailyLb, result); + return { global: globalData, daily: dailyData }; + } } module.exports = ResultDAO; diff --git a/src/js/elements/leaderboards.js b/src/js/elements/leaderboards.js index 0198fe912..188377f18 100644 --- a/src/js/elements/leaderboards.js +++ b/src/js/elements/leaderboards.js @@ -30,8 +30,12 @@ function update() { Loader.show(); Promise.all([ - axiosInstance.get(`/getLeaderboard/daily/${boardinfo[0]}/${boardinfo[1]}`), - axiosInstance.get(`/getLeaderboard/global/${boardinfo[0]}/${boardinfo[1]}`), + axiosInstance.get( + `/results/getLeaderboard/daily/${boardinfo[0]}/${boardinfo[1]}` + ), + axiosInstance.get( + `/results/getLeaderboard/global/${boardinfo[0]}/${boardinfo[1]}` + ), ]) .then((lbdata) => { Loader.hide(); diff --git a/src/js/test/test-leaderboards.js b/src/js/test/test-leaderboards.js index cdfe05a47..c1b1166fc 100644 --- a/src/js/test/test-leaderboards.js +++ b/src/js/test/test-leaderboards.js @@ -161,7 +161,7 @@ export async function check(completedEvent) { delete lbRes.keyDuration; delete lbRes.chartData; axiosInstance - .post("/attemptAddToLeaderboards", { + .post("/results/checkLeaderboardQualification", { result: lbRes, }) .then((data) => {