From 772ba8ecba4edfff899aeaeb9fb623dfcc9ffaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 14:23:15 +0700 Subject: [PATCH 01/15] Fix incorrect `count` variable --- src/data/database.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index 3fd66c41..7c39cbaf 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -244,9 +244,11 @@ async function updateUserPassword(user_id, old_pass, new_pass) { /** * Count number of submissions */ -function countSubmissions() { +function countSubmissions(user_id) { + let query = {}; + if (user_id) query = { user_id }; return new Promise((resolve, reject) => { - db.submissions.count({}, function(err, count) { + db.submissions.count(query, function(err, count) { if (err) reject(err); else resolve(count); }); @@ -356,7 +358,7 @@ function readSubmission(sub_id) { */ async function readUserSubmission(user_id, page, size, count) { const username = await readUserByID(user_id); - const maxSize = await countSubmissions(); + const maxSize = await countSubmissions(user_id); ({ page, size, count } = verifySubsQuery(page, size, count, maxSize)); return new Promise((resolve, reject) => { From 1e3b9650b097848a32e8144f5fc6a45b1f9514b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 14:48:00 +0700 Subject: [PATCH 02/15] Fix incorrect username returned --- src/data/database.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index 7c39cbaf..c041e899 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -357,7 +357,7 @@ function readSubmission(sub_id) { * @returns {Promise>} Array of user's submissions if success */ async function readUserSubmission(user_id, page, size, count) { - const username = await readUserByID(user_id); + const userData = await readUserByID(user_id); const maxSize = await countSubmissions(user_id); ({ page, size, count } = verifySubsQuery(page, size, count, maxSize)); @@ -383,7 +383,7 @@ async function readUserSubmission(user_id, page, size, count) { if (err) reject(err); else { let serialized = docs.map((doc) => { - doc.username = username; + doc.username = userData.username; return doc; }); resolve({ From 576ab5afe02556e27f9aab610c0ccdd9751aa379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 14:57:41 +0700 Subject: [PATCH 03/15] Add username in return of readSubmission --- src/data/database.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/data/database.js b/src/data/database.js index c041e899..1d9ef5d4 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -341,7 +341,15 @@ function readSubmission(sub_id) { if (err) reject(err); else if (docs === null) reject(new Error(`Invalid Submission's ID: ${sub_id}`)); - else resolve(docs); + + readUserByID(docs.user_id) + .then((res) => { + docs.username = res.username; + resolve(docs); + }) + .catch((err) => { + reject(err); + }); } ); }); From a877ce965a8fc2a011d1acee90d46a48a038b7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 15:11:37 +0700 Subject: [PATCH 04/15] Still resolve even if user_id is invalid --- src/data/database.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index 1d9ef5d4..51d6623e 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -345,10 +345,9 @@ function readSubmission(sub_id) { readUserByID(docs.user_id) .then((res) => { docs.username = res.username; - resolve(docs); }) - .catch((err) => { - reject(err); + .finally(() => { + resolve(docs); }); } ); From d94d5e834995e57baee03f7c4f6335a166f712e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 15:12:01 +0700 Subject: [PATCH 05/15] Allow admin to read seperate submissions --- src/routes/subs.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/subs.js b/src/routes/subs.js index 5382f752..e9435892 100644 --- a/src/routes/subs.js +++ b/src/routes/subs.js @@ -56,7 +56,8 @@ router router.get("/:id", (req, res) => { readSubmission(req.params.id).then( (docs) => { - if (docs.user_id === req.user._id) res.send(docs); + if (docs.user_id === req.user._id || req.user.isAdmin) + res.send(docs); else res.sendStatus(401); }, (err) => { From 18fb5218e6b32e1da986e4dedca7d6feef51544f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 15:20:50 +0700 Subject: [PATCH 06/15] Add else to do the right condition --- src/data/database.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index 51d6623e..295e7523 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -341,14 +341,14 @@ function readSubmission(sub_id) { if (err) reject(err); else if (docs === null) reject(new Error(`Invalid Submission's ID: ${sub_id}`)); - - readUserByID(docs.user_id) - .then((res) => { - docs.username = res.username; - }) - .finally(() => { - resolve(docs); - }); + else + readUserByID(docs.user_id) + .then((res) => { + docs.username = res.username; + }) + .finally(() => { + resolve(docs); + }); } ); }); From 58faaab7f172bc7a6f2f52098a249d13df60f3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 15:54:29 +0700 Subject: [PATCH 07/15] Add feature to read submission's source --- src/data/database.js | 27 +++++++++++++++++++++++++++ src/routes/subs.js | 18 +++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/data/database.js b/src/data/database.js index 3fd66c41..89ee8552 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -395,6 +395,32 @@ async function readUserSubmission(user_id, page, size, count) { }); } +/** + * Read Submission's source + * @param {String} sub_id Submission's ID + */ +function readSubmissionSrc(sub_id) { + return new Promise((resolve, reject) => { + db.submissions.findOne( + { _id: sub_id }, + { ext: 1, user_id: 1, prob_id: 1, source_code: 1 }, + (err, docs) => { + if (err) reject(err); + else if (docs === null) + reject(new Error(`Invalid Submission's ID: ${sub_id}`)); + else + readUserByID(docs.user_id) + .then((res) => { + docs.username = res.username; + }) + .finally(() => { + resolve(docs); + }); + } + ); + }); +} + /** * Add submission to database * @param {String} source_code Source Code @@ -557,6 +583,7 @@ module.exports = { readAllSubmissions, readSubmission, readUserSubmission, + readSubmissionSrc, newSubmission, updateSubmission, readLastSatisfy, diff --git a/src/routes/subs.js b/src/routes/subs.js index 5382f752..36f9bcf7 100644 --- a/src/routes/subs.js +++ b/src/routes/subs.js @@ -6,7 +6,8 @@ const { sendCode } = require("../controller/submitCode"); const { readSubmission, readAllSubmissions, - readUserSubmission + readUserSubmission, + readSubmissionSrc } = require("../data/database"); const auth = require("../middleware/auth"); const bruteForce = require("../middleware/bruteForce"); @@ -65,4 +66,19 @@ router.get("/:id", (req, res) => { ); }); +router.get("/:id/source", (req, res) => { + readSubmissionSrc(req.params.id) + .then((docs) => { + if (docs.user_id === req.user._id || req.user.isAdmin) + res.download( + docs.source_code, + "".concat(docs.prob_id, docs.ext) + ); + else res.sendStatus(401); + }) + .catch((err) => { + res.status(400).json(err.message); + }); +}); + module.exports = router; From bcf22fbd5b4915a9293997e6ec703ec0b3ec8e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 15:57:53 +0700 Subject: [PATCH 08/15] Use submission's id instead of problem id --- src/data/database.js | 2 +- src/routes/subs.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index 89ee8552..b14609a4 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -403,7 +403,7 @@ function readSubmissionSrc(sub_id) { return new Promise((resolve, reject) => { db.submissions.findOne( { _id: sub_id }, - { ext: 1, user_id: 1, prob_id: 1, source_code: 1 }, + { ext: 1, user_id: 1, source_code: 1 }, (err, docs) => { if (err) reject(err); else if (docs === null) diff --git a/src/routes/subs.js b/src/routes/subs.js index 36f9bcf7..701318a7 100644 --- a/src/routes/subs.js +++ b/src/routes/subs.js @@ -72,7 +72,7 @@ router.get("/:id/source", (req, res) => { if (docs.user_id === req.user._id || req.user.isAdmin) res.download( docs.source_code, - "".concat(docs.prob_id, docs.ext) + "".concat(docs.req.params.id, docs.ext) ); else res.sendStatus(401); }) From 09774c8ae2ea039c4711e9e2e2baf92d63c9741a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 16:00:31 +0700 Subject: [PATCH 09/15] Does not allow space in prob_id and ext_id --- src/util/config/contestConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/config/contestConfig.js b/src/util/config/contestConfig.js index 7aa425d4..e84b3b6a 100644 --- a/src/util/config/contestConfig.js +++ b/src/util/config/contestConfig.js @@ -23,7 +23,7 @@ function parseContainer(container) { if (!Array.isArray(container)) throw new Error("Invalid Container"); let parsedContainer = container .filter((x) => typeof x === "string") - .map((x) => x.trim().toUpperCase()) + .map((x) => x.toUpperCase().replace(" ", "")) .sort((a, b) => a.localeCompare(b)); return [...new Set(parsedContainer)]; } From 349a874b3c351751f9f525a3cf77f1b716a07c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Thu, 7 Mar 2019 16:09:39 +0700 Subject: [PATCH 10/15] Seperate function --- src/data/database.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index 295e7523..fdb50999 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -244,11 +244,22 @@ async function updateUserPassword(user_id, old_pass, new_pass) { /** * Count number of submissions */ -function countSubmissions(user_id) { - let query = {}; - if (user_id) query = { user_id }; +function countAllSubmissions() { return new Promise((resolve, reject) => { - db.submissions.count(query, function(err, count) { + db.submissions.count({}, function(err, count) { + if (err) reject(err); + else resolve(count); + }); + }); +} + +/** + * Count number of submissions from user_id + * @param {String} user_id User's ID + */ +function countUserSubmissions(user_id) { + return new Promise((resolve, reject) => { + db.submissions.count({ user_id }, function(err, count) { if (err) reject(err); else resolve(count); }); @@ -274,7 +285,7 @@ function verifySubsQuery(page, size, count, maxSize) { * @returns {Promise>} Array of submission if success */ async function readAllSubmissions(page, size, count) { - const maxSize = await countSubmissions(); + const maxSize = await countAllSubmissions(); ({ page, size, count } = verifySubsQuery(page, size, count, maxSize)); return new Promise((resolve, reject) => { @@ -365,7 +376,7 @@ function readSubmission(sub_id) { */ async function readUserSubmission(user_id, page, size, count) { const userData = await readUserByID(user_id); - const maxSize = await countSubmissions(user_id); + const maxSize = await countUserSubmissions(user_id); ({ page, size, count } = verifySubsQuery(page, size, count, maxSize)); return new Promise((resolve, reject) => { @@ -563,6 +574,8 @@ module.exports = { readUserPassHash, updateUserName, updateUserPassword, + countAllSubmissions, + countUserSubmissions, readAllSubmissions, readSubmission, readUserSubmission, From ea46bb0aee60afff2fad243d40b38aaf82f35d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Fri, 8 Mar 2019 14:17:49 +0700 Subject: [PATCH 11/15] Fix problem where file is not returned --- src/routes/subs.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/routes/subs.js b/src/routes/subs.js index d4a3a314..21b4fbbb 100644 --- a/src/routes/subs.js +++ b/src/routes/subs.js @@ -71,10 +71,7 @@ router.get("/:id/source", (req, res) => { readSubmissionSrc(req.params.id) .then((docs) => { if (docs.user_id === req.user._id || req.user.isAdmin) - res.download( - docs.source_code, - "".concat(docs.req.params.id, docs.ext) - ); + res.download(docs.source_code, "".concat(docs._id, docs.ext)); else res.sendStatus(401); }) .catch((err) => { From 9f1283c5db02de309514379cd3e97ce604897ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Fri, 8 Mar 2019 14:29:37 +0700 Subject: [PATCH 12/15] Hide ENOENT error with 404 --- src/routes/subs.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/routes/subs.js b/src/routes/subs.js index 21b4fbbb..4dcd2f48 100644 --- a/src/routes/subs.js +++ b/src/routes/subs.js @@ -1,6 +1,7 @@ "use strict"; const express = require("express"); +const { existsSync } = require("fs"); const { sendCode } = require("../controller/submitCode"); const { @@ -70,9 +71,14 @@ router.get("/:id", (req, res) => { router.get("/:id/source", (req, res) => { readSubmissionSrc(req.params.id) .then((docs) => { - if (docs.user_id === req.user._id || req.user.isAdmin) - res.download(docs.source_code, "".concat(docs._id, docs.ext)); - else res.sendStatus(401); + if (docs.user_id === req.user._id || req.user.isAdmin) { + if (!existsSync(docs.source_code)) res.sendStatus(404); + else + res.download( + docs.source_code, + "".concat(docs._id, docs.ext) + ); + } else res.sendStatus(401); }) .catch((err) => { res.status(400).json(err.message); From 762211197d5b40e4183ab30f35ac0fa87213106b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Fri, 8 Mar 2019 14:34:55 +0700 Subject: [PATCH 13/15] convert to lowercase extension --- src/routes/subs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/subs.js b/src/routes/subs.js index 4dcd2f48..6efcb5c1 100644 --- a/src/routes/subs.js +++ b/src/routes/subs.js @@ -76,7 +76,7 @@ router.get("/:id/source", (req, res) => { else res.download( docs.source_code, - "".concat(docs._id, docs.ext) + "".concat(docs._id, docs.ext.toLowerCase()) ); } else res.sendStatus(401); }) From a33ef07490c1c41b10ab1860238ca4b0037d24e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Fri, 8 Mar 2019 19:44:51 +0700 Subject: [PATCH 14/15] Fix replace function --- src/util/config/contestConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/config/contestConfig.js b/src/util/config/contestConfig.js index e84b3b6a..b66301ff 100644 --- a/src/util/config/contestConfig.js +++ b/src/util/config/contestConfig.js @@ -23,7 +23,7 @@ function parseContainer(container) { if (!Array.isArray(container)) throw new Error("Invalid Container"); let parsedContainer = container .filter((x) => typeof x === "string") - .map((x) => x.toUpperCase().replace(" ", "")) + .map((x) => x.replace(/\s/g, "").toUpperCase()) .sort((a, b) => a.localeCompare(b)); return [...new Set(parsedContainer)]; } From f41544b2a710da831744e3a7fe0a8a824ff469ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tu=E1=BA=A5n=20D=C5=A9ng?= Date: Mon, 1 Apr 2019 20:16:40 +0700 Subject: [PATCH 15/15] Patch unhandled promise in readAllSubmissions --- src/data/database.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/data/database.js b/src/data/database.js index c42e50a4..c4921572 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -310,10 +310,11 @@ async function readAllSubmissions(page, size, count) { // TODO: Decide what to do when there's invalid user // Currently, it will throw error with invalid user_id if (err) reject(err); - else - Promise.all( - docs.map((doc) => readUserByID(doc.user_id)) - ).then((usernameList) => { + else { + let usernameListPromise = docs.map((doc) => + readUserByID(doc.user_id).catch(() => null) + ); + Promise.all(usernameListPromise).then((usernameList) => { let serialized = docs.map((doc, idx) => { doc.username = usernameList[idx].username; return doc; @@ -325,6 +326,7 @@ async function readAllSubmissions(page, size, count) { count: count }); }); + } }); }); }