From c1bc9c6e505eedf7124d4bcfc47625fbf5b9138c Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 21:22:08 -0500 Subject: [PATCH 01/10] Added backend documentation to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5247dcd..a29d2e6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ## BDPA NHSCC 2022 Problem: - [Problem Statement](https://github.com/nhscc/problem-statements/tree/main/2022/qoverflow) +- [Backend Documentation](https://hscc8udvc7gs.docs.apiary.io/) ## Solution From b55e4d996626f7125d5c9c4e9fe05a2fb395c977 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 22:28:25 -0500 Subject: [PATCH 02/10] Fixed cronjobs --- client/package.json | 1 + package-lock.json | 117 ++++++++++++++++++++++++++++++++- server/bin/www | 12 +++- server/routes/user/Register.js | 4 +- server/utils/cronRefresh.js | 5 +- server/utils/getData.js | 65 ++++++++++++++---- 6 files changed, 182 insertions(+), 22 deletions(-) diff --git a/client/package.json b/client/package.json index c5869e6..f712e4c 100644 --- a/client/package.json +++ b/client/package.json @@ -17,6 +17,7 @@ "js-cookie": "^3.0.1", "nvm": "^0.0.4", "react": "^18.2.0", + "react-gravatar": "^2.6.3", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", "react-router-dom": "^6.3.0", diff --git a/package-lock.json b/package-lock.json index f7ec7a8..9dc2f59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "js-cookie": "^3.0.1", "nvm": "^0.0.4", "react": "^18.2.0", + "react-gravatar": "^2.6.3", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", "react-router-dom": "^6.3.0", @@ -5549,6 +5550,14 @@ "version": "1.2.1", "license": "MIT" }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, "node_modules/charm": { "version": "0.1.2", "license": "MIT/X11" @@ -6020,6 +6029,14 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, "node_modules/crypto-js": { "version": "4.1.1", "license": "MIT" @@ -9472,6 +9489,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-retina": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-retina/-/is-retina-1.0.3.tgz", + "integrity": "sha512-/tCmbIETZwCd8uHWO+GvbRa7jxwHFHdfetHfiwoP0aN9UDf3prUJMtKn7iBFYipYhqY1bSTjur8hC/Dakt8eyw==" + }, "node_modules/is-root": { "version": "2.1.0", "license": "MIT", @@ -12491,6 +12513,16 @@ "tmpl": "1.0.5" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/mdast-util-definitions": { "version": "5.1.1", "license": "MIT", @@ -15575,6 +15607,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==", + "dependencies": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "funding": [ @@ -15856,6 +15900,19 @@ "version": "2.0.4", "license": "MIT" }, + "node_modules/react-gravatar": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-gravatar/-/react-gravatar-2.6.3.tgz", + "integrity": "sha512-yITonigS2LmG7Fw0gWfZfcVwy1mpiBHNVmoFyetitQjXu7JCYoE6jtub0GIfq+ydpnQSYyJT3kwpX6zj1wXR4w==", + "dependencies": { + "is-retina": "^1.0.3", + "md5": "^2.1.0", + "query-string": "^4.2.2" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-helmet": { "version": "6.1.0", "license": "MIT", @@ -18020,6 +18077,14 @@ "node": ">= 0.8" } }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "license": "MIT", @@ -23572,6 +23637,11 @@ "character-parser": { "version": "1.2.1" }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" + }, "charm": { "version": "0.1.2" }, @@ -23865,6 +23935,11 @@ "which": "^2.0.1" } }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" + }, "crypto-js": { "version": "4.1.1" }, @@ -25907,6 +25982,11 @@ "is-regexp": { "version": "1.0.0" }, + "is-retina": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-retina/-/is-retina-1.0.3.tgz", + "integrity": "sha512-/tCmbIETZwCd8uHWO+GvbRa7jxwHFHdfetHfiwoP0aN9UDf3prUJMtKn7iBFYipYhqY1bSTjur8hC/Dakt8eyw==" + }, "is-root": { "version": "2.1.0" }, @@ -27809,6 +27889,16 @@ "tmpl": "1.0.5" } }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "mdast-util-definitions": { "version": "5.1.1", "requires": { @@ -29461,7 +29551,7 @@ "@emotion/styled": "^11.9.3", "@mui/icons-material": "^5.8.4", "@mui/material": "^5.9.1", - "acorn": "*", + "acorn": "^8.8.0", "crypto-js": "^4.1.1", "dotenv": "^16.0.1", "formik": "^2.2.9", @@ -29470,6 +29560,7 @@ "js-cookie": "^3.0.1", "nvm": "^0.0.4", "react": "^18.2.0", + "react-gravatar": "*", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", "react-router-dom": "^6.3.0", @@ -29495,6 +29586,15 @@ "side-channel": "^1.0.4" } }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==", + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "queue-microtask": { "version": "1.2.3" }, @@ -29665,6 +29765,16 @@ "react-fast-compare": { "version": "2.0.4" }, + "react-gravatar": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-gravatar/-/react-gravatar-2.6.3.tgz", + "integrity": "sha512-yITonigS2LmG7Fw0gWfZfcVwy1mpiBHNVmoFyetitQjXu7JCYoE6jtub0GIfq+ydpnQSYyJT3kwpX6zj1wXR4w==", + "requires": { + "is-retina": "^1.0.3", + "md5": "^2.1.0", + "query-string": "^4.2.2" + } + }, "react-helmet": { "version": "6.1.0", "requires": { @@ -31087,6 +31197,11 @@ "statuses": { "version": "2.0.1" }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==" + }, "string_decoder": { "version": "1.3.0", "requires": { diff --git a/server/bin/www b/server/bin/www index 960c48f..ab7082b 100644 --- a/server/bin/www +++ b/server/bin/www @@ -36,8 +36,13 @@ mongoose.connect(process.env.DB_CONN_STRING, { useUnifiedTopology: true, }); -mongoose.connection.once('open', () => console.log('MongoDB connected')); -mongoose.connection.on('error', console.error.bind(console, 'MongoDB connection error:')); +mongoose.connection.once('open', () => + console.log('[INFO]: MongoDB connected') +); +mongoose.connection.on( + 'error', + console.error.bind(console, '[ERROR]: MongoDB connection error - ') +); cron.schedule('*/30 * * * * *', refreshQuestions); cron.schedule('*/2 * * * *', refreshUsers); @@ -84,6 +89,7 @@ function onError(error) { function onListening() { const addr = server.address(); - const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; + const bind = + typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; debug('Listening on ' + bind); } diff --git a/server/routes/user/Register.js b/server/routes/user/Register.js index a2cc5b9..a696efd 100644 --- a/server/routes/user/Register.js +++ b/server/routes/user/Register.js @@ -12,7 +12,7 @@ async function Register(req, res) { const { salt, key } = await deriveKeyFromPassword(password); - const { success, error } = await createRequest('post', '/users', { + const { success, error, user } = await createRequest('post', '/users', { username, email, salt, @@ -29,7 +29,7 @@ async function Register(req, res) { return res.status(500).send(config.errorGeneric); } - await User.create({ username, email, salt }); + await User.create(user); return res.sendStatus(201); } diff --git a/server/utils/cronRefresh.js b/server/utils/cronRefresh.js index 5119e74..f516550 100644 --- a/server/utils/cronRefresh.js +++ b/server/utils/cronRefresh.js @@ -1,6 +1,7 @@ const { getAllQuestions, getAllUsers } = require('./getData'); async function refreshQuestions(_job, done) { + console.log('Im running'); await getAllQuestions(); done(); } @@ -11,5 +12,5 @@ async function refreshUsers(_job, done) { module.exports = { refreshQuestions, - refreshUsers -} \ No newline at end of file + refreshUsers, +}; diff --git a/server/utils/getData.js b/server/utils/getData.js index ee5af5a..0c17a0a 100644 --- a/server/utils/getData.js +++ b/server/utils/getData.js @@ -17,38 +17,75 @@ async function getAllData(Model, url, id, dataName) { return data; } -async function getAllAnswers({ question_id, username }) { +async function getAllAnswers(question_id, username) { if (question_id) - return getAllData(Answer, `/questions/${question_id}/answers`, 'answer_id', 'answers') + return getAllData( + Answer, + `/questions/${question_id}/answers`, + 'answer_id', + 'answers' + ); else if (username) - return getAllData(Answer, `/users/${username}/answers`, 'answer_id', 'answers') + return getAllData( + Answer, + `/users/${username}/answers`, + 'answer_id', + 'answers' + ); } -async function getAllComments({ answer_id, question_id }) { +async function getAllComments(answer_id, question_id) { if (answer_id) - return getAllData(Comment, `/questions/${question_id}/answers/${answer_id}/comments`, 'comment_id', 'comments') + return getAllData( + Comment, + `/questions/${question_id}/answers/${answer_id}/comments`, + 'comment_id', + 'comments' + ); else - return getAllData(Comment, `/questions/${question_id}/comments`, 'comment_id', 'comments') + return getAllData( + Comment, + `/questions/${question_id}/comments`, + 'comment_id', + 'comments' + ); } -async function getAllMail({ question_id }) { - return getAllData(Mail, `/questions/${question_id}/comments`, 'mail_id', 'mail') +async function getAllMail(question_id) { + return getAllData( + Mail, + `/questions/${question_id}/comments`, + 'mail_id', + 'mail' + ); } -async function getAllQuestions({ username }) { +async function getAllQuestions(username) { if (username) - return getAllData(Question, `/users/${username}/questions`, 'question_id', 'questions') - else - return getAllData(Question, `/questions/search`, 'question_id', 'questions') + return getAllData( + Question, + `/users/${username}/questions`, + 'question_id', + 'questions' + ); + else { + return getAllData( + Question, + `/questions/search`, + 'question_id', + 'questions' + ); + } } async function getAllUsers() { - return getAllData(User, `/users`, 'user_id', 'users') + return getAllData(User, `/users`, 'user_id', 'users'); } module.exports = { getAllAnswers, getAllComments, getAllQuestions, - getAllUsers + getAllUsers, + getAllMail, }; From 3be7f676ed83e062787e63e851f457180ab02270 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 22:31:30 -0500 Subject: [PATCH 03/10] Added /users/remember route to formatting --- server/openapi.yml | 131 ++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 55 deletions(-) diff --git a/server/openapi.yml b/server/openapi.yml index 4549572..f324b2a 100644 --- a/server/openapi.yml +++ b/server/openapi.yml @@ -45,13 +45,11 @@ paths: schema: type: object properties: - username: - type: string - minLength: 4 - maxLength: 16 email: type: string format: email + password: + type: string security: - BearerAuth: [] responses: @@ -159,6 +157,27 @@ paths: $ref: '#/components/responses/ServerError' tags: - users + /users/remember: + get: + summary: Retrieve authenticated data of the user + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + 'application/json': + schema: + type: object + properties: + user: + $ref: '#/components/schemas/User' + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/ServerError' + tags: + - users /users/logout: delete: summary: Login a user and receiver an authentication token @@ -344,11 +363,11 @@ paths: $ref: '#/components/responses/ServerError' tags: - questions - /questions/{question_id}: + /questions/{questionID}: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' get: - summary: Get a question by its question_id + summary: Get a question by its questionID responses: '200': description: OK @@ -364,7 +383,7 @@ paths: tags: - questions patch: - summary: Modify a question by its question_id + summary: Modify a question by its questionID security: - BearerAuth: [] requestBody: @@ -386,9 +405,9 @@ paths: $ref: '#/components/responses/BadRequest' tags: - questions - /questions/{question_id}/close: + /questions/{questionID}/close: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' patch: summary: Toggle vote to close a question security: @@ -404,9 +423,9 @@ paths: $ref: '#/components/responses/BadRequest' tags: - questions - /questions/{question_id}/protect: + /questions/{questionID}/protect: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' patch: summary: Toggle vote to protect a question security: @@ -422,9 +441,9 @@ paths: $ref: '#/components/responses/BadRequest' tags: - questions - /questions/{question_id}/reopen: + /questions/{questionID}/reopen: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' patch: summary: Toggle vote to reopen a question security: @@ -440,9 +459,9 @@ paths: $ref: '#/components/responses/BadRequest' tags: - questions - /questions/{question_id}/vote: + /questions/{questionID}/vote: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' get: summary: Get a user's vote on a question security: @@ -491,9 +510,9 @@ paths: $ref: '#/components/responses/BadRequest' tags: - questions - /questions/{question_id}/comments: + /questions/{questionID}/comments: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' get: summary: Get all comments of a question responses: @@ -536,10 +555,10 @@ paths: $ref: '#/components/responses/BadRequest' tags: - comments - /questions/{question_id}/comments/{comment_id}: + /questions/{questionID}/comments/{commentID}: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/comment_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/commentID' delete: summary: Delete a question comment security: @@ -555,10 +574,10 @@ paths: $ref: '#/components/responses/ServerError' tags: - comments - /questions/{question_id}/comments/{comment_id}/vote: + /questions/{questionID}/comments/{commentID}/vote: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/comment_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/commentID' get: summary: Get a user's vote on a question comment security: @@ -609,9 +628,9 @@ paths: tags: - comments - votes - /questions/{question_id}/answers: + /questions/{questionID}/answers: parameters: - - $ref: '#/components/parameters/question_id' + - $ref: '#/components/parameters/questionID' get: summary: Get all answers of a question responses: @@ -654,12 +673,12 @@ paths: $ref: '#/components/responses/BadRequest' tags: - answers - /questions/{question_id}/answers/{answer_id}: + /questions/{questionID}/answers/{answerID}: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/answer_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' patch: - summary: Modify an answer by its answer_id + summary: Modify an answer by its answerID security: - BearerAuth: [] requestBody: @@ -688,10 +707,10 @@ paths: $ref: '#/components/responses/BadRequest' tags: - answers - /questions/{question_id}/answers/{answer_id}/accept: + /questions/{questionID}/answers/{answerID}/accept: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/answer_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' patch: summary: Accept an answer as correct security: @@ -707,10 +726,10 @@ paths: $ref: '#/components/responses/BadRequest' tags: - answers - /questions/{question_id}/answers/{answer_id}/vote: + /questions/{questionID}/answers/{answerID}/vote: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/answer_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' get: summary: Get a user's vote on an answer security: @@ -761,10 +780,10 @@ paths: tags: - answers - votes - /questions/{question_id}/answers/{answer_id}/comments: + /questions/{questionID}/answers/{answerID}/comments: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/answer_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' get: summary: Get all comments of a answer responses: @@ -807,11 +826,11 @@ paths: $ref: '#/components/responses/BadRequest' tags: - comments - /questions/{question_id}/answers/{answer_id}/comments/{comment_id}: + /questions/{questionID}/answers/{answerID}/comments/{commentID}: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/answer_id' - - $ref: '#/components/parameters/comment_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + - $ref: '#/components/parameters/commentID' delete: summary: Delete an answer comment security: @@ -827,11 +846,11 @@ paths: $ref: '#/components/responses/ServerError' tags: - comments - /questions/{question_id}/answers/{answer_id}/comments/{comment_id}/vote: + /questions/{questionID}/answers/{answerID}/comments/{commentID}/vote: parameters: - - $ref: '#/components/parameters/question_id' - - $ref: '#/components/parameters/answer_id' - - $ref: '#/components/parameters/comment_id' + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + - $ref: '#/components/parameters/commentID' get: summary: Get a user's vote on an answer comment security: @@ -903,7 +922,7 @@ components: id: type: string example: '62d8727d6c584b3b12eb23be' - question_id: + questionID: type: string example: '62d5c7ad1b8e0da8804bde22' creator: @@ -926,7 +945,7 @@ components: id: type: string example: '62d87292afa7f2e7e81f1470' - parent_id: + parentID: type: string example: '62d5c7ad1b8e0da8804bde22' creator: @@ -1021,6 +1040,8 @@ components: format: email points: type: integer + level: + type: integer Vote: type: string nullable: true @@ -1077,8 +1098,8 @@ components: type: string example: 'That resource was not found. Please check your request and try again.' parameters: - question_id: - name: question_id + questionID: + name: questionID in: path required: true schema: @@ -1086,8 +1107,8 @@ components: example: '62d61d428849dda1c15a8b64' description: >- This should be the object id of the desired question. - answer_id: - name: answer_id + answerID: + name: answerID in: path required: true schema: @@ -1095,8 +1116,8 @@ components: example: '62d61ffd5f20e06f3cb350c7' description: >- This should be the object id of the desired answer. - comment_id: - name: comment_id + commentID: + name: commentID in: path required: true schema: From f964e52e82e0192c95165ffc2bc8faf92aeb0165 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 22:38:32 -0500 Subject: [PATCH 04/10] Removed log from cronjobs --- server/utils/cronRefresh.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/utils/cronRefresh.js b/server/utils/cronRefresh.js index f516550..07dadc5 100644 --- a/server/utils/cronRefresh.js +++ b/server/utils/cronRefresh.js @@ -1,7 +1,6 @@ const { getAllQuestions, getAllUsers } = require('./getData'); async function refreshQuestions(_job, done) { - console.log('Im running'); await getAllQuestions(); done(); } From b3b32acc64ccdd9c4ea51f57dceb368087f0ca60 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 22:38:40 -0500 Subject: [PATCH 05/10] Added dev script to base monorepo --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2df6dcd..0f6ef76 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "start:server": "npm start -w server", "start:client": "npm start -w client", "start:prod": "npm run start:server", - "prestart:prod": "npm run build -w client", + "prestart:prod": "npm run build", + "dev": "npm run dev -w server", "build": "npm run build -w client" }, "repository": { @@ -25,4 +26,4 @@ "client", "server" ] -} \ No newline at end of file +} From b1372c0ede61928b477655bdf3f81c37b4bd4c4b Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 22:56:13 -0500 Subject: [PATCH 06/10] Updated routes to bypass duplicate ID errors --- package.json | 4 ++-- server/package.json | 4 ++-- server/routes/user/GetUser.js | 24 ++++++++++++++---------- server/utils/question/getAnswer.js | 12 +++++++++--- server/utils/question/getComment.js | 0 server/utils/question/getQuestion.js | 11 ++++++++--- server/utils/question/index.js | 6 ++---- 7 files changed, 37 insertions(+), 24 deletions(-) delete mode 100644 server/utils/question/getComment.js diff --git a/package.json b/package.json index 0f6ef76..7641601 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "start": "npm start -w", "start:server": "npm start -w server", "start:client": "npm start -w client", - "start:prod": "npm run start:server", + "start:prod": "npm run prod -w server", "prestart:prod": "npm run build", - "dev": "npm run dev -w server", + "dev": "npm start -workspaces", "build": "npm run build -w client" }, "repository": { diff --git a/server/package.json b/server/package.json index 081e183..7cf1461 100644 --- a/server/package.json +++ b/server/package.json @@ -19,8 +19,8 @@ "superagent-throttle": "^1.0.1" }, "scripts": { - "start": "pm2 start ./bin/www", - "dev": "nodemon ./bin/www" + "start": "nodemon ./bin/www", + "prod": "pm2 start ./bin/www" }, "devDependencies": { "jest": "^28.1.3", diff --git a/server/routes/user/GetUser.js b/server/routes/user/GetUser.js index 116bfc9..fbc237d 100644 --- a/server/routes/user/GetUser.js +++ b/server/routes/user/GetUser.js @@ -8,27 +8,31 @@ async function GetUser(req, res) { const cachedUser = await User.findOne({ username }); - if (cachedUser) return res.send({ - user: { - username: cachedUser.username, - email: cachedUser.email, - points: cachedUser.points, - level: getUserLevel(cachedUser.points), - } - }); + if (cachedUser) + return res.send({ + user: { + username: cachedUser.username, + email: cachedUser.email, + points: cachedUser.points, + level: getUserLevel(cachedUser.points), + }, + }); const { success, user } = await createRequest('get', `/users/${username}`); if (!success) return res.status(500).send(config.errorGeneric); - const newUser = await User.create({ ...user, id: user.user_id }); + const newUser = await User.findByIdAndUpdate(user.user_id, user, { + upsert: true, + }); + return res.send({ user: { username: newUser.username, email: newUser.email, points: newUser.points, level: getUserLevel(newUser.points), - } + }, }); } diff --git a/server/utils/question/getAnswer.js b/server/utils/question/getAnswer.js index fec6a77..aab08f3 100644 --- a/server/utils/question/getAnswer.js +++ b/server/utils/question/getAnswer.js @@ -4,8 +4,12 @@ const Answer = require('server/db/models/Answer'); async function getAnswer(question_id, answer_id) { let cachedAnswer; - try { cachedAnswer = await Answer.findById(answer_id); } - catch { return; } + + try { + cachedAnswer = await Answer.findById(answer_id); + } catch { + return; + } // Retrieve uncached answer and patch to cache if (!cachedAnswer) { @@ -14,7 +18,9 @@ async function getAnswer(question_id, answer_id) { `/questions/${question_id}/answers/${answer_id}` ); if (!success) return; - return Answer.create({ ...answer, id: answer.answer_id, question_id }); + return Answer.findByIdAndUpdate(answer.answer_id, answer, { + upsert: true, + }); } else return cachedAnswer; } diff --git a/server/utils/question/getComment.js b/server/utils/question/getComment.js deleted file mode 100644 index e69de29..0000000 diff --git a/server/utils/question/getQuestion.js b/server/utils/question/getQuestion.js index 9135207..37fd067 100644 --- a/server/utils/question/getQuestion.js +++ b/server/utils/question/getQuestion.js @@ -4,8 +4,11 @@ const Question = require('server/db/models/Question'); async function getQuestion(question_id) { let cachedQuestion; - try { cachedQuestion = await Question.findById(question_id); } - catch { return; } + try { + cachedQuestion = await Question.findById(question_id); + } catch { + return; + } // Retrieve uncached question and patch to cache if (!cachedQuestion) { @@ -14,7 +17,9 @@ async function getQuestion(question_id) { `/questions/${question_id}` ); if (!success) return; - return Question.create({ ...question, id: question.question_id }); + return Question.findByIdAndUpdate(question.question_id, question, { + upsert: true, + }); } else return cachedQuestion; } diff --git a/server/utils/question/index.js b/server/utils/question/index.js index de55630..0009ec1 100644 --- a/server/utils/question/index.js +++ b/server/utils/question/index.js @@ -1,11 +1,9 @@ const getAnswer = require('./getAnswer'); -const getComment = require('./getComment'); const getQuestion = require('./getQuestion'); const refreshQuestion = require('./refreshQuestion'); module.exports = { getAnswer, - getComment, getQuestion, - refreshQuestion -}; \ No newline at end of file + refreshQuestion, +}; From d71fb9f1d72a1b8f8e068b3aa74e58e929619b6d Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 23:41:51 -0500 Subject: [PATCH 07/10] Changed default value for points --- server/db/models/User.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/db/models/User.js b/server/db/models/User.js index b7b11c1..5a4124c 100644 --- a/server/db/models/User.js +++ b/server/db/models/User.js @@ -4,7 +4,7 @@ const User = mongoose.Schema( { username: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true }, - points: { type: Number, required: true, default: 1 }, + points: { type: Number, required: true, default: 0 }, salt: { type: String, required: true }, lastMailFetch: { type: Date, default: new Date(0) }, lastAnswerFetch: { type: Date, default: new Date(0) }, From 08a7e294fd9710f0a128fd68454a82e0f3827865 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 1 Aug 2022 23:42:43 -0500 Subject: [PATCH 08/10] Queries return new documents --- server/utils/question/getAnswer.js | 1 + server/utils/question/getQuestion.js | 1 + 2 files changed, 2 insertions(+) diff --git a/server/utils/question/getAnswer.js b/server/utils/question/getAnswer.js index aab08f3..5b6b032 100644 --- a/server/utils/question/getAnswer.js +++ b/server/utils/question/getAnswer.js @@ -20,6 +20,7 @@ async function getAnswer(question_id, answer_id) { if (!success) return; return Answer.findByIdAndUpdate(answer.answer_id, answer, { upsert: true, + new: true, }); } else return cachedAnswer; } diff --git a/server/utils/question/getQuestion.js b/server/utils/question/getQuestion.js index 37fd067..9b5c204 100644 --- a/server/utils/question/getQuestion.js +++ b/server/utils/question/getQuestion.js @@ -19,6 +19,7 @@ async function getQuestion(question_id) { if (!success) return; return Question.findByIdAndUpdate(question.question_id, question, { upsert: true, + new: true, }); } else return cachedQuestion; } From b508f54f9d4bbc3a1e6061ba338a105d905314b7 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Tue, 2 Aug 2022 00:37:51 -0500 Subject: [PATCH 09/10] Fixed id errors and sendmail --- client/src/containers/Mail.jsx | 3 +- .../FormControllers/SendMailController.js | 23 +++++----- .../src/controllers/FormControllers/index.js | 6 ++- client/src/services/fields.js | 44 +++++++++---------- client/src/services/mailServices.js | 13 +----- server/app.js | 1 - server/bin/www | 1 + server/middleware/tokenAuth.js | 6 +-- server/routes/user/GetUser.js | 1 + server/utils/getData.js | 1 + server/utils/question/getAnswer.js | 12 +++-- server/utils/question/getQuestion.js | 14 ++++-- server/utils/question/refreshQuestion.js | 10 ++++- 13 files changed, 73 insertions(+), 62 deletions(-) diff --git a/client/src/containers/Mail.jsx b/client/src/containers/Mail.jsx index a98a5a2..7f43bed 100644 --- a/client/src/containers/Mail.jsx +++ b/client/src/containers/Mail.jsx @@ -1,6 +1,7 @@ import { Card, CardContent } from '@mui/material'; import React, { useEffect } from 'react'; -import { Inbox, SendMail } from 'controllers'; +import { SendMail } from 'controllers/FormControllers'; +import { Inbox } from 'controllers'; import { MdPreview } from 'components'; import { useNavigate } from 'react-router-dom'; import { useUser } from 'contexts'; diff --git a/client/src/controllers/FormControllers/SendMailController.js b/client/src/controllers/FormControllers/SendMailController.js index 577394c..a447adf 100644 --- a/client/src/controllers/FormControllers/SendMailController.js +++ b/client/src/controllers/FormControllers/SendMailController.js @@ -6,29 +6,30 @@ import { mailSchema } from 'services/schemas'; import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; export default function SendMailController() { - const { userData } = useUser(); const navigate = useNavigate(); useEffect(() => { - if(checkAuth()){ - navigate('/users/login', {state: {name : 'ask', msg : 'you need to be authenticated to access this feature' , prevPath: '/ask'}}) + if (checkAuth()) { + navigate('/users/login', { + state: { + name: 'ask', + msg: 'you need to be authenticated to access this feature', + prevPath: '/ask', + }, + }); } }, []); - function checkAuth(){ - - if(!userData.username){ + function checkAuth() { + if (!userData.username) { return true; } } - const sendMail = ({ receiver, subject, text }) => - postMail(userData.username, receiver, subject, text); - return Form({ fields: composeMailFields, - onSubmit: sendMail, - validationSchema: mailSchema + onSubmit: postMail, + validationSchema: mailSchema, }); } diff --git a/client/src/controllers/FormControllers/index.js b/client/src/controllers/FormControllers/index.js index 962379f..29a42e0 100644 --- a/client/src/controllers/FormControllers/index.js +++ b/client/src/controllers/FormControllers/index.js @@ -7,6 +7,8 @@ import ResetForm from './ResetFormController'; import SearchForm from './SearchFormController'; import UpdateForm from './UpdateFormController'; import AnswerForm from './AnwerFormController'; +import SendMail from './SendMailController'; + export { AskForm, ForgotPasswordForm, @@ -16,6 +18,6 @@ export { ResetForm, SearchForm, UpdateForm, - AnswerForm - + AnswerForm, + SendMail, }; diff --git a/client/src/services/fields.js b/client/src/services/fields.js index 3713792..5a8295e 100644 --- a/client/src/services/fields.js +++ b/client/src/services/fields.js @@ -8,28 +8,28 @@ const answerFields = [ { id: 'text', label: 'Answer', - multiline: true - } + multiline: true, + }, ]; const askQuestionFields = [ { id: 'title', - label: 'Title' + label: 'Title', }, { id: 'text', label: 'Text', - multiline: true - } + multiline: true, + }, ]; const commentFields = [ { id: 'text', label: 'Comment', - multiline: true - } + multiline: true, + }, ]; const composeMailFields = [ @@ -39,38 +39,38 @@ const composeMailFields = [ }, { id: 'subject', - label: 'Subject:', + label: 'Subject', }, { id: 'text', label: 'Body', multiline: true, - } + }, ]; const loginFields = [ { id: 'username', - title: 'Username' + title: 'Username', }, { id: 'password', title: 'Password', - type: 'password' - } + type: 'password', + }, ]; const recoverFields = [ { id: 'username', - title: 'Username' - } + title: 'Username', + }, ]; const registerFields = [ { id: 'username', - title: 'Username' + title: 'Username', }, { id: 'email', @@ -85,7 +85,7 @@ const registerFields = [ { id: 'captcha', title: 'CAPTCHA', - } + }, ]; const resetFields = [ @@ -94,7 +94,7 @@ const resetFields = [ helperText: (value) => `Password strength: ${passwordStrength(value)}`, title: 'Password', type: 'password', - } + }, ]; const patchFields = [ @@ -107,8 +107,8 @@ const patchFields = [ helperText: (value) => `Password strength: ${passwordStrength(value)}`, title: 'Password', type: 'password', - } -] + }, +]; const searchFields = [ { @@ -120,13 +120,13 @@ const searchFields = [ label: 'Text', }, { - id: 'createdAt', + id: 'createdAt', type: 'date', }, { id: 'creator', label: 'Creator', - } + }, ]; export { @@ -139,5 +139,5 @@ export { registerFields, recoverFields, resetFields, - searchFields + searchFields, }; diff --git a/client/src/services/mailServices.js b/client/src/services/mailServices.js index 0a49d18..2dabea8 100644 --- a/client/src/services/mailServices.js +++ b/client/src/services/mailServices.js @@ -2,17 +2,8 @@ import { createEndpoint } from './api'; const callMailAPI = createEndpoint('/mail'); -const postMail = async (data) => - callMailAPI( - 'post', - ``, - data - ); +const postMail = async (data) => callMailAPI('post', ``, data); -const getMail = async () => - callMailAPI( - 'get', - `` - ); +const getMail = async () => callMailAPI('get', ``); export { getMail, postMail }; diff --git a/server/app.js b/server/app.js index c1370ad..c76a398 100644 --- a/server/app.js +++ b/server/app.js @@ -19,7 +19,6 @@ app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); -app.use(express.static(path.join(__dirname, 'public'))); app.use('/users', userRouter); app.use('/mail', mailRouter); diff --git a/server/bin/www b/server/bin/www index ab7082b..2b00ff8 100644 --- a/server/bin/www +++ b/server/bin/www @@ -34,6 +34,7 @@ const server = http.createServer(app); mongoose.connect(process.env.DB_CONN_STRING, { useNewUrlParser: true, useUnifiedTopology: true, + dbName: process.env.DB_NAME, }); mongoose.connection.once('open', () => diff --git a/server/middleware/tokenAuth.js b/server/middleware/tokenAuth.js index 85a63ea..b59cb8b 100644 --- a/server/middleware/tokenAuth.js +++ b/server/middleware/tokenAuth.js @@ -1,6 +1,5 @@ const Token = require('server/db/models/Token'); const User = require('server/db/models/User'); -const jwt = require('jsonwebtoken'); const config = require('server/config.json'); async function tokenAuth(req, res, next) { @@ -9,10 +8,9 @@ async function tokenAuth(req, res, next) { const token = authHeader?.split(' ')[1]; // Verify token is included in request - if (!token) - return res.status(401).send(config.errorUnauthed); + if (!token) return res.status(401).send(config.errorUnauthed); - const result = await Token.findOne({ token: token }); + const result = await Token.findOne({ token }); // Verify token expiration const date = new Date(); diff --git a/server/routes/user/GetUser.js b/server/routes/user/GetUser.js index fbc237d..25ddd93 100644 --- a/server/routes/user/GetUser.js +++ b/server/routes/user/GetUser.js @@ -24,6 +24,7 @@ async function GetUser(req, res) { const newUser = await User.findByIdAndUpdate(user.user_id, user, { upsert: true, + new: true, }); return res.send({ diff --git a/server/utils/getData.js b/server/utils/getData.js index 0c17a0a..2bea11e 100644 --- a/server/utils/getData.js +++ b/server/utils/getData.js @@ -12,6 +12,7 @@ async function getAllData(Model, url, id, dataName) { ...item, id: item[id], })); + for (const item of data) await Model.findByIdAndUpdate(item[id], item, { upsert: true }); return data; diff --git a/server/utils/question/getAnswer.js b/server/utils/question/getAnswer.js index 5b6b032..e7a86cc 100644 --- a/server/utils/question/getAnswer.js +++ b/server/utils/question/getAnswer.js @@ -18,10 +18,14 @@ async function getAnswer(question_id, answer_id) { `/questions/${question_id}/answers/${answer_id}` ); if (!success) return; - return Answer.findByIdAndUpdate(answer.answer_id, answer, { - upsert: true, - new: true, - }); + return Answer.findByIdAndUpdate( + answer.answer_id, + { ...answer, id: answer.answer_id }, + { + upsert: true, + new: true, + } + ); } else return cachedAnswer; } diff --git a/server/utils/question/getQuestion.js b/server/utils/question/getQuestion.js index 9b5c204..3622545 100644 --- a/server/utils/question/getQuestion.js +++ b/server/utils/question/getQuestion.js @@ -16,11 +16,17 @@ async function getQuestion(question_id) { 'get', `/questions/${question_id}` ); + if (!success) return; - return Question.findByIdAndUpdate(question.question_id, question, { - upsert: true, - new: true, - }); + + return Question.findByIdAndUpdate( + question.question_id, + { ...question, id: question.question_id }, + { + upsert: true, + new: true, + } + ); } else return cachedQuestion; } diff --git a/server/utils/question/refreshQuestion.js b/server/utils/question/refreshQuestion.js index 69c0c02..fbf3db9 100644 --- a/server/utils/question/refreshQuestion.js +++ b/server/utils/question/refreshQuestion.js @@ -2,7 +2,10 @@ const Question = require('server/db/models/Question'); const createRequest = require('server/utils/api'); async function refreshQuestion(question_id) { - const { question, success } = await createRequest('get', `/questions/${question_id}`); + const { question, success } = await createRequest( + 'get', + `/questions/${question_id}` + ); if (!success) return false; // Refresh cache @@ -10,7 +13,10 @@ async function refreshQuestion(question_id) { ...question, id: question.question_id, }; - return Question.findByIdAndUpdate(question.id, newQuestion, { upsert: true }); + + return Question.findByIdAndUpdate(question.id, newQuestion, { + upsert: true, + }); } module.exports = refreshQuestion; From 2af3b6f21df39954847b5dda7693b105b623284c Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Tue, 2 Aug 2022 00:52:34 -0500 Subject: [PATCH 10/10] Fixed vote operation --- server/routes/question/CreateAnswer.js | 10 +++------- server/routes/question/CreateQuestion.js | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/server/routes/question/CreateAnswer.js b/server/routes/question/CreateAnswer.js index 81860b1..4a17992 100644 --- a/server/routes/question/CreateAnswer.js +++ b/server/routes/question/CreateAnswer.js @@ -22,16 +22,12 @@ async function CreateAnswer(req, res) { if (question.status === 'closed') return res.status(403).send(config.errorForbidden); - if ( - question.status === 'protected' && - getUserLevel(user.points) < 5 - ) { + if (question.status === 'protected' && getUserLevel(user.points) < 5) { return res.status(403).send(config.errorForbidden); } // Verify request includes required information - if (!text) - return res.status(400).send(config.errorIncomplete); + if (!text) return res.status(400).send(config.errorIncomplete); // Create question with BDPA server const { success, answer } = await createRequest( @@ -53,7 +49,7 @@ async function CreateAnswer(req, res) { amount: 2, }); - await User.findByIdAndUpdate(user.id, { points: { $inc: 2 } }); + await User.findByIdAndUpdate(user.id, { $inc: { points: 2 } }); return res.sendStatus(200); } diff --git a/server/routes/question/CreateQuestion.js b/server/routes/question/CreateQuestion.js index 3fd362f..20ee3b5 100644 --- a/server/routes/question/CreateQuestion.js +++ b/server/routes/question/CreateQuestion.js @@ -27,7 +27,7 @@ async function CreateQuestion(req, res) { amount: 1, }); - await User.findByIdAndUpdate(user.id, { points: { $inc: 1 } }); + await User.findByIdAndUpdate(user.id, { $inc: { points: 1 } }); return res.sendStatus(200); }