diff --git a/backend/app/models/answers.js b/backend/app/models/answers.js index 90d85036..8f80fcfe 100644 --- a/backend/app/models/answers.js +++ b/backend/app/models/answers.js @@ -27,6 +27,10 @@ const answerSchema = new Schema( type: Number, default: 0, }, + downvotes:{ + type:Number, + default:0 + }, created_on: { type: Date, required: true, diff --git a/backend/app/models/question.js b/backend/app/models/question.js index 4fe46114..a3d51bbe 100644 --- a/backend/app/models/question.js +++ b/backend/app/models/question.js @@ -28,6 +28,11 @@ const questionSchema = new Schema( downvotes:{ type:Number, default:0 + }, + created_by:{ + type:String, + required:true, + trim:true } }, { timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' } } diff --git a/backend/app/routes/Q&A/answers/downvoteAnswer.js b/backend/app/routes/Q&A/answers/downvoteAnswer.js index b4608d80..afcf5462 100644 --- a/backend/app/routes/Q&A/answers/downvoteAnswer.js +++ b/backend/app/routes/Q&A/answers/downvoteAnswer.js @@ -2,29 +2,11 @@ const to = require('await-to-js').default; const answer = require('../../../models/answers'); const { ErrorHandler } = require('../../../../helpers/error'); const constants = require('../../../../constants'); +const { getVoteCookieName } = require('../../../../helpers/middlewares/cookie'); module.exports = async (req, res, next) => { const { answerId } = req.body; - const [err] = await to( - answer.updateOne({ _id: answerId }, [ - { - $set: { - upvotes: { - $cond: [ - { - $gt: ['$upvotes', 0], - }, - { - $subtract: ['$upvotes', 1], - }, - 0, - ], - }, - }, - }, - ]) - ); - + const [err] = await to(answer.updateOne({ _id: answerId }, { $inc: { downvotes: 1 } })); if (err) { const error = new ErrorHandler(constants.ERRORS.DATABASE, { statusCode: 500, @@ -35,6 +17,8 @@ module.exports = async (req, res, next) => { return next(error); } + res.cookie(getVoteCookieName('answer', answerId), true, { maxAge: 20 * 365 * 24 * 60 * 60 * 1000,sameSite:"none",secure:true }); + res.status(200).send({ message: 'Answer has been down voted', }); diff --git a/backend/app/routes/Q&A/answers/index.js b/backend/app/routes/Q&A/answers/index.js index 86ea6772..4b61f12b 100644 --- a/backend/app/routes/Q&A/answers/index.js +++ b/backend/app/routes/Q&A/answers/index.js @@ -9,6 +9,7 @@ const downvoteAnswer = require('./downvoteAnswer'); const updateAnswerStatus = require('./updateAnswerStatus'); const { authMiddleware } = require('../../../../helpers/middlewares/auth'); const deleteAnswer = require('./deleteAnswer'); +const { checkVoteCookie } = require('../../../../helpers/middlewares/cookie'); // POST API FOR ANSWER router.post('/', validation(answerValidationSchema), postAnswer); @@ -17,10 +18,10 @@ router.post('/', validation(answerValidationSchema), postAnswer); router.get('/:questionId', getAnswers); // INCREASE UPVOTE FOR ANSWERS -router.patch('/upvote', upvoteAnswer); +router.patch('/upvote', checkVoteCookie,upvoteAnswer); // DECREASE UPVOTE FOR ANSWERS -router.patch('/downvote', downvoteAnswer); +router.patch('/downvote', checkVoteCookie,downvoteAnswer); // Update Answer Status router.patch('/updateStatus', validation(updateAnswerStatusSchema), updateAnswerStatus); diff --git a/backend/app/routes/Q&A/answers/upvoteAnswer.js b/backend/app/routes/Q&A/answers/upvoteAnswer.js index 38ce0678..24c38d03 100644 --- a/backend/app/routes/Q&A/answers/upvoteAnswer.js +++ b/backend/app/routes/Q&A/answers/upvoteAnswer.js @@ -2,6 +2,7 @@ const to = require('await-to-js').default; const answer = require('../../../models/answers'); const { ErrorHandler } = require('../../../../helpers/error'); const constants = require('../../../../constants'); +const { getVoteCookieName } = require('../../../../helpers/middlewares/cookie'); module.exports = async (req, res, next) => { const { answerId } = req.body; @@ -16,6 +17,8 @@ module.exports = async (req, res, next) => { return next(error); } + res.cookie(getVoteCookieName('answer', answerId), true, { maxAge: 20 * 365 * 24 * 60 * 60 * 1000,sameSite:"none",secure:true }); + res.status(200).send({ message: 'Answer has been upvoted', }); diff --git a/backend/app/routes/Q&A/question/@validationSchema/index.js b/backend/app/routes/Q&A/question/@validationSchema/index.js index 10bfee90..a440ad31 100644 --- a/backend/app/routes/Q&A/question/@validationSchema/index.js +++ b/backend/app/routes/Q&A/question/@validationSchema/index.js @@ -4,6 +4,7 @@ const QuestionValidationSchema = Joi.object().keys({ title: Joi.string().trim().required().min(5), description: Joi.string().trim().required().min(10), tags: Joi.array().required(), + created_by:Joi.string().trim().required().min(5) }); const updateQuestionStatusSchema = Joi.object().keys({ diff --git a/frontend/src/pages/Q&A/AnswerModel/AnswerModel.jsx b/frontend/src/pages/Q&A/AnswerModel/AnswerModel.jsx index aaf075af..f7d087e4 100644 --- a/frontend/src/pages/Q&A/AnswerModel/AnswerModel.jsx +++ b/frontend/src/pages/Q&A/AnswerModel/AnswerModel.jsx @@ -1,31 +1,34 @@ import React, { useEffect, useState } from "react"; import { Modal, Backdrop, Fade } from '@material-ui/core'; import { SimpleToast } from '../../../components/util/Toast' -import {postAnswer,getAnswers} from '../../../service/Faq' +import { postAnswer, getAnswers,upvoteAnswer,downvoteAnswer } from '../../../service/Faq' import style from './AnswerModel.scss' export function AnswerModel(props) { + let dark=props.theme const [answer, setAnswer] = useState("") - const[answers,setAnswers]=useState([]) + const [author, setAuthor] = useState("") + const [answers, setAnswers] = useState([]) const [toast, setToast] = useState({ toastStatus: false, toastType: "", toastMessage: "", }); - const filterAnswers=(fetchedAnswers)=>{ - return fetchedAnswers.filter((ans)=>{return ans.isApproved==true}) + const filterAnswers = (fetchedAnswers) => { + return fetchedAnswers.filter((ans) => { return ans.isApproved == true }) } - async function fetchAnswers(){ - const data=await getAnswers(props.data._id,setToast) + async function fetchAnswers() { + const data = await getAnswers(props.data._id, setToast) setAnswers(filterAnswers(data)) } - useEffect(()=>{ - fetchAnswers() - },[props]) - function timeStampFormatter(time){ - const months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] - const messageTime=new Date(time) - return `${String(messageTime.getDate())} ${String(months[messageTime.getMonth()])} ${String(messageTime.getFullYear())} ${String(messageTime.getHours()%12 || 12).padStart(2,'0')}:${String(messageTime.getMinutes()).padStart(2,'0')} ${messageTime.getHours()>=12?'pm':'am'}` + useEffect(() => { + if (props.open) + fetchAnswers() + }, [props]) + function timeStampFormatter(time) { + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + const messageTime = new Date(time) + return `${String(messageTime.getDate())} ${String(months[messageTime.getMonth()])} ${String(messageTime.getFullYear())} ${String(messageTime.getHours() % 12 || 12).padStart(2, '0')}:${String(messageTime.getMinutes()).padStart(2, '0')} ${messageTime.getHours() >= 12 ? 'pm' : 'am'}` } const Tags = [ { value: "ml" }, @@ -43,22 +46,31 @@ export function AnswerModel(props) { ]; function handleSubmit(e) { e.preventDefault() - if(answer!=""){ - let data={question_id:props.data._id,answer,created_on:new Date(),created_by:"Anonymous"} - postAnswer(data,setToast) + if (answer != "" && author != "") { + let data = { question_id: props.data._id, answer, created_on: new Date(), created_by: author } + postAnswer(data, setToast) setAnswer("") + setAuthor("") props.handleClose(false) - }else{ - setToast({toastStatus:true,toastMessage:"Please enter your answer",toastType:"error"}) + } else { + setToast({ toastStatus: true, toastMessage: "Please fill both the fields", toastType: "error" }) } } + const handleUpvote=async(answerId)=>{ + await upvoteAnswer(answerId,setToast) + fetchAnswers() + } + const handleDownvote=async(answerId)=>{ + await downvoteAnswer(answerId,setToast) + fetchAnswers() + } return (
{props.data?.description}
-{props.data?.description}
+No answers found...
- : -{timeStampFormatter(ans.created_on)}
+ answers.length == 0 ? +No answers found...
+ : +{timeStampFormatter(ans.created_on)}
+{ans.answer}
+{ans.answer}
-- {item?.created_by||"Anonymous"}
+