From 0e071fc33946b1f7a9dd6b3f1a8d69f25f3ffaeb Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Mon, 18 Jul 2022 23:13:58 -0500 Subject: [PATCH] Added openapi documentation --- server/config.json | 2 +- server/middleware/tokenAuth.js | 2 +- server/openapi.yml | 1024 +++++++++++++++++ server/routes/mail.js | 2 +- server/routes/mail/Send.js | 5 +- server/routes/question/CreateAnswer.js | 18 +- server/routes/question/EditAnswer.js | 4 +- .../routes/question/EditAnswerCommentVote.js | 4 +- server/routes/question/EditAnswerVote.js | 6 +- server/routes/question/EditCommentVote.js | 4 +- server/routes/question/EditQuestion.js | 4 +- server/routes/question/EditQuestionVote.js | 4 +- server/routes/user.js | 6 +- server/routes/user/Answers.js | 2 +- server/routes/user/Logout.js | 2 +- server/routes/user/Questions.js | 2 +- 16 files changed, 1065 insertions(+), 26 deletions(-) create mode 100644 server/openapi.yml diff --git a/server/config.json b/server/config.json index 955881f..e3c2b6c 100644 --- a/server/config.json +++ b/server/config.json @@ -28,7 +28,7 @@ "error": "Request failed. Please check form and try again." }, "errorNotFound": { - "error": "That object was not found. Please check the URI and try again." + "error": "That resource was not found. Please check the URI and try again." }, "errorUnauthed": { "error": "You are unauthenticated, please include your JWT." diff --git a/server/middleware/tokenAuth.js b/server/middleware/tokenAuth.js index c219c8b..7af7d42 100644 --- a/server/middleware/tokenAuth.js +++ b/server/middleware/tokenAuth.js @@ -21,7 +21,7 @@ async function tokenAuth(req, res, next) { date.setDate(date.getDate + 1) > result.createdAt ) { await Token.findOneAndDelete({ token }); - return res.status(401).send(config.errorFailed); + return res.status(401).send(config.errorUnauthed); } const decoded = jwt.verify(result.token, result.id); diff --git a/server/openapi.yml b/server/openapi.yml new file mode 100644 index 0000000..8f4a74a --- /dev/null +++ b/server/openapi.yml @@ -0,0 +1,1024 @@ +openapi: 3.0.0 +servers: + - description: SwaggerHub API Auto Mocking + url: https://virtserver.swaggerhub.com/C4theBomb/qOverflow/1.0.0 + - description: Localhost server + url: https://localhost:3001 +info: + version: '1.0.0' + title: qOverflow API + description: >- + This API will interact with the BDPA API to expand operations and cache data to bypass rate limitations. It also implements enforcement features to prevent unauthorized operations. Authorization is done through the `authorization` header and has two scopes, `bearer` and `basic`. + +paths: + /users/: + patch: + summary: Modify user information + requestBody: + content: + '*/*': + schema: + type: object + properties: + username: + type: string + email: + type: string + format: email + security: + - BearerAuth: [] + responses: + '200': + description: OK + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /users/{username}: + parameters: + - name: username + in: path + required: true + schema: + type: string + example: 'pinapplezzz' + description: >- + This should be the username of the desired user. + get: + summary: Get a user by their username + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + user: + $ref: '#/components/schemas/User' + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /users/questions: + get: + summary: Get all questions written by logged in user + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + questions: + type: array + items: + $ref: '#/components/schemas/Question' + tags: + - users + /users/answers: + get: + summary: Get all answers written by logged in user + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + answers: + type: array + items: + $ref: '#/components/schemas/Answer' + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /users/register: + post: + summary: Register a new user + requestBody: + required: true + content: + '*/*': + schema: + type: object + properties: + username: + type: string + email: + type: string + format: email + password: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /users/login: + post: + summary: Login a user and reciever an authentication token + security: + - BasicAuth: [] + requestBody: + required: true + content: + '*/*': + schema: + type: object + properties: + username: + type: string + email: + type: string + format: email + password: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + user: + $ref: '#/components/schemas/User' + token: + type: string + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /users/logout: + delete: + summary: Login a user and reciever an authentication token + security: + - BearerAuth: [] + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /users/reset: + post: + summary: Get a link for the user to reset their password + requestBody: + required: true + content: + '*/*': + schema: + type: object + properties: + username: + type: string + example: 'pinapplezzz' + description: >- + Username of the user that need to reset their password. + responses: + '200': + description: OK + tags: + - users + /users/reset/{id}: + parameters: + - name: id + in: path + required: true + schema: + type: string + example: '62d61301c3fd83c49d35173d' + description: >- + This should be the ID of the request that was created in the request page. + post: + summary: Reset the user's password + requestBody: + required: true + content: + '*/*': + schema: + type: object + properties: + password: + type: string + responses: + '200': + description: OK + '500': + $ref: '#/components/responses/ServerError' + tags: + - users + /mail/: + get: + summary: Get all of the logged in user's incoming mail + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + messages: + type: array + items: + $ref: '#/components/schemas/Mail' + '500': + $ref: '#/components/responses/ServerError' + tags: + - mail + post: + summary: Send out outgoing mail for the logged in user + security: + - BearerAuth: [] + requestBody: + required: true + content: + '*/*': + schema: + type: object + properties: + reciever: + type: string + example: 'pinapplezzz' + subject: + type: string + text: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/ServerError' + tags: + - mail + /questions: + post: + summary: Create a new question + security: + - BearerAuth: [] + requestBody: + required: true + content: + '*/*': + schema: + type: object + properties: + title: + type: string + text: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '500': + $ref: '#/components/responses/ServerError' + tags: + - questions + /questions/{questionID}: + parameters: + - $ref: '#/components/parameters/questionID' + get: + summary: Get a question by its questionID + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + question: + $ref: '#/components/schemas/Question' + '500': + $ref: '#/components/responses/ServerError' + tags: + - questions + patch: + summary: Modify a question by its questionID + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + text: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - questions + /questions/{questionID}/close: + parameters: + - $ref: '#/components/parameters/questionID' + patch: + summary: Toggle vote to close a question + security: + - BearerAuth: [] + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - questions + /questions/{questionID}/protect: + parameters: + - $ref: '#/components/parameters/questionID' + patch: + summary: Toggle vote to protect a question + security: + - BearerAuth: [] + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - questions + /questions/{questionID}/reopen: + parameters: + - $ref: '#/components/parameters/questionID' + patch: + summary: Toggle vote to reopen a question + security: + - BearerAuth: [] + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - questions + /questions/{questionID}/vote: + parameters: + - $ref: '#/components/parameters/questionID' + get: + summary: Get a user's vote on a question + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + tags: + - questions + patch: + summary: Modify a user's vote on a question + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + operation: + type: string + enum: ['upvote', 'downvote'] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - questions + /questions/{questionID}/comments: + parameters: + - $ref: '#/components/parameters/questionID' + get: + summary: Get all comments of a question + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + comments: + type: array + items: + $ref: '#/components/schemas/Comment' + '500': + $ref: '#/components/responses/ServerError' + tags: + - comments + post: + summary: Create a comment on a question + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + text: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - comments + /questions/{questionID}/comments/{commentID}: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/commentID' + delete: + summary: Delete a question comment + security: + - BearerAuth: [] + responses: + '200': + description: OK + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/ServerError' + tags: + - comments + /questions/{questionID}/comments/{commentID}/vote: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/commentID' + get: + summary: Get a user's vote on a question comment + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + tags: + - comments + - votes + patch: + summary: Modify a user's vote on a question comment + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + operation: + type: string + enum: ['upvote', 'downvote'] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - comments + - votes + /questions/{questionID}/answers: + parameters: + - $ref: '#/components/parameters/questionID' + get: + summary: Get all answers of a question + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + answers: + type: array + items: + $ref: '#/components/schemas/Answer' + '500': + $ref: '#/components/responses/ServerError' + tags: + - answers + post: + summary: Answer a question + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + text: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - answers + /questions/{questionID}/answers/{answerID}: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + patch: + summary: Modify an answer by its answerID + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + text: + type: string + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + answer: + $ref: '#/components/schemas/Answer' + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - answers + /questions/{questionID}/answers/{answerID}/vote: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + get: + summary: Get a user's vote on an answer + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + tags: + - answers + - votes + patch: + summary: Modify a user's vote on an answer + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + operation: + type: string + enum: ['upvote', 'downvote'] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - answers + - votes + /questions/{questionID}/answers/{answerID}/comments: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + get: + summary: Get all comments of a answer + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + comments: + type: array + items: + $ref: '#/components/schemas/Comment' + '500': + $ref: '#/components/responses/ServerError' + tags: + - comments + post: + summary: Create a comment on an answer + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + text: + type: string + responses: + '200': + description: OK + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - comments + /questions/{questionID}/answers/{answerID}/comments/{commentID}: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + - $ref: '#/components/parameters/commentID' + delete: + summary: Delete an answer comment + security: + - BearerAuth: [] + responses: + '200': + description: OK + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/ServerError' + tags: + - comments + /questions/{questionID}/answers/{answerID}/comments/{commentID}/vote: + parameters: + - $ref: '#/components/parameters/questionID' + - $ref: '#/components/parameters/answerID' + - $ref: '#/components/parameters/commentID' + get: + summary: Get a user's vote on an answer comment + security: + - BearerAuth: [] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + tags: + - comments + - votes + patch: + summary: Modify a user's vote on an answer comment + security: + - BearerAuth: [] + requestBody: + content: + '*/*': + schema: + type: object + properties: + operation: + type: string + enum: ['upvote', 'downvote'] + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + properties: + vote: + $ref: '#/components/schemas/Vote' + + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/BadRequest' + tags: + - comments + - votes + +components: + securitySchemes: + BasicAuth: + type: http + scheme: basic + description: >- + This is the username and password authentication method used for the login route. The authorization header should be equal to `basic {base64 encoded username:password}` encoded into base64. The base64 encoding can be found by running `btoa(username:password)`. + BearerAuth: + type: http + scheme: bearer + bearerFormat: jwt + description: >- + This is the JWT token authentication method used for other routes requiring user privileges. The authorization header should be equal to `bearer {JTW Token}`. The token is returned in the token property of the `/users/login` response. + schemas: + Answer: + type: object + properties: + questionID: + type: string + example: '62d5c7ad1b8e0da8804bde22' + creator: + type: string + example: 'pinapplezzz' + text: + type: string + upvotes: + type: integer + downvotes: + type: integer + accepted: + type: boolean + createdAt: + type: string + format: date-time + Comment: + type: object + properties: + parentID: + type: string + example: '62d5c7ad1b8e0da8804bde22' + creator: + type: string + example: 'pinapplezzz' + text: + type: string + upvotes: + type: integer + downvotes: + type: integer + createdAt: + type: string + format: date-time + Mail: + type: object + properties: + sender: + type: string + example: 'pinapplezzz' + reciever: + type: string + example: 'pinapplezzz' + subject: + type: string + text: + type: string + createdAt: + type: string + format: date-time + Question: + type: object + properties: + title: + type: string + text: + type: string + status: + type: string + enum: ['open', 'protected', 'closed'] + views: + type: integer + answers: + type: integer + comments: + type: integer + upvotes: + type: integer + downvotes: + type: integer + hasAccepted: + type: boolean + creator: + type: string + example: 'pinapplezzz' + reopen: + type: array + items: + type: string + example: 'pinapplezzz' + close: + type: array + items: + type: string + example: 'pinapplezzz' + protect: + type: array + items: + type: string + example: 'pinapplezzz' + createdAt: + type: string + format: date-time + User: + type: object + properties: + username: + type: string + example: 'pinapplezzz' + email: + type: string + format: email + points: + type: integer + Vote: + type: string + nullable: true + enum: ['upvoted', 'downvoted', 'null'] + responses: + BadRequest: + description: Bad request + content: + '*/*': + schema: + type: object + properties: + error: + type: string + example: 'Your request is missing information.' + ServerError: + description: Server Error + content: + '*/*': + schema: + type: object + properties: + error: + type: string + example: 'Oops! Something went wrong.' + Unauthorized: + description: User unauthorized + content: + '*/*': + schema: + type: object + properties: + error: + type: string + example: 'You are unauthenticated. Please inclue your JWT.' + Forbidden: + description: User not allowed + content: + '*/*': + schema: + type: object + properties: + error: + type: string + example: 'You are not authorized to do that.' + NotFound: + description: Not Found + content: + '*/*': + schema: + type: object + properties: + error: + type: string + example: 'That resource was not found. Please check your request and try again.' + parameters: + questionID: + name: questionID + in: path + required: true + schema: + type: string + example: '62d61d428849dda1c15a8b64' + description: >- + This should be the object id of the desired question. + answerID: + name: answerID + in: path + required: true + schema: + type: string + example: '62d61ffd5f20e06f3cb350c7' + description: >- + This should be the object id of the desired answer. + commentID: + name: commentID + in: path + required: true + schema: + type: string + example: '62d620175bdb35fbb86e33cb' + description: >- + This should be the object id of the desired comment. diff --git a/server/routes/mail.js b/server/routes/mail.js index 850e6d0..4a3f09d 100644 --- a/server/routes/mail.js +++ b/server/routes/mail.js @@ -6,7 +6,7 @@ const tokenAuth = require('../middleware/tokenAuth'); const GetMail = require('./mail/Get'); const SendMail = require('./mail/Send'); -router.post('/', tokenAuth, SendMail); router.get('/', tokenAuth, GetMail); +router.post('/', tokenAuth, SendMail); module.exports = router; diff --git a/server/routes/mail/Send.js b/server/routes/mail/Send.js index 52dfe9b..b6ae1e9 100644 --- a/server/routes/mail/Send.js +++ b/server/routes/mail/Send.js @@ -7,10 +7,7 @@ async function Send(req, res, next) { const { reciever, subject, text } = req.body; if (!reciever | !subject | !text) { - return res.status(400).send({ - success: false, - error: 'Your message is missing information.', - }); + return res.status(400).send(config.errorIncomplete); } const { success, message } = await createRequest('post', `/mail`, { diff --git a/server/routes/question/CreateAnswer.js b/server/routes/question/CreateAnswer.js index 271bec5..c4eac43 100644 --- a/server/routes/question/CreateAnswer.js +++ b/server/routes/question/CreateAnswer.js @@ -1,17 +1,31 @@ const Answer = require('../../db/models/Answer'); +const Question = require('../../db/models/Question'); const config = require('../../config.json'); const getUserLevel = require('../../utils/getUserLevel'); async function CreateAnswer(req, res, next) { const user = req.user; - const { title, text } = req.body; + const { text } = req.body; const { questionID } = req.params; if (getUserLevel(user.points) < 1) { return res.status(403).send(config.errorForbidden); } - if (!title || !text) { + const cachedQuestion = await Question.findById(questionID); + + if (cachedQuestion.status === 'closed') { + return res.status(403).send(config.errorForbidden); + } + + if ( + cachedQuestion.status === 'protected' && + getUserLevel(user.points) < 5 + ) { + return res.status(403).send(config.errorForbidden); + } + + if (!text) { return res.status(400).send(config.errorIncomplete); } diff --git a/server/routes/question/EditAnswer.js b/server/routes/question/EditAnswer.js index b0eb3f2..c75a647 100644 --- a/server/routes/question/EditAnswer.js +++ b/server/routes/question/EditAnswer.js @@ -3,9 +3,11 @@ const config = require('../../config.json'); async function EditAnswer(req, res, next) { const user = req.user; - const body = req.body; + const { text } = req.body; const { questionID, answerID } = req.params; + if (!text) return res.status(400).send(config.errorIncomplete); + const answerPull = await createRequest( 'get', `/questions/${questionID}/answers/${answerID}` diff --git a/server/routes/question/EditAnswerCommentVote.js b/server/routes/question/EditAnswerCommentVote.js index 6a05793..74964dc 100644 --- a/server/routes/question/EditAnswerCommentVote.js +++ b/server/routes/question/EditAnswerCommentVote.js @@ -8,6 +8,8 @@ async function EditAnswerVote(req, res, next) { const { questionID, answerID, commentID } = req.params; const { operation } = req.body; + if (!operation) return res.status(400).send(config.errorIncomplete); + const userLevel = getUserLevel(user.points); if (operation === 'upvote' && userLevel < 2) { return res.status(403).send(config.errorForbidden); @@ -19,8 +21,6 @@ async function EditAnswerVote(req, res, next) { const URL = `/questions/${questionID}/answerID/${answerID}/comments/${commentID}/vote/${user.username}`; - if (!operation) return res.status(400).send(config.errorIncomplete); - var cachedVote = await Vote.findOneAndDelete({ parentID: commentID, creator: user.username, diff --git a/server/routes/question/EditAnswerVote.js b/server/routes/question/EditAnswerVote.js index 697f24d..9356292 100644 --- a/server/routes/question/EditAnswerVote.js +++ b/server/routes/question/EditAnswerVote.js @@ -3,13 +3,15 @@ const config = require('../../config.json'); const getUserLevel = require('../../utils/getUserLevel'); const Vote = require('../../db/models/Vote'); -const Answer = require('../../db/mdoels/Answer'); +const Answer = require('../../db/models/Answer'); async function EditAnswerVote(req, res, next) { const user = req.user; const { questionID, answerID } = req.params; const { operation } = req.body; + if (!operation) return res.status(400).send(config.errorIncomplete); + const userLevel = getUserLevel(user.points); if (operation === 'upvote' && userLevel < 2) { return res.status(403).send(config.errorForbidden); @@ -21,8 +23,6 @@ async function EditAnswerVote(req, res, next) { const URL = `/questions/${questionID}/answers/${answerID}/vote/${user.username}`; - if (!operation) return res.status(400).send(config.errorIncomplete); - const cachedAnswer = await Answer.findById(answerID); var cachedVote = await Vote.findOneAndDelete({ parentID: answerID, diff --git a/server/routes/question/EditCommentVote.js b/server/routes/question/EditCommentVote.js index 1733069..d02a859 100644 --- a/server/routes/question/EditCommentVote.js +++ b/server/routes/question/EditCommentVote.js @@ -8,6 +8,8 @@ async function EditAnswerVote(req, res, next) { const { questionID, commentID } = req.params; const { operation } = req.body; + if (!operation) return res.status(400).send(config.errorIncomplete); + const userLevel = getUserLevel(user.points); if (operation === 'upvote' && userLevel < 2) { return res.status(403).send(config.errorForbidden); @@ -19,8 +21,6 @@ async function EditAnswerVote(req, res, next) { const URL = `/questions/${questionID}/comments/${commentID}/vote/${user.username}`; - if (!operation) return res.status(400).send(config.errorIncomplete); - var cachedVote = await Vote.findOneAndDelete({ parentID: commentID, creator: user.username, diff --git a/server/routes/question/EditQuestion.js b/server/routes/question/EditQuestion.js index 33d9517..3eedad4 100644 --- a/server/routes/question/EditQuestion.js +++ b/server/routes/question/EditQuestion.js @@ -3,9 +3,11 @@ const config = require('../../config.json'); async function EditAnswer(req, res, next) { const user = req.user; - const { token, ...body } = req.body; + const { text } = req.body; const { questionID } = req.params; + if (!text) return res.status(400).send(config.errorIncomplete); + const questionPull = await createRequest('get', `/questions/${questionID}`); if (!questionPull.success) return res.status(500).send(config.errorGeneric); diff --git a/server/routes/question/EditQuestionVote.js b/server/routes/question/EditQuestionVote.js index 4feb208..608a666 100644 --- a/server/routes/question/EditQuestionVote.js +++ b/server/routes/question/EditQuestionVote.js @@ -9,6 +9,8 @@ async function EditQuestionVote(req, res, next) { const { questionID } = req.params; const { operation } = req.body; + if (!operation) return res.status(400).send(config.errorIncomplete); + const userLevel = getUserLevel(user.points); if (operation === 'upvote' && userLevel < 2) { return res.status(403).send(config.errorForbidden); @@ -20,8 +22,6 @@ async function EditQuestionVote(req, res, next) { const URL = `/questions/${questionID}/vote/${user.username}`; - if (!operation) return res.status(400).send(config.errorIncomplete); - const cachedQuestion = await Question.findByID(questionID); var cachedVote = await Vote.findOneAndDelete({ parentID: questionID, diff --git a/server/routes/user.js b/server/routes/user.js index cb42cdd..d0a35e7 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -17,10 +17,10 @@ const ResetPassword = require('./user/ResetPassword'); router.get('/:username', GetUser); router.get('/questions', tokenAuth, Questions); router.get('/answers', tokenAuth, Answers); -router.get('/logout', tokenAuth, Logout); -router.get('/reset', RequestReset); -router.post('/login', basicAuth, Login); router.post('/register', Register); +router.post('/login', basicAuth, Login); +router.delete('/logout', tokenAuth, Logout); +router.get('/reset', RequestReset); router.post('/reset/:id', ResetPassword); router.patch('/', tokenAuth, Edit); diff --git a/server/routes/user/Answers.js b/server/routes/user/Answers.js index 1e610f3..187e1b3 100644 --- a/server/routes/user/Answers.js +++ b/server/routes/user/Answers.js @@ -37,7 +37,7 @@ async function Answers(req, res, next) { creator: user.username, }).sort({ createdAt: 'desc' }); - return res.send(cachedAnswers); + return res.send({ answers: cachedAnswers }); } module.exports = Answers; diff --git a/server/routes/user/Logout.js b/server/routes/user/Logout.js index 3df7c83..2ca1edb 100644 --- a/server/routes/user/Logout.js +++ b/server/routes/user/Logout.js @@ -3,7 +3,7 @@ const Token = require('../../db/models/Token'); async function Logout(req, res, next) { const user = req.user; - await Token.findByIdAndDelete(user.token); + await Token.findOne({ user: user.id }); return res.sendStatus(200); } diff --git a/server/routes/user/Questions.js b/server/routes/user/Questions.js index dfaad88..56b15a1 100644 --- a/server/routes/user/Questions.js +++ b/server/routes/user/Questions.js @@ -8,7 +8,7 @@ async function Questions(req, res, next) { creator: user.username, }).sort({ createdAt: 'desc' }); - return res.send(cachedQuestions); + return res.send({ questions: cachedQuestions }); } module.exports = Questions;