diff --git a/backend/api/controllers/leaderboards.js b/backend/api/controllers/leaderboards.js
new file mode 100644
index 000000000..6a211ee73
--- /dev/null
+++ b/backend/api/controllers/leaderboards.js
@@ -0,0 +1,38 @@
+const LeaderboardsDAO = require("../../dao/leaderboards");
+
+class LeaderboardsController {
+ static async get(req, res, next) {
+ try {
+ const { language, mode, mode2 } = req.query;
+ if (!language || !mode || !mode2) {
+ return res.status(400).json({
+ message: "Missing parameters",
+ });
+ }
+ let retval = await LeaderboardsDAO.get(mode, mode2, language);
+ retval.forEach((item) => {
+ delete item.uid;
+ });
+ return res.status(200).json(retval);
+ } catch (e) {
+ return next(e);
+ }
+ }
+
+ static async update(req, res, next) {
+ try {
+ const { language, mode, mode2 } = req.body;
+ if (!language || !mode || !mode2) {
+ return res.status(400).json({
+ message: "Missing parameters",
+ });
+ }
+ let retval = await LeaderboardsDAO.update(mode, mode2, language);
+ return res.status(200).json(retval);
+ } catch (e) {
+ return next(e);
+ }
+ }
+}
+
+module.exports = LeaderboardsController;
diff --git a/backend/api/routes/leaderboards.js b/backend/api/routes/leaderboards.js
new file mode 100644
index 000000000..ea2a9df6b
--- /dev/null
+++ b/backend/api/routes/leaderboards.js
@@ -0,0 +1,22 @@
+const { authenticateRequest } = require("../../middlewares/auth");
+const LeaderboardsController = require("../controllers/leaderboards");
+const RateLimit = require("../../middlewares/rate-limit");
+
+const { Router } = require("express");
+
+const router = Router();
+
+router.get(
+ "/",
+ RateLimit.limit1persec,
+ authenticateRequest,
+ LeaderboardsController.get
+);
+
+router.post(
+ "/debug_update",
+ RateLimit.limit1persec,
+ LeaderboardsController.update
+);
+
+module.exports = router;
diff --git a/backend/dao/leaderboards.js b/backend/dao/leaderboards.js
new file mode 100644
index 000000000..39dabea8d
--- /dev/null
+++ b/backend/dao/leaderboards.js
@@ -0,0 +1,126 @@
+const MonkeyError = require("../handlers/error");
+const { mongoDB } = require("../init/mongodb");
+const { ObjectID } = require("mongodb");
+
+class LeaderboardsDAO {
+ static async get(mode, mode2, language) {
+ const preset = await mongoDB()
+ .collection(`leaderboards.${language}.${mode}.${mode2}`)
+ .find()
+ .toArray();
+ return preset;
+ }
+
+ static async getRank(mode, mode2, language, uid) {
+ const res = await mongoDB()
+ .collection(`leaderboards.${language}.${mode}.${mode2}`)
+ .findOne({ uid });
+ return res.rank;
+ }
+
+ static async update(mode, mode2, language, uid = undefined) {
+ let str = `personalBests.${mode}.${mode2}`;
+ let lb = await mongoDB()
+ .collection("users")
+ .aggregate([
+ {
+ $unset: [
+ "_id",
+ "addedAt",
+ "email",
+ "oldTypingStats",
+ "tags",
+ "bananas",
+ "discordId",
+ "timeTyping",
+ "startedTests",
+ "completedTests",
+ ],
+ },
+ {
+ $match: {
+ banned: {
+ $exists: false,
+ },
+ [str]: {
+ $elemMatch: {
+ language: "english",
+ difficulty: "normal",
+ timestamp: {
+ $exists: true,
+ },
+ },
+ },
+ },
+ },
+ {
+ $replaceWith: {
+ name: "$name",
+ uid: "$uid",
+ result: "$" + str,
+ },
+ },
+ {
+ $unwind: {
+ path: "$result",
+ },
+ },
+ {
+ $match: {
+ "result.language": language,
+ "result.difficulty": "normal",
+ "result.punctuation": false,
+ },
+ },
+ {
+ $set: {
+ "result.name": "$name",
+ "result.uid": "$uid",
+ },
+ },
+ {
+ $replaceRoot: {
+ newRoot: "$result",
+ },
+ },
+ {
+ $sort: {
+ wpm: -1,
+ acc: -1,
+ timestamp: -1,
+ },
+ },
+ ])
+ .toArray();
+
+ let rerval = undefined;
+ lb.forEach((lbEntry, index) => {
+ lbEntry.rank = index + 1;
+ if (uid && lbEntry.uid === uid) {
+ rerval = index + 1;
+ }
+ });
+
+ try {
+ await mongoDB()
+ .collection(`leaderboards.${language}.${mode}.${mode2}`)
+ .drop();
+ } catch (e) {}
+ await mongoDB()
+ .collection(`leaderboards.${language}.${mode}.${mode2}`)
+ .insertMany(lb);
+
+ if (rerval) {
+ return {
+ message: "Successfully updated leaderboard",
+ rank: retval,
+ };
+ } else {
+ return {
+ message: "Successfully updated leaderboard",
+ };
+ }
+ }
+}
+
+module.exports = LeaderboardsDAO;
diff --git a/src/js/elements/leaderboards.js b/src/js/elements/leaderboards.js
index 902a3f543..1afac8ad3 100644
--- a/src/js/elements/leaderboards.js
+++ b/src/js/elements/leaderboards.js
@@ -30,87 +30,66 @@ function update() {
Loader.show();
Promise.all([
- axiosInstance.get(
- `/results/getLeaderboard/daily/${boardinfo[0]}/${boardinfo[1]}`
- ),
- axiosInstance.get(
- `/results/getLeaderboard/global/${boardinfo[0]}/${boardinfo[1]}`
- ),
+ axiosInstance.get(`/leaderboards`, {
+ params: {
+ language: "english",
+ mode: "time",
+ mode2: "15",
+ },
+ }),
+ axiosInstance.get(`/leaderboards`, {
+ params: {
+ language: "english",
+ mode: "time",
+ mode2: "60",
+ },
+ }),
])
.then((lbdata) => {
Loader.hide();
- let dailyData = lbdata[0].data;
- let globalData = lbdata[1].data;
+ let time15data = lbdata[0].data;
+ let time60data = lbdata[1].data;
- //daily
- let nextReset = new Date(dailyData.resetTime);
- let diffAsDate = new Date(nextReset - Date.now());
-
- let diffHours = diffAsDate.getUTCHours();
- let diffMinutes = diffAsDate.getUTCMinutes();
- let diffSeconds = diffAsDate.getUTCSeconds();
-
- let resetString = "";
- if (diffHours > 0) {
- resetString = `resets in ${diffHours} ${
- diffHours == 1 ? "hour" : "hours"
- } ${diffMinutes} ${diffMinutes == 1 ? "minute" : "minutes"}
- `;
- } else if (diffMinutes > 0) {
- resetString = `resets in ${diffMinutes} ${
- diffMinutes == 1 ? "minute" : "minutes"
- } ${diffSeconds} ${diffSeconds == 1 ? "second" : "seconds"}`;
- } else if (diffSeconds > 0) {
- resetString = `resets in ${diffSeconds} ${
- diffSeconds == 1 ? "second" : "seconds"
- }`;
- }
-
- $("#leaderboardsWrapper .subtitle").text(resetString);
-
- $("#leaderboardsWrapper table.daily tfoot").html(`
+ $("#leaderboardsWrapper table.left tfoot").html(`
|
Not qualified>
|
|
`);
- //daily
- $("#leaderboardsWrapper table.daily tbody").empty();
+ //left
+ $("#leaderboardsWrapper table.left tbody").empty();
let dindex = 0;
- if (dailyData.board !== undefined) {
- dailyData.board.forEach((entry) => {
+ if (time15data !== undefined) {
+ time15data.forEach((entry) => {
if (entry.hidden) return;
let meClassString = "";
- //hacky way to get username because auth().currentUser.name isn't working after mongo switch
- if (DB.getSnapshot() && entry.name == DB.getSnapshot().name) {
+ if (entry.name == DB.getSnapshot().name) {
meClassString = ' class="me"';
- $("#leaderboardsWrapper table.daily tfoot").html(`
-
- ${dindex + 1} |
- You |
- ${entry.wpm.toFixed(
- 2
- )}
${entry.acc.toFixed(2)}% |
- ${entry.raw.toFixed(
- 2
- )}
${
+ $("#leaderboardsWrapper table.left tfoot").html(`
+
+ ${dindex + 1} |
+ You |
+ ${entry.wpm.toFixed(
+ 2
+ )}
${entry.acc.toFixed(2)}% |
+ ${entry.raw.toFixed(
+ 2
+ )}
${
entry.consistency === "-"
? "-"
: entry.consistency.toFixed(2) + "%"
} |
- ${entry.mode}
${
- entry.mode2
- } |
- ${moment(entry.timestamp).format(
- "DD MMM YYYY"
- )}
${moment(entry.timestamp).format(
+ time
15 |
+ ${moment(entry.timestamp).format(
+ "DD MMM YYYY"
+ )}
${moment(entry.timestamp).format(
"HH:mm"
)} |
- |
+ |
`);
}
- $("#leaderboardsWrapper table.daily tbody").append(`
+ $("#leaderboardsWrapper table.left tbody").append(`
${
dindex === 0 ? '' : dindex + 1
@@ -122,9 +101,7 @@ function update() {
| ${entry.raw.toFixed(2)}
${
entry.consistency === "-" ? "-" : entry.consistency.toFixed(2) + "%"
} |
- ${entry.mode}
${
- entry.mode2
- } |
+ time
15 |
${moment(entry.timestamp).format(
"DD MMM YYYY"
)}
${moment(entry.timestamp).format(
@@ -135,24 +112,8 @@ function update() {
dindex++;
});
}
- let lenDaily = 0;
- if (dailyData.board !== undefined) lenDaily = dailyData.board.length;
- if (dailyData.length === 0 || lenDaily !== dailyData.size) {
- for (let i = lenDaily; i < dailyData.size; i++) {
- $("#leaderboardsWrapper table.daily tbody").append(`
-
- ${i + 1} |
- - |
- - |
- - |
- - |
- - - |
-
- `);
- }
- }
- $("#leaderboardsWrapper table.global tfoot").html(`
+ $("#leaderboardsWrapper table.right tfoot").html(`
|
Not qualified>
@@ -160,15 +121,15 @@ function update() {
|
`);
//global
- $("#leaderboardsWrapper table.global tbody").empty();
+ $("#leaderboardsWrapper table.right tbody").empty();
let index = 0;
- if (globalData.board !== undefined) {
- globalData.board.forEach((entry) => {
+ if (time60data !== undefined) {
+ time60data.forEach((entry) => {
if (entry.hidden) return;
let meClassString = "";
- if (DB.getSnapshot() && entry.name == DB.getSnapshot().name) {
+ if (entry.name == DB.getSnapshot().name) {
meClassString = ' class="me"';
- $("#leaderboardsWrapper table.global tfoot").html(`
+ $("#leaderboardsWrapper table.right tfoot").html(`
${index + 1} |
You |
@@ -182,9 +143,7 @@ function update() {
? "-"
: entry.consistency.toFixed(2) + "%"
}
- ${entry.mode}
${
- entry.mode2
- } |
+ time
60 |
${moment(entry.timestamp).format(
"DD MMM YYYY"
)}
${moment(entry.timestamp).format(
@@ -193,7 +152,7 @@ function update() {
|
`);
}
- $("#leaderboardsWrapper table.global tbody").append(`
+ $("#leaderboardsWrapper table.right tbody").append(`
${
index === 0 ? '' : index + 1
@@ -205,9 +164,7 @@ function update() {
| ${entry.raw.toFixed(2)}
${
entry.consistency === "-" ? "-" : entry.consistency.toFixed(2) + "%"
} |
- ${entry.mode}
${
- entry.mode2
- } |
+ time
60 |
${moment(entry.timestamp).format(
"DD MMM YYYY"
)}
${moment(entry.timestamp).format(
@@ -218,22 +175,6 @@ function update() {
index++;
});
}
- let lenGlobal = 0;
- if (globalData.board !== undefined) lenGlobal = globalData.board.length;
- if (globalData.length === 0 || lenGlobal !== globalData.size) {
- for (let i = lenGlobal; i < globalData.size; i++) {
- $("#leaderboardsWrapper table.global tbody").append(`
- |
- ${i + 1} |
- - |
- - |
- - |
- - |
- - - |
-
- `);
- }
- }
})
.catch((e) => {
Loader.hide();
diff --git a/src/sass/style.scss b/src/sass/style.scss
index e96c2f5c5..82b9608a1 100644
--- a/src/sass/style.scss
+++ b/src/sass/style.scss
@@ -452,16 +452,16 @@ a:hover {
}
}
- .globalTableWrapper,
- .dailyTableWrapper {
+ .leftTableWrapper,
+ .rightTableWrapper {
height: calc(100vh - 22rem);
@extend .ffscroll;
overflow-y: scroll;
overflow-x: auto;
}
- .globalTableWrapper::-webkit-scrollbar,
- .dailyTableWrapper::-webkit-scrollbar {
+ .leftTableWrapper::-webkit-scrollbar,
+ .rightTableWrapper::-webkit-scrollbar {
height: 5px;
width: 5px;
}
diff --git a/static/index.html b/static/index.html
index 0822ef4b9..3d90a8c7d 100644
--- a/static/index.html
+++ b/static/index.html
@@ -388,9 +388,9 @@
- Global
-
-
+ English Time 15
+
+
# |
@@ -670,10 +670,10 @@
- Daily
+ English Time 60
-
- |