diff --git a/client/package.json b/client/package.json index 289fe82..6fe2359 100644 --- a/client/package.json +++ b/client/package.json @@ -16,6 +16,7 @@ "js-cookie": "^3.0.1", "marked": "^4.0.18", "react": "^18.2.0", + "react-copy-to-clipboard": "^5.1.0", "react-gravatar": "^2.6.3", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", diff --git a/client/src/components/MailUnit.jsx b/client/src/components/MailUnit.jsx index d818e4d..a694f7f 100644 --- a/client/src/components/MailUnit.jsx +++ b/client/src/components/MailUnit.jsx @@ -3,11 +3,23 @@ import { Accordion, AccordionDetails, AccordionSummary, Box, Typography } from ' import ReactTimeAgo from 'react-time-ago'; import { Markdown } from 'components'; +import { readMail } from 'services/mailServices'; -export default function MailUnit({ sender, createdAt, subject, text }) { +export default function MailUnit({ + mail_id, + sender, + createdAt, + subject, + text, + read, +}) { return ( - }> + } + onClick={() => {readMail(mail_id)}} + sx={read && {backgroundColor: 'lightGray'}} + > From {sender} @@ -16,6 +28,8 @@ export default function MailUnit({ sender, createdAt, subject, text }) { {subject} + + Read: {String(read)} diff --git a/client/src/components/Profile.jsx b/client/src/components/Profile.jsx index 96b3d93..4b9c15d 100644 --- a/client/src/components/Profile.jsx +++ b/client/src/components/Profile.jsx @@ -2,15 +2,17 @@ import { IconButton, Typography } from '@mui/material'; import Gravatar from 'react-gravatar'; import { Link } from 'react-router-dom'; -export default function Profile({ userData: { email, level, points } }) { +export default function Profile({ userData: { badgeCount, email, level, points } }) { return ( <> - - {level} - {points} - + {level} + {points} + {badgeCount?.gold} + /{badgeCount?.silver} + /{badgeCount?.bronze} ); } diff --git a/client/src/components/QAComponents/AnswerComment.jsx b/client/src/components/QAComponents/AnswerComment.jsx index 79fabdb..c89e9a7 100644 --- a/client/src/components/QAComponents/AnswerComment.jsx +++ b/client/src/components/QAComponents/AnswerComment.jsx @@ -1,4 +1,5 @@ -import { Divider, ListItem, ListItemText } from '@mui/material'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { Divider, IconButton, ListItem, ListItemText } from '@mui/material'; import { CreationInfoTag } from 'controllers'; import { VoteControl } from 'controllers/QAControllers'; @@ -11,6 +12,7 @@ export default function AnswerComment({ text, upvotes, getVote, + onDelete, updateVote, }) { return ( @@ -21,6 +23,9 @@ export default function AnswerComment({ {text} + {onDelete && + + } diff --git a/client/src/components/QAComponents/Comment.jsx b/client/src/components/QAComponents/Comment.jsx index 6883072..8f715c8 100644 --- a/client/src/components/QAComponents/Comment.jsx +++ b/client/src/components/QAComponents/Comment.jsx @@ -1,4 +1,5 @@ -import { Divider, ListItem, ListItemText } from '@mui/material'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { Divider, IconButton, ListItem, ListItemText } from '@mui/material'; import { CreationInfoTag } from 'controllers'; import { VoteControl } from 'controllers/QAControllers'; @@ -11,7 +12,8 @@ export default function Comment({ text, upvotes, getVote, - updateVote, + onDelete, + updateVote }) { return ( @@ -21,6 +23,9 @@ export default function Comment({ {text} + {onDelete && + + } diff --git a/client/src/components/QAComponents/Suggest.jsx b/client/src/components/QAComponents/Suggest.jsx new file mode 100644 index 0000000..48e4793 --- /dev/null +++ b/client/src/components/QAComponents/Suggest.jsx @@ -0,0 +1,67 @@ +import {Tooltip, Button, Card, CardContent, Typography} from '@mui/material' +import { editQuestion } from 'services/questionsServices'; +import EditFormController from "controllers/FormControllers/EditQuestionFormController"; +import { useEffect, useState } from "react"; +import { useUser, useQuestion } from 'contexts'; +import { Markdown } from 'components'; +export default function Suggest(){ + const [show, setShow] = useState(false); + const [canSuggest, setCanSuggest] = useState(false) + const {userData} = useUser(); + const {questionData} = useQuestion(); + const [ongoingEdit, setOngoingEdit] = useState({users : [], new : []}) + + useEffect(()=>{ + setCanSuggest(userData.level >= 7) + + if(ongoingEdit.users.length > 0)setCanSuggest((userData.username !== ongoingEdit.users[0])) + if(!questionData.loading) setOngoingEdit({users : questionData.edit, new : questionData.editText}) + },[userData, questionData, setCanSuggest]) + + async function toggleShow(){ + if(questionData.edit.length === 0){ + setShow(!show) + }else{ + const { status } = await editQuestion(questionData.question_id); + } + + } + + + + return ( +
+ + + + + + {show && ( + + + + + + )} + {ongoingEdit.users.length > 0 && + + + + + + {ongoingEdit.users} have voted to edit the question + + + } + + +
+ ); +} \ No newline at end of file diff --git a/client/src/containers/QA.jsx b/client/src/containers/QA.jsx index 757301f..64cd8b7 100644 --- a/client/src/containers/QA.jsx +++ b/client/src/containers/QA.jsx @@ -1,4 +1,5 @@ import { List, ListItem } from '@mui/material'; +import Suggest from 'components/QAComponents/Suggest'; import { AnswersList, CommentsList, CreateAnswer, Question } from 'controllers/QAControllers'; export default function QA() { @@ -8,7 +9,8 @@ export default function QA() { - + +
diff --git a/client/src/contexts/UserContext.js b/client/src/contexts/UserContext.js index 5baf70c..d4ac10a 100644 --- a/client/src/contexts/UserContext.js +++ b/client/src/contexts/UserContext.js @@ -11,9 +11,6 @@ export default function UserProvider({ children }) { const [userData, setUserData] = useState(initialUserData) const navigate = useNavigate(); - - - useEffect(() => { const loadUserData = async () => { const { user, error } = await remember(); diff --git a/client/src/controllers/FormControllers/EditQuestionFormController.js b/client/src/controllers/FormControllers/EditQuestionFormController.js new file mode 100644 index 0000000..ca29d64 --- /dev/null +++ b/client/src/controllers/FormControllers/EditQuestionFormController.js @@ -0,0 +1,28 @@ + +import { Form } from 'controllers/FormControllers'; +import { generateEditFields } from 'services/fields'; +import { editQuestion } from 'services/questionsServices'; +import { questionSchema } from 'services/schemas'; +import { useQuestion } from 'contexts'; + +export default function EditFormController() { + const {questionData} = useQuestion(); + const {title, text} = questionData; + + + + const editTheQuestion = async (fields) => { + console.log("hello") + const { status } = await editQuestion(questionData.question_id, fields); + window.location.reload(false); + }; + + const field = generateEditFields + + return !questionData.loading && Form({ + fields: field, + onSubmit: editTheQuestion, + validationSchema: questionSchema, + initialValues: {etext : text, etitle : title} + }); +} diff --git a/client/src/controllers/FormControllers/FormController.js b/client/src/controllers/FormControllers/FormController.js index 9d2dcc3..e033785 100644 --- a/client/src/controllers/FormControllers/FormController.js +++ b/client/src/controllers/FormControllers/FormController.js @@ -1,6 +1,6 @@ import { useFormik } from 'formik'; import { useEffect } from 'react'; - +import { useQuestion } from 'contexts'; import { Form } from 'components'; import { useForm } from 'contexts'; @@ -10,11 +10,15 @@ export default function FormController({ validate, validationSchema, children, + initialValues }) { - const { setContent } = useForm(); + + const { setContent } = useForm(); + useEffect(() => { setContent(''); + }, [setContent]); const handleChange = (e) => { @@ -22,7 +26,7 @@ export default function FormController({ }; const formik = useFormik({ - initialValues: fields.reduce((acc, { id }) => ({ ...acc, [id]: '' }), {}), + initialValues: fields.reduce((acc, { id }) => ({ ...acc, [id]: initialValues[id] || '' }), {}), onSubmit, validate, validateOnChange: false, diff --git a/client/src/controllers/QAControllers/AnswerCommentController.jsx b/client/src/controllers/QAControllers/AnswerCommentController.jsx index 3c9c4d6..b83c48a 100644 --- a/client/src/controllers/QAControllers/AnswerCommentController.jsx +++ b/client/src/controllers/QAControllers/AnswerCommentController.jsx @@ -1,9 +1,19 @@ +import { useUser } from 'contexts'; import { AnswerComment } from 'components/QAComponents'; -import { getAnswerCommentVote, updateAnswerCommentVote } from 'services/questionsServices'; +import { getAnswerCommentVote, deleteAnswerComment, updateAnswerCommentVote } from 'services/questionsServices'; export default function AnswerCommentController({ answer_id, comment_id, question_id, ...props }) { + const { userData } = useUser(); + const getVote = () => getAnswerCommentVote(question_id, answer_id, comment_id); const updateVote = (data) => updateAnswerCommentVote(question_id, answer_id, comment_id, data); + const onDelete = async () => { + if (userData?.username === props?.creator) { + const { status } = await deleteAnswerComment(question_id, answer_id, comment_id); + if (status === 200) + window.location.reload(false); + } + } - return ; + return ; } diff --git a/client/src/controllers/QAControllers/CommentController.jsx b/client/src/controllers/QAControllers/CommentController.jsx index 87047fe..0e22cc7 100644 --- a/client/src/controllers/QAControllers/CommentController.jsx +++ b/client/src/controllers/QAControllers/CommentController.jsx @@ -1,9 +1,20 @@ +import { useUser } from 'contexts'; import { Comment } from 'components/QAComponents'; -import { getCommentVote, updateCommentVote } from 'services/questionsServices'; +import { getCommentVote, deleteQuestionComment, updateCommentVote } from 'services/questionsServices'; + export default function CommentController({ comment_id, question_id, ...props }) { + const { userData } = useUser(); + const getVote = () => getCommentVote(question_id, comment_id); const updateVote = (data) => updateCommentVote(question_id, comment_id, data); + const onDelete = async () => { + if (userData?.username === props?.creator) { + const { status } = await deleteQuestionComment(question_id, comment_id); + if (status === 200) + window.location.reload(false); + } + } - return ; + return ; } diff --git a/client/src/controllers/QAControllers/QuestionController.jsx b/client/src/controllers/QAControllers/QuestionController.jsx index d182891..695ac14 100644 --- a/client/src/controllers/QAControllers/QuestionController.jsx +++ b/client/src/controllers/QAControllers/QuestionController.jsx @@ -37,8 +37,8 @@ export default function QuestionController() { useEffect(() => { const permissions = getPermissions(questionData, userData, ongoingVote); - if(userData.username)canBounty = (userData.level >= 4 && status !== 'closed' && !questionData.hasBounty && !questionData.hasAcceptedAnswer) - + if (userData.username) canBounty = (userData.level >= 4 && status !== 'closed' && !questionData.hasBounty && !questionData.hasAcceptedAnswer) + permissions.canBounty = canBounty; setPermissions(permissions); setVote(); @@ -77,14 +77,14 @@ export default function QuestionController() { ongoingVoteSet(reopen, 'reopen'); } } - function handleBounty(amount){ - if(show){ - const data = {user : userData.username, hasAcceptedAnswer: questionData.hasAcceptedAnswer , amount: amount , isOpen: (questionData.status !== 'closed') , hasBounty: questionData.hasBounty } + function handleBounty(amount) { + if (show) { + const data = { user: userData.username, hasAcceptedAnswer: questionData.hasAcceptedAnswer, amount: amount, isOpen: (questionData.status !== 'closed'), hasBounty: questionData.hasBounty } addBounty(question_id, data) questionData.hasBounty = amount; userData.points -= amount; setShow(false) - }else{ + } else { setShow(true) } } @@ -111,7 +111,7 @@ export default function QuestionController() { postComment, show, handleBounty - + }} /> )} diff --git a/client/src/services/fields.js b/client/src/services/fields.js index 4545a94..e99386f 100644 --- a/client/src/services/fields.js +++ b/client/src/services/fields.js @@ -131,6 +131,22 @@ const searchFields = [ { id: 'tags', label: 'Tags (separated by spaces)' }, ]; +const generateEditFields = + + [ + { + id: 'etitle', + label: 'Title', + + }, + { + id: 'etext', + label: 'Text', + multiline: true, + + }, + ] + export { answerFields, askQuestionFields, @@ -142,4 +158,5 @@ export { recoverFields, resetFields, searchFields, + generateEditFields }; diff --git a/client/src/services/levels.json b/client/src/services/levels.json index 67b2b4f..009c7d5 100644 --- a/client/src/services/levels.json +++ b/client/src/services/levels.json @@ -1,8 +1,11 @@ { + "Level 1": 1, "Level 2": 15, "Level 3": 50, - "Level 4": 125, - "Level 5": 1000, - "Level 6": 3000, - "Level 7": 10000 + "Level 4": 75, + "Level 5": 125, + "Level 6": 1000, + "Level 7": 2000, + "Level 8" : 3000, + "Level 9" : 10000 } diff --git a/client/src/services/mailServices.js b/client/src/services/mailServices.js index 2dabea8..becd381 100644 --- a/client/src/services/mailServices.js +++ b/client/src/services/mailServices.js @@ -2,8 +2,11 @@ import { createEndpoint } from './api'; const callMailAPI = createEndpoint('/mail'); -const postMail = async (data) => callMailAPI('post', ``, data); - const getMail = async () => callMailAPI('get', ``); -export { getMail, postMail }; +const postMail = async (data) => callMailAPI('post', ``, data); + +const readMail = async (mail_id) => callMailAPI('patch', `/${mail_id}`, { read: 'true' }); + + +export { getMail, postMail, readMail }; diff --git a/client/src/services/questionsServices.js b/client/src/services/questionsServices.js index 6f34d63..bc3622a 100644 --- a/client/src/services/questionsServices.js +++ b/client/src/services/questionsServices.js @@ -11,8 +11,17 @@ const postQuestion = async (data) => callQuestionsAPI('post', ``, data); const getQuestion = async (question_id) => callQuestionsAPI('get', `/${question_id}`); -const addBounty = async (question_id, data) => - callQuestionsAPI('patch', `/${question_id}/addBounty`, data); +const addBounty = async (question_id,data) => callQuestionsAPI( + 'patch', + `/${question_id}/addBounty`, + data + +) +const editQuestion = async (question_id,data) => callQuestionsAPI( + 'patch', + `/${question_id}/edit`, + data +) const updateQuestion = async (question_id, data) => callQuestionsAPI('patch', `/${question_id}`, data); @@ -110,4 +119,5 @@ export { openQuestion, protectQuestion, addBounty, + editQuestion }; diff --git a/client/src/services/userServices.js b/client/src/services/userServices.js index faa74b6..7e9f04f 100644 --- a/client/src/services/userServices.js +++ b/client/src/services/userServices.js @@ -6,17 +6,17 @@ import { createEndpoint } from './api'; const callUsersAPI = createEndpoint('/users'); const getLoginAttempts = () => { - let loginAttempts = Number(Cookies.get('loginAttempts')) || 0; - let loginTimeout = Number(Cookies.get('loginTimeout')) - Date.now() || 0; + let loginAttempts = Number(Cookies.get('loginAttempts')) || 0; + let loginTimeout = Number(Cookies.get('loginTimeout')) - Date.now() || 0; - if (loginTimeout < 0) { - Cookies.remove('loginAttempts'); - Cookies.remove('loginTimeout'); - loginAttempts = 0; - loginTimeout = 0; - } + if (loginTimeout < 0) { + Cookies.remove('loginAttempts'); + Cookies.remove('loginTimeout'); + loginAttempts = 0; + loginTimeout = 0; + } - return { loginAttempts, loginTimeout }; + return { loginAttempts, loginTimeout }; }; const getUser = async (username) => callUsersAPI('get', `/${username}`); @@ -27,28 +27,28 @@ const getUserBadges = async () => callUsersAPI('get', `/badges`); const getUserQuestions = async () => callUsersAPI('get', `/questions`); -const deleteUser = async () => callUsersAPI('delete',`/delete`) +const deleteUser = async () => callUsersAPI('delete', `/delete`) const incrementLoginAttempts = () => { - const { loginAttempts } = getLoginAttempts(); - Cookies.set('loginAttempts', loginAttempts + 1); - if (loginAttempts >= 2) Cookies.set('loginTimeout', Date.now() + 1000 * 60 * 5); + const { loginAttempts } = getLoginAttempts(); + Cookies.set('loginAttempts', loginAttempts + 1); + if (loginAttempts >= 2) Cookies.set('loginTimeout', Date.now() + 1000 * 60 * 5); }; const login = async ({ username, password }) => { - const encoded = Buffer.from(`${username}:${password}`).toString('base64'); - const { token, ...data } = await callUsersAPI( - 'post', - `/login`, - { remember: false }, - `basic ${encoded}` - ); - if (token) { - Cookies.set('token', token); - Cookies.remove('loginAttempts'); - Cookies.remove('loginTimeout'); - } - return data; + const encoded = Buffer.from(`${username}:${password}`).toString('base64'); + const { token, ...data } = await callUsersAPI( + 'post', + `/login`, + { remember: false }, + `basic ${encoded}` + ); + if (token) { + Cookies.set('token', token); + Cookies.remove('loginAttempts'); + Cookies.remove('loginTimeout'); + } + return data; }; const logout = async () => callUsersAPI('post', `/login`, { remember: false }); @@ -58,13 +58,13 @@ const updateUser = async (data) => callUsersAPI('patch', ``, data); const register = async (data) => callUsersAPI('post', ``, data); const remember = async () => { - if (Cookies.get('token')) { - const { user, error } = await callUsersAPI('get', `/remember`); - if (user) - return { user }; - Cookies.remove('token'); - return { error } - } + if (Cookies.get('token')) { + const { user, error } = await callUsersAPI('get', `/remember`); + if (user) + return { user }; + Cookies.remove('token'); + return { error } + } } const requestReset = async (data) => callUsersAPI('post', `/reset`, data); @@ -72,18 +72,18 @@ const requestReset = async (data) => callUsersAPI('post', `/reset`, data); const resetPassword = async (id, data) => callUsersAPI('post', `/reset/${id}`, data); export { - getLoginAttempts, - getUser, - getUserAnswers, - getUserBadges, - getUserQuestions, - incrementLoginAttempts, - login, - logout, - register, - remember, - updateUser, - requestReset, - resetPassword, - deleteUser + getLoginAttempts, + getUser, + getUserAnswers, + getUserBadges, + getUserQuestions, + incrementLoginAttempts, + login, + logout, + register, + remember, + updateUser, + requestReset, + resetPassword, + deleteUser }; diff --git a/package-lock.json b/package-lock.json index 60df64f..122433f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "js-cookie": "^3.0.1", "marked": "^4.0.18", "react": "^18.2.0", + "react-copy-to-clipboard": "^5.1.0", "react-gravatar": "^2.6.3", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", @@ -32177,6 +32178,7 @@ "js-cookie": "^3.0.1", "marked": "^4.0.18", "react": "^18.2.0", + "react-copy-to-clipboard": "*", "react-gravatar": "^2.6.3", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", diff --git a/server/bin/www b/server/bin/www index d0655af..1ba6662 100644 --- a/server/bin/www +++ b/server/bin/www @@ -43,8 +43,8 @@ mongoose.connection.on( console.error.bind(console, '[ERROR]: MongoDB connection error - ') ); -//cron.schedule('*/30 * * * * *', refreshQuestions); -//cron.schedule('*/2 * * * *', refreshUsers); +// cron.schedule('*/30 * * * * *', refreshQuestions); +// cron.schedule('*/2 * * * *', refreshUsers); server.listen(port, console.log(`Listening on port: ${port}`)); server.on('error', onError); diff --git a/server/db/models/Answer.js b/server/db/models/Answer.js index ff4ecba..f705a31 100644 --- a/server/db/models/Answer.js +++ b/server/db/models/Answer.js @@ -18,9 +18,10 @@ const Answer = mongoose.Schema( ); Answer.post('findOneAndUpdate', (doc) => { - const badges = calculateAnswerBadges(doc.points); - - User.findOneAndUpdate({ username: doc.creator }, { $addToSet: { tags: { $each: badges } } }); + if (doc) { + const badges = calculateAnswerBadges(doc.upvotes - doc.downvotes); + User.findOneAndUpdate({ username: doc.creator }, { $addToSet: { tags: { $each: badges } } }); + } }); module.exports = mongoose.model('Answer', Answer); diff --git a/server/db/models/Question.js b/server/db/models/Question.js index 9661147..fbed167 100644 --- a/server/db/models/Question.js +++ b/server/db/models/Question.js @@ -16,7 +16,7 @@ const Question = mongoose.Schema( reopen: [String], close: [String], edit: [String], - editText: { type: String }, + editText: [String], tags: [String], question_id: { type: String, required: true }, status: { type: String, required: true, default: 'open' }, @@ -24,15 +24,16 @@ const Question = mongoose.Schema( title: { type: String, required: true }, upvotes: { type: Number, required: true, default: 0 }, views: { type: Number, required: true, default: 0 }, - hasBounty: {type: Number, required: false} + hasBounty: { type: Number, required: false }, }, { timestamps: { createdAt: false, updatedAt: true } } ); Question.post('findOneAndUpdate', (doc) => { - const badges = calculateQuestionBadges(doc.points); - - User.findOneAndUpdate({ username: doc.creator }, { $addToSet: { tags: { $each: badges } } }); + if(doc){ + const badges = calculateQuestionBadges(doc.upvotes - doc.downvotes); + User.findOneAndUpdate({ username: doc.creator }, { $addToSet: { tags: { $each: badges } } }); + } }); module.exports = mongoose.model('Question', Question); diff --git a/server/db/models/User.js b/server/db/models/User.js index c959d32..3eb6861 100644 --- a/server/db/models/User.js +++ b/server/db/models/User.js @@ -17,10 +17,8 @@ const User = mongoose.Schema( User.post('findOneAndUpdate', async (doc) => { const badges = calculateUserBadges(doc.points); - doc.badges = [...new Set([...doc.badges, ...badges])]; - - doc.save(); + await doc.save(); }); module.exports = mongoose.model('User', User); diff --git a/server/routes/mail/Get.js b/server/routes/mail/Get.js index 81e0dc4..861c56f 100644 --- a/server/routes/mail/Get.js +++ b/server/routes/mail/Get.js @@ -7,15 +7,15 @@ async function Get(req, res) { // Fetch mail if expired if (Number(lastMailFetch) + config.mailExpires < Date.now()) { - const messages = await getAllMail({ username }); - return res.send({ messages }); - } else { + + await getAllMail({ username }) + } const messages = await Mail.find({ receiver: username }).sort({ createdAt: 'desc', }); return res.send({ messages }); - } + } module.exports = Get; diff --git a/server/routes/question/EditQuestionBody.js b/server/routes/question/EditQuestionBody.js index 04dd9ac..7a06cea 100644 --- a/server/routes/question/EditQuestionBody.js +++ b/server/routes/question/EditQuestionBody.js @@ -7,7 +7,7 @@ const getUserLevel = require('server/utils/getUserLevel'); async function EditQuestionStatusClosed(req, res) { const { user } = req; const { question_id } = req.params; - const { text } = req.body; + const { etext, etitle } = req.body; // Verify user has required level if (getUserLevel(user.points) < 7) { @@ -20,12 +20,12 @@ async function EditQuestionStatusClosed(req, res) { // Toggle question vote if (question.edit.length === 0) { - if (!text) { + if (!etext || !etitle) { return res.status(400).send(config.errorIncomplete); } await Question.findByIdAndUpdate(question_id, { - editText: text, + editText: etext, $push: { edit: user.username }, }); @@ -48,11 +48,13 @@ async function EditQuestionStatusClosed(req, res) { if (question.edit.length === 2) { const question = await Question.findByIdAndUpdate(question_id, { edit: [], - text, + etext, + etitle }); const { success } = await createRequest('patch', `/questions/${question_id}`, { - text, + etext, + etitle }); return success diff --git a/server/routes/user.js b/server/routes/user.js index 6799b89..eb42caa 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -21,7 +21,7 @@ router.post('/', Register); router.patch('/', tokenAuth, Edit); router.get('/questions', tokenAuth, Questions); router.get('/answers', tokenAuth, Answers); -router.get('/badge', tokenAuth, GetBadges); +router.get('/badges', tokenAuth, GetBadges); router.post('/login', basicAuth, Login); router.get('/remember', tokenAuth, Remember); router.delete('/logout', tokenAuth, Logout); diff --git a/server/routes/user/GetBadges.js b/server/routes/user/GetBadges.js index a7f0e34..fc83dd4 100644 --- a/server/routes/user/GetBadges.js +++ b/server/routes/user/GetBadges.js @@ -8,9 +8,9 @@ async function GetBadges(req, res) { const response = badges.reduce( (acc, badge) => { if (user.badges.includes(badge.title)) { - acc.obtained.append(badge); + acc.obtained.push(badge); } else { - acc.unobtained.append(badge); + acc.unobtained.push(badge); } return acc; @@ -18,7 +18,7 @@ async function GetBadges(req, res) { { obtained: [], unobtained: [] } ); - return res.send(response); + return res.send({ badges: response }); } module.exports = GetBadges; diff --git a/server/routes/user/GetUser.js b/server/routes/user/GetUser.js index b86dc67..9e0b720 100644 --- a/server/routes/user/GetUser.js +++ b/server/routes/user/GetUser.js @@ -55,8 +55,8 @@ async function GetUser(req, res) { email: newUser.email, points: newUser.points, level: getUserLevel(newUser.points), + badgeCount, }, - badgeCount, }); } diff --git a/server/routes/user/Remember.js b/server/routes/user/Remember.js index 3c6ea79..8507fed 100644 --- a/server/routes/user/Remember.js +++ b/server/routes/user/Remember.js @@ -1,15 +1,38 @@ const getUserLevel = require('server/utils/getUserLevel'); +const Badge = require('../../db/models/Badge'); async function Remember(req, res) { const { user } = req; + const badges = await Badge.find({ title: { $in: user.badges } }); + + const badgeCount = badges.reduce( + (acc, badge) => { + if (badge.rank === 'Gold') { + acc.gold = acc.gold + 1; + } else if (badge.rank === 'Silver') { + acc.silver = acc.silver + 1; + } else if (badge.rank === 'Bronze') { + acc.bronze = acc.bronze + 1; + } + + return acc; + }, + { + gold: 0, + silver: 0, + bronze: 0, + } + ); + return res.send({ user: { username: user.username, email: user.email, points: user.points, level: getUserLevel(user.points), - } + badgeCount, + }, }); }