Merge branch 'main' of github.com:spicecat/qOverflow
This commit is contained in:
commit
046c0d61fe
23 changed files with 215 additions and 141 deletions
|
|
@ -1,12 +1,12 @@
|
|||
import { ButtonGroup, ListItem, ListItemText, Tooltip } from '@mui/material';
|
||||
import { Button, ButtonGroup, ListItem, ListItemText, Tooltip } from '@mui/material';
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
|
||||
import CreationInfoTag from 'components/CreationInfoTag';
|
||||
import { useUser } from 'contexts';
|
||||
import { AnswerCommentsList, CommentControl, VoteControl } from 'controllers/QAControllers';
|
||||
import { CreationInfoTag } from 'controllers';
|
||||
import { getAnswerVote, updateAnswerVote, postAnswerComment } from 'services/questionsServices';
|
||||
|
||||
import { getAnswerVote, updateAcceptAnswer, updateAnswerVote, updateQuestion } from 'services/questionsServices';
|
||||
import { useQuestion } from 'contexts';
|
||||
import { postQuestionComment, postAnswerComment } from 'services/questionsServices';
|
||||
export default function Answer({
|
||||
accepted,
|
||||
answer_id,
|
||||
|
|
@ -23,21 +23,22 @@ export default function Answer({
|
|||
const getVote = () => getAnswerVote(question_id, answer_id);
|
||||
const updateVote = (data) => updateAnswerVote(question_id, answer_id, data);
|
||||
|
||||
const {permissions} = useQuestion();
|
||||
let canVote = permissions.canVote;
|
||||
let canComment = permissions.canComment;
|
||||
let canAccept = permissions.canAccept;
|
||||
|
||||
function acceptAnswer(){
|
||||
updateAcceptAnswer(question_id, answer_id)
|
||||
|
||||
}
|
||||
const postComment = (data) => postAnswerComment(question_id, answer_id, data);
|
||||
|
||||
return (
|
||||
<span key={answer_id}>
|
||||
<ListItem disablePadding>
|
||||
<ButtonGroup orientation='vertical'>
|
||||
<VoteControl
|
||||
{...{
|
||||
downvotes,
|
||||
getVote,
|
||||
orientation: 'vertical',
|
||||
updateVote,
|
||||
upvotes,
|
||||
}}
|
||||
/>
|
||||
<VoteControl {...{ downvotes, getVote, orientation: 'vertical', updateVote, upvotes, canVote }} />
|
||||
{accepted && (
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Tooltip title='Accepted Answer' placement='right'>
|
||||
|
|
@ -47,14 +48,12 @@ export default function Answer({
|
|||
)}
|
||||
</ButtonGroup>
|
||||
<ListItemText>
|
||||
<CreationInfoTag
|
||||
{...{ createdAt, creator, text: 'answered' }}
|
||||
/>
|
||||
<ReactMarkdown>{text}</ReactMarkdown>
|
||||
<CommentControl {...{
|
||||
canComment: level >= 3 || creator === username,
|
||||
postComment
|
||||
}} />
|
||||
<CreationInfoTag {...{ createdAt, creator, text: 'answered' }} />
|
||||
<ReactMarkdown>
|
||||
{text}
|
||||
</ReactMarkdown>
|
||||
<CommentControl {...{canComment, postComment}} />
|
||||
<Tooltip title = {!canAccept && "Only the creator can accept, or an answer is already accepted"}><span><Button onClick = {acceptAnswer} disabled = {!canAccept} style = {{'marginLeft':'10px'}}variant = "standard">Accept</Button></span></Tooltip>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem sx={{ pl: 8 }}>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Divider, ListItem, ListItemText } from '@mui/material';
|
|||
import { CreationInfoTag } from 'controllers';
|
||||
import { VoteControl } from 'controllers/QAControllers';
|
||||
import { getAnswerCommentVote, updateAnswerCommentVote } from 'services/questionsServices';
|
||||
|
||||
import { useQuestion } from 'contexts';
|
||||
export default function AnswerComment({
|
||||
answer_id,
|
||||
comment_id,
|
||||
|
|
@ -15,7 +15,8 @@ export default function AnswerComment({
|
|||
}) {
|
||||
const getVote = () => getAnswerCommentVote(question_id, answer_id, comment_id);
|
||||
const updateVote = (data) => updateAnswerCommentVote(question_id, answer_id, comment_id, data);
|
||||
|
||||
const {permissions} = useQuestion();
|
||||
let canVote = permissions.canVote;
|
||||
return (
|
||||
<span key={comment_id}>
|
||||
<ListItem disablePadding>
|
||||
|
|
@ -23,7 +24,7 @@ export default function AnswerComment({
|
|||
<CreationInfoTag {...{ createdAt, creator, text: 'commented' }} />
|
||||
{text}
|
||||
</ListItemText>
|
||||
<VoteControl {...{ downvotes, getVote, updateVote, upvotes }} />
|
||||
<VoteControl {...{ downvotes, getVote, updateVote, upvotes, canVote }} />
|
||||
</ListItem >
|
||||
<Divider />
|
||||
</span >
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Divider, ListItem, ListItemText } from '@mui/material';
|
|||
import { CreationInfoTag } from 'controllers';
|
||||
import { VoteControl } from 'controllers/QAControllers';
|
||||
import { getCommentVote, updateCommentVote } from 'services/questionsServices';
|
||||
import { useQuestion } from 'contexts';
|
||||
|
||||
export default function Comment({
|
||||
comment_id,
|
||||
|
|
@ -10,11 +11,13 @@ export default function Comment({
|
|||
downvotes,
|
||||
question_id,
|
||||
text,
|
||||
upvotes
|
||||
upvotes,
|
||||
|
||||
}) {
|
||||
const getVote = () => getCommentVote(question_id, comment_id);
|
||||
const updateVote = (data) => updateCommentVote(question_id, comment_id, data);
|
||||
|
||||
const {permissions} = useQuestion();
|
||||
let canVote = permissions.canVote;
|
||||
return (
|
||||
<span key={comment_id}>
|
||||
<ListItem disablePadding>
|
||||
|
|
@ -22,7 +25,7 @@ export default function Comment({
|
|||
<CreationInfoTag {...{ createdAt, creator, text: 'commented' }} />
|
||||
{text}
|
||||
</ListItemText>
|
||||
<VoteControl {...{ downvotes, getVote, updateVote, upvotes }} />
|
||||
<VoteControl {...{ downvotes, getVote, updateVote, upvotes, canVote}} />
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ export default function CommentControl({
|
|||
commentSchema,
|
||||
postComment,
|
||||
show,
|
||||
toggleShow
|
||||
toggleShow,
|
||||
|
||||
|
||||
}) {
|
||||
|
||||
|
||||
return (
|
||||
<span>
|
||||
<ButtonGroup style={{ alignItems: 'center' }}>
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ export default function CreateAnswer({
|
|||
|
||||
return (
|
||||
<div>
|
||||
<Tooltip title={canAnswer ? '' : 'You need to be authenticated to answer or level 5 if the question is protected'}>
|
||||
<Tooltip title={!canAnswer ? '' : 'You need to be authenticated to answer or level 5 if the question is protected'}>
|
||||
<span>
|
||||
<Button
|
||||
disabled={!canAnswer}
|
||||
disabled={canAnswer}
|
||||
variant='contained'
|
||||
onClick={toggleShow}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -9,18 +9,13 @@ import {
|
|||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { CreationInfoTag } from 'controllers';
|
||||
import { CommentControl, CreateAnswer, VoteControl } from 'controllers/QAControllers';
|
||||
import { useUser } from 'contexts';
|
||||
import {
|
||||
getQuestionVote,
|
||||
postQuestionComment,
|
||||
editQuestionStatus,
|
||||
updateQuestionVote,
|
||||
} from 'services/questionsServices';
|
||||
|
||||
import { CommentControl, VoteControl } from 'controllers/QAControllers';
|
||||
import { getQuestionVote, postQuestionComment,openQuestion,protectQuestion , updateQuestion, closeQuestion, updateQuestionVote } from 'services/questionsServices';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useQuestion, useUser } from 'contexts';
|
||||
import CreateAnswer from './CreateAnswer';
|
||||
const statusColor = (status) => {
|
||||
switch (status) {
|
||||
case 'open':
|
||||
|
|
@ -47,19 +42,67 @@ export default function Question({
|
|||
question_id,
|
||||
upvotes,
|
||||
views,
|
||||
protect,
|
||||
close,
|
||||
reopen
|
||||
}) {
|
||||
const { userData: { level, username } } = useUser();
|
||||
|
||||
|
||||
const protect = level >= 6 && status === 'open';
|
||||
const close = level >= 7;
|
||||
const {userData} = useUser();
|
||||
const [ongoingVote, setOngoingVote] = useState({})
|
||||
const {setPermissions} = useQuestion();
|
||||
|
||||
function setVote(){
|
||||
if(protect.length > 0){setOngoingVote({users : protect, type : "protect"})}
|
||||
if(close.length > 0){setOngoingVote({users : close, type : "close"})}
|
||||
if(reopen.length > 0){setOngoingVote({users : reopen, type : "open"})}
|
||||
}
|
||||
|
||||
function changeProtect() {
|
||||
editQuestionStatus(question_id, 'protect');
|
||||
|
||||
|
||||
let level = 0;
|
||||
let protection = false;
|
||||
|
||||
let canProtect = false;
|
||||
let canClose = false;
|
||||
let canComment = false;
|
||||
let canAnswer = true;
|
||||
let canVote = true;
|
||||
let canAccept = false;
|
||||
|
||||
|
||||
|
||||
if(userData.username){
|
||||
level = userData.level;
|
||||
if(status === 'protected' || status === 'closed'){protection = true;}
|
||||
if(userData.username === creator && !hasAcceptedAnswer){canAccept = true}
|
||||
if(level >= 7 && ongoingVote.type !== "protect"){canClose = true}
|
||||
if(level >= 6 && !protection && ongoingVote.type !== "close"){canProtect = true}
|
||||
if((level >= 3 && !protection) || (status === 'protected' && level >= 5) || (userData.username === creator)){canComment = true}
|
||||
if((status === 'protected' && level < 5) || status === 'closed'){canAnswer = false}
|
||||
if(status === 'closed' || level < 2){canVote = false}
|
||||
}else{
|
||||
canAnswer = false;
|
||||
}
|
||||
useEffect(()=>{
|
||||
setPermissions({canVote: canVote, canComment: canComment, canAccept: canAccept })
|
||||
setVote();
|
||||
},[canVote, canComment, canAccept])
|
||||
|
||||
function changeClose() {
|
||||
const operation = status === 'open' ? 'close' : 'reopen';
|
||||
editQuestionStatus(question_id, operation);
|
||||
useEffect(()=>{
|
||||
updateQuestion(question_id, {views: "increment"})
|
||||
},[])
|
||||
|
||||
function changeProtect(){
|
||||
protectQuestion(question_id, userData)
|
||||
}
|
||||
function changeClose(){
|
||||
if(status === 'open'){
|
||||
closeQuestion(question_id, userData)
|
||||
}else{
|
||||
openQuestion(question_id, userData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const getVote = () => getQuestionVote(question_id);
|
||||
|
|
@ -87,44 +130,21 @@ export default function Question({
|
|||
label={hasAcceptedAnswer ? 'yes' : 'no'}
|
||||
size='small'
|
||||
/>
|
||||
<Button
|
||||
component={Link}
|
||||
display='inline'
|
||||
m={1}
|
||||
style={{ marginLeft: '10px' }}
|
||||
to='../ask'
|
||||
variant='contained'
|
||||
>
|
||||
Ask question
|
||||
</Button>
|
||||
<Tooltip title={close ? '' : 'You must be level 7'}>
|
||||
<Button component={Link} to='../ask' style={{'marginLeft': '10px'}}display = 'inline' m = {1} variant = "contained">Ask question</Button>
|
||||
|
||||
<Tooltip title = {!canClose && "You must be level 7"}>
|
||||
<span>
|
||||
<Button
|
||||
disabled={!close}
|
||||
style={{ marginLeft: '10px' }}
|
||||
display='inline'
|
||||
m={1}
|
||||
onClick={changeProtect}
|
||||
variant='contained'
|
||||
>
|
||||
Close/Open
|
||||
</Button>
|
||||
<Button disabled = {!canClose} style={{'marginLeft': '10px'}}display = 'inline' m = {1} variant = "contained" onClick = {changeClose}>Close/Open</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip title={protect ? '' : 'You must be level 6 and this question must be open'}>
|
||||
|
||||
<Tooltip title = {!canProtect && "You must be level 6 and this question must be open" }>
|
||||
<span>
|
||||
<Button
|
||||
disabled={!protect}
|
||||
style={{ marginLeft: '10px' }}
|
||||
display='inline'
|
||||
m={1}
|
||||
variant='contained'
|
||||
onClick={changeClose}
|
||||
>
|
||||
Protect
|
||||
</Button>
|
||||
<Button disabled = {!canProtect} style={{'marginLeft': '10px'}}display = 'inline' m = {1} variant = "contained" onClick = {changeProtect}>Protect</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
{Object.keys(ongoingVote).length > 0 && <Typography>{ongoingVote.users.toString()} - voting to {ongoingVote.type} this question </Typography>}
|
||||
</Box>
|
||||
<Divider />
|
||||
|
||||
|
|
@ -140,14 +160,10 @@ export default function Question({
|
|||
/>
|
||||
<ListItemText>
|
||||
<CreationInfoTag {...{ createdAt, creator }} />
|
||||
<ReactMarkdown>{text}</ReactMarkdown>
|
||||
<CommentControl {...{
|
||||
canComment:
|
||||
(level >= 3 && status === 'open')
|
||||
|| (level >= 5 && status === 'protected')
|
||||
|| creator === username,
|
||||
postComment
|
||||
}} />
|
||||
<ReactMarkdown>
|
||||
{text}
|
||||
</ReactMarkdown>
|
||||
<CommentControl {...{ postComment, canComment}} />
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<CreateAnswer />
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export default function VoteControl({
|
|||
upvotes,
|
||||
vote
|
||||
}) {
|
||||
|
||||
|
||||
return (
|
||||
<span style={{ marginRight: 8 }}>
|
||||
<ButtonGroup {...{ orientation, style: { alignItems: 'center' } }}>
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ export default function Buffet() {
|
|||
|
||||
const [sort, setSort] = useState(0);
|
||||
|
||||
const getData = async ({ question_id }) => {
|
||||
const getData = async () => {
|
||||
|
||||
const { error, questions } = await searchQuestions({
|
||||
...sortObjArr[sort],
|
||||
after: question_id
|
||||
...sortObjArr[sort]
|
||||
|
||||
});
|
||||
if (error) {
|
||||
setError(error);
|
||||
|
|
|
|||
|
|
@ -29,15 +29,13 @@ export default function Dashboard() {
|
|||
setCurrent(value);
|
||||
};
|
||||
|
||||
const getAnswers = async ({ answer_id }) => {
|
||||
const { error, answers } = await getUserAnswers({ after: answer_id });
|
||||
const getAnswers = async () => {
|
||||
const { error, answers } = await getUserAnswers();
|
||||
if (!error) return answers;
|
||||
};
|
||||
|
||||
const getQuestions = async ({ question_id }) => {
|
||||
const { error, questions } = await getUserQuestions({
|
||||
after: question_id,
|
||||
});
|
||||
const getQuestions = async () => {
|
||||
const { error, questions } = await getUserQuestions();
|
||||
if (!error) return questions;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { searchQuestions } from 'services/questionsServices';
|
|||
export default function Search() {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const getData = async ({ question_id }) => {
|
||||
const getData = async () => {
|
||||
let match = {};
|
||||
const regexMatch = {}
|
||||
const time = {};
|
||||
|
|
@ -32,7 +32,7 @@ export default function Search() {
|
|||
const title = searchParams.get('title');
|
||||
if (title) regexMatch.title = title.replaceAll(' ', '|');
|
||||
|
||||
const { questions } = await searchQuestions({ after: question_id, regexMatch, match })
|
||||
const { questions } = await searchQuestions({ regexMatch, match })
|
||||
|
||||
return questions;
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ export default function Search() {
|
|||
<SearchForm />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<PaginatedList {...{ Component: ListQuestion, getData }} />;
|
||||
<PaginatedList {...{ concat: true, Component: ListQuestion, getData }} />;
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ const QuestionContext = createContext();
|
|||
export default function QuestionProvider({ children }) {
|
||||
const { question_id } = useParams();
|
||||
const [questionData, setQuestionData] = useState(initialQuestionData);
|
||||
const [permissions, setPermissions] = useState({})
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const loadQuestion = async () => {
|
||||
|
|
@ -21,7 +23,7 @@ export default function QuestionProvider({ children }) {
|
|||
}, [question_id]);
|
||||
|
||||
return (
|
||||
<QuestionContext.Provider value={{ questionData }}>
|
||||
<QuestionContext.Provider value={{ questionData, permissions, setPermissions }}>
|
||||
<Helmet>
|
||||
<title>{questionData.title}</title>
|
||||
</Helmet>
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ export default function AskFormController() {
|
|||
const askQuestion = async (fields) => {
|
||||
const { status } = await postQuestion(fields);
|
||||
|
||||
if (status === 200)
|
||||
navigate('/');
|
||||
if (status === "success") {
|
||||
navigate('../');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -3,17 +3,19 @@ import { PaginatedList } from 'components';
|
|||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
const rowsPerPage = 5;
|
||||
|
||||
export default function PaginatedListController({
|
||||
concat = true,
|
||||
concat = false,
|
||||
count,
|
||||
Component,
|
||||
getData,
|
||||
noData,
|
||||
}) {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [page, setPage] = useState(1);
|
||||
const [load, setLoad] = useState(true);
|
||||
const searchParams = useSearchParams();
|
||||
const [load, setLoad] = useState(concat);
|
||||
|
||||
const handleChangePage = (_, newPage) => {
|
||||
setPage(newPage);
|
||||
|
|
@ -21,13 +23,12 @@ export default function PaginatedListController({
|
|||
loadData();
|
||||
};
|
||||
|
||||
const loadData = async () => {
|
||||
const newData = await getData(
|
||||
concat ? data[data.length - 1] ?? {} : {}
|
||||
);
|
||||
if (newData.length)
|
||||
if (concat) setData(data.concat(newData));
|
||||
else setData(newData);
|
||||
const loadData = async (clear) => {
|
||||
const newData = await getData(clear ? {} : data[data.length - 1] ?? {});
|
||||
|
||||
if (newData?.length)
|
||||
if (clear) setData(newData);
|
||||
else setData(data.concat(newData));
|
||||
else setLoad(false);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,19 +4,21 @@ import { CommentControl } from 'components/QAComponents';
|
|||
import { commentFields } from 'services/fields';
|
||||
import { commentSchema } from 'services/schemas';
|
||||
|
||||
export default function CommentControlController({ canComment, postComment }) {
|
||||
const [show, setShow] = useState(false);
|
||||
|
||||
export default function CommentControlController({ postComment, canComment }) {
|
||||
const [show, setShow] = useState(false)
|
||||
|
||||
const toggleShow = () => {
|
||||
setShow(!show);
|
||||
};
|
||||
|
||||
return CommentControl({
|
||||
canComment,
|
||||
commentFields,
|
||||
commentSchema,
|
||||
postComment,
|
||||
show,
|
||||
toggleShow,
|
||||
});
|
||||
return (
|
||||
CommentControl({
|
||||
commentFields,
|
||||
commentSchema,
|
||||
postComment,
|
||||
show,
|
||||
toggleShow,
|
||||
canComment
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { getAnswerComments, getAnswers, getQuestionComments } from 'services/que
|
|||
export function AnswerCommentsList({ answer_id, comments: count }) {
|
||||
const { questionData: { question_id } } = useQuestion();
|
||||
|
||||
const getData = () =>
|
||||
getAnswerComments(question_id, answer_id)
|
||||
const getData = ({ comment_id }) =>
|
||||
getAnswerComments(question_id, answer_id, { after: comment_id })
|
||||
.then(({ comments }) => comments.map(comment => ({ ...comment, answer_id, question_id })))
|
||||
.catch(() => []);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export default function VoteControlController({
|
|||
orientation,
|
||||
updateVote,
|
||||
upvotes,
|
||||
canVote
|
||||
}) {
|
||||
const { questionData: { status } } = useQuestion();
|
||||
const { userData: { level } } = useUser();
|
||||
|
|
@ -63,7 +64,8 @@ export default function VoteControlController({
|
|||
handleUpvote,
|
||||
orientation,
|
||||
upvotes: upvotes + (vote === 'upvoted') - (original === 'upvoted'),
|
||||
vote
|
||||
vote,
|
||||
canVote
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,30 @@ const getQuestion = async (question_id) =>
|
|||
callQuestionsAPI('get', `/${question_id}`);
|
||||
|
||||
const updateQuestion = async (question_id, data) =>
|
||||
callQuestionsAPI('patch', `/${question_id}`, data);
|
||||
callQuestionsAPI(
|
||||
'patch',
|
||||
`/${question_id}`,
|
||||
data
|
||||
);
|
||||
const closeQuestion = async (question_id, data) =>
|
||||
callQuestionsAPI(
|
||||
'patch',
|
||||
`/${question_id}/close`,
|
||||
data
|
||||
);
|
||||
const openQuestion = async (question_id, data) =>
|
||||
callQuestionsAPI(
|
||||
'patch',
|
||||
`/${question_id}/reopen`,
|
||||
data
|
||||
);
|
||||
const protectQuestion = async (question_id, data) =>
|
||||
callQuestionsAPI(
|
||||
'patch',
|
||||
`/${question_id}/protect`,
|
||||
data
|
||||
);
|
||||
|
||||
|
||||
const getQuestionVote = async (question_id) =>
|
||||
callQuestionsAPI('get', `/${question_id}/vote`);
|
||||
|
|
@ -48,7 +71,10 @@ const updateAnswer = async (question_id, answer_id, data) =>
|
|||
callQuestionsAPI('patch', `/${question_id}/answers/${answer_id}`, data);
|
||||
|
||||
const updateAcceptAnswer = async (question_id, answer_id) =>
|
||||
callQuestionsAPI('patch', `/${question_id}/answer/${answer_id}/accept`);
|
||||
callQuestionsAPI(
|
||||
'patch',
|
||||
`/${question_id}/answers/${answer_id}/accept`
|
||||
);
|
||||
|
||||
const getAnswerVote = async (question_id, answer_id) =>
|
||||
callQuestionsAPI('get', `/${question_id}/answers/${answer_id}/vote`);
|
||||
|
|
@ -120,5 +146,7 @@ export {
|
|||
updateCommentVote,
|
||||
updateQuestion,
|
||||
updateQuestionVote,
|
||||
editQuestionStatus,
|
||||
closeQuestion,
|
||||
openQuestion,
|
||||
protectQuestion
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ async function CreateAnswer(req, res) {
|
|||
amount: 2,
|
||||
});
|
||||
|
||||
await User.findByIdAndUpdate(user.id, { $inc: { $points: 2 } });
|
||||
await User.findByIdAndUpdate(user.id, { $inc: { points: 2 } });
|
||||
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ async function EditAnswerAccepted(req, res) {
|
|||
}
|
||||
|
||||
const cachedAnswer = await Answer.findByIdAndDelete(answer_id);
|
||||
//update hasAcceptedAnswer
|
||||
await createRequest('patch', `/questions/${question_id}`, {
|
||||
hasAcceptedAnswer: true
|
||||
});
|
||||
|
||||
// Increment points of answer creator
|
||||
await createRequest('patch', `/users/${cachedAnswer.creator}/points`, {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,23 @@ const createRequest = require('server/utils/api');
|
|||
async function EditQuestion(req, res) {
|
||||
const { user } = req;
|
||||
const { text } = req.body;
|
||||
const {views} = req.body;
|
||||
const { question_id } = req.params;
|
||||
|
||||
|
||||
if(views){
|
||||
const { success } = await createRequest(
|
||||
'patch',
|
||||
`/questions/${question_id}`,
|
||||
{ views }
|
||||
);
|
||||
|
||||
if (!success) return res.status(500).send(config.errorGeneric);
|
||||
|
||||
await refreshQuestion(question_id);
|
||||
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
if (!text) return res.status(400).send(config.errorIncomplete);
|
||||
|
||||
// Verify user owns question
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ async function EditQuestionStatusClosed(req, res) {
|
|||
// Toggle question vote
|
||||
if (question.close.includes(user.username)) {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
close: { $pull: user.username },
|
||||
$pull: { close: user.username },
|
||||
});
|
||||
|
||||
return res.sendStatus(200);
|
||||
} else {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
close: { $push: user.username },
|
||||
$push: { close: user.username },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ async function EditQuestionStatusProtected(req, res) {
|
|||
// Toggle vote
|
||||
if (question.protect.includes(user.username)) {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
protect: { $pull: user.username },
|
||||
$pull: { protect: user.username },
|
||||
});
|
||||
|
||||
return res.sendStatus(200);
|
||||
} else {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
protect: { $push: user.username },
|
||||
$push: { protect: user.username },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ async function EditQuestionStatusReopened(req, res) {
|
|||
// Toggle vote
|
||||
if (question.reopen.includes(user.username)) {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
reopen: { $pull: user.username },
|
||||
$pull: { reopen: user.username },
|
||||
});
|
||||
|
||||
return res.sendStatus(200);
|
||||
} else {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
reopen: { $push: user.username },
|
||||
$push: { reopen: user.username },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Reference in a new issue