Merge branch 'main' of https://github.com/spicecat/qOverflow
This commit is contained in:
commit
f1e9351dad
26 changed files with 127 additions and 122 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import { Helmet } from 'react-helmet';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { Box, CssBaseline } from '@mui/material';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
|
|
@ -22,6 +23,9 @@ export default function Layout() {
|
|||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline enableColorScheme />
|
||||
<Helmet>
|
||||
<title>qOverflow</title>
|
||||
</Helmet>
|
||||
<main>
|
||||
<Navbar />
|
||||
<Box sx={{ height: '92vh' }}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { Helmet } from 'react-helmet';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Card, CardContent, Grid, Typography, Alert } from '@mui/material';
|
||||
|
||||
import { LoginForm } from '../controllers/FormControllers';
|
||||
|
||||
export default function Login() {
|
||||
|
|
@ -10,29 +12,34 @@ export default function Login() {
|
|||
}
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
alignItems='center'
|
||||
justifyContent='center'
|
||||
style={{ height: '92vh' }}
|
||||
>
|
||||
<Grid item xs={3.5} />
|
||||
<Grid item xs={5}>
|
||||
<Card sx={{ padding: '1vh' }}>
|
||||
<CardContent>
|
||||
<LoginForm />
|
||||
<Typography variant='body1'>
|
||||
Forgot your password?{' '}
|
||||
<Link to='/users/recover'>Recover Password</Link>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{returnMsg() ? (
|
||||
<Alert severity='warning'> {returnMsg()} </Alert>
|
||||
) : null}
|
||||
<>
|
||||
<Helmet>
|
||||
<title>Log In - qOverflow</title>
|
||||
</Helmet>
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
alignItems='center'
|
||||
justifyContent='center'
|
||||
style={{ height: '92vh' }}
|
||||
>
|
||||
<Grid item xs={3.5} />
|
||||
<Grid item xs={5}>
|
||||
<Card sx={{ padding: '1vh' }}>
|
||||
<CardContent>
|
||||
<LoginForm />
|
||||
<Typography variant='body1'>
|
||||
Forgot your password?{' '}
|
||||
<Link to='/users/recover'>Recover Password</Link>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{returnMsg() ? (
|
||||
<Alert severity='warning'> {returnMsg()} </Alert>
|
||||
) : null}
|
||||
</Grid>
|
||||
<Grid item xs={3.5} />
|
||||
</Grid>
|
||||
<Grid item xs={3.5} />
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { Helmet } from 'react-helmet';
|
||||
import { Card, CardContent, Grid } from '@mui/material';
|
||||
|
||||
import CAPTCHA from 'assets/captcha.jpg';
|
||||
|
|
@ -5,6 +6,10 @@ import { RegisterForm } from 'controllers/FormControllers';
|
|||
|
||||
export default function Register() {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>Register - qOverflow</title>
|
||||
</Helmet>
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
|
|
@ -25,5 +30,6 @@ export default function Register() {
|
|||
</Grid>
|
||||
<Grid item xs={3.5} />
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ const http = require('http');
|
|||
const mongoose = require('mongoose');
|
||||
const cron = require('node-cron');
|
||||
|
||||
const {getAllQuestions, getAllUsers } = require('server/services/getData');
|
||||
const { refreshQuestions, refreshUsers } = require('server/utils/cronRefresh');
|
||||
|
||||
require('dotenv').config();
|
||||
|
||||
|
|
@ -39,8 +39,8 @@ mongoose.connect(process.env.DB_CONN_STRING, {
|
|||
mongoose.connection.once('open', () => console.log('MongoDB connected'));
|
||||
mongoose.connection.on('error', console.error.bind(console, 'MongoDB connection error:'));
|
||||
|
||||
cron.schedule('*/2 * * * *', getAllUsers);
|
||||
cron.schedule('*/30 * * * * *', getAllQuestions);
|
||||
cron.schedule('*/30 * * * * *', refreshQuestions);
|
||||
cron.schedule('*/2 * * * *', refreshUsers);
|
||||
|
||||
server.listen(port, console.log(`Listening on port: ${port}`));
|
||||
server.on('error', onError);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const config = require('server/config.json');
|
||||
const Answer = require('server/db/models/Answer');
|
||||
const User = require('server/db/models/User');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
const createRequest = require('server/utils/api');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const config = require('server/config.json');
|
||||
const Answer = require('server/db/models/Answer');
|
||||
const Comment = require('server/db/models/Comment');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const createRequest = require('server/utils/api');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Comment = require('server/db/models/Comment');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const createRequest = require('server/utils/api');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Answer = require('server/db/models/Answer');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const createRequest = require('server/utils/api');
|
||||
|
||||
async function EditAnswerAccepted(req, res) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const config = require('server/config.json');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const createRequest = require('server/utils/api');
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Question = require('server/db/models/Question');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const createRequest = require('server/utils/api');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Question = require('server/db/models/Question');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
const createRequest = require('server/utils/api');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Question = require('server/db/models/Question');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
const createRequest = require('server/utils/api');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const config = require('server/config.json');
|
||||
const User = require('server/db/models/User');
|
||||
const Vote = require('server/db/models/Vote');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const createRequest = require('server/utils/api');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,48 +1,21 @@
|
|||
const config = require('server/config.json');
|
||||
const Answer = require('server/db/models/Answer');
|
||||
const Question = require('server/db/models/Question');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const fetchAnswers = require('server/utils/fetchAnswers');
|
||||
const { getAllAnswers } = require('server/utils/getData');
|
||||
|
||||
async function GetAnswers(req, res) {
|
||||
const { question_id } = req.params;
|
||||
|
||||
const question = await getQuestion(question_id);
|
||||
if (!question) return res.status(404).send(config.errorNotFound);
|
||||
|
||||
// Fetch answers if expired
|
||||
if (Number(question.lastAnswerFetch) + config.answerExpires < Date.now()) {
|
||||
const { success, requests } = await fetchAnswers(
|
||||
`/questions/${question_id}/answers`
|
||||
);
|
||||
|
||||
if (!success) return res.status(500).send(config.errorGeneric);
|
||||
|
||||
// Reformat questions and patch to cache
|
||||
await requests
|
||||
.map(({ answer_id, ...answer }) => {
|
||||
return {
|
||||
...answer,
|
||||
id: answer_id,
|
||||
question_id
|
||||
}
|
||||
})
|
||||
.map(async (answer) => {
|
||||
if (answer.accepted) {
|
||||
await Question.findByIdAndUpdate(question_id, {
|
||||
hasAccepted: true,
|
||||
});
|
||||
}
|
||||
|
||||
return Answer.findByIdAndUpdate(answer.id, answer, {
|
||||
upsert: true,
|
||||
});
|
||||
});
|
||||
const answers = await getAllAnswers({ question_id });
|
||||
return res.send({ answers });
|
||||
} else{
|
||||
const answers = await Answer.find({ question_id });
|
||||
return res.send({ answers });
|
||||
}
|
||||
|
||||
const answers = await Answer.find({ question_id });
|
||||
|
||||
return res.send({ answers });
|
||||
}
|
||||
|
||||
module.exports = GetAnswers;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Comment = require('server/db/models/Comment');
|
||||
const { getQuestion, refreshQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const fetchComments = require('server/utils/fetchComments');
|
||||
|
||||
async function GetComments(req, res) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const config = require('server/config.json');
|
||||
const { getQuestion } = require('server/services/questionServices');
|
||||
const { getQuestion } = require('server/utils/question');
|
||||
|
||||
async function GetQuestion(req, res) {
|
||||
const { question_id } = req.params;
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
const Question = require('server/db/models/Question');
|
||||
const User = require('server/db/models/User');
|
||||
const fetchData = require('server/utils/fetchData');
|
||||
|
||||
async function getAllData(_job, done, Model, url, id, dataName) {
|
||||
console.log('[INFO]: Refreshing question database.');
|
||||
const data = await fetchData(url, id, dataName);
|
||||
|
||||
if (!success) console.log(`[ERROR]: ${dataName} fetch failed`);
|
||||
|
||||
for (const item of data)
|
||||
await Model.findByIdAndUpdate(item[id], {
|
||||
...item,
|
||||
id: item[id],
|
||||
}, { upsert: true })
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
async function getAllQuestions(_job, done) {
|
||||
return getAllData(_job, done, Question, '/questions/search', 'question_id', 'questions')
|
||||
}
|
||||
async function getAllUsers(_job, done) {
|
||||
return getAllData(_job, done, User, '/users', 'user_id', 'users')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAllQuestions,
|
||||
getAllUsers
|
||||
};
|
||||
15
server/utils/cronRefresh.js
Normal file
15
server/utils/cronRefresh.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
const { getAllQuestions, getAllUsers } = require('./getData');
|
||||
|
||||
async function refreshQuestions(_job, done) {
|
||||
await getAllQuestions();
|
||||
done();
|
||||
}
|
||||
async function refreshUsers(_job, done) {
|
||||
await getAllUsers();
|
||||
done();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
refreshQuestions,
|
||||
refreshUsers
|
||||
}
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
const createRequest = require('./api');
|
||||
|
||||
const defaultAcc = [];
|
||||
|
||||
async function fetchData(
|
||||
url,
|
||||
id,
|
||||
dataName,
|
||||
acc = defaultAcc,
|
||||
acc = [],
|
||||
after = ''
|
||||
) {
|
||||
const { success, [dataName]: data } = await createRequest('get', url, { after });
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
const createRequest = require('./api');
|
||||
|
||||
const defaultAcc = [];
|
||||
|
||||
async function fetchQuestions(
|
||||
acc = defaultAcc,
|
||||
after = ''
|
||||
) {
|
||||
const { success, questions } = await createRequest('get', '/questions/search', { after });
|
||||
|
||||
if (!success || !questions.length) return acc;
|
||||
|
||||
const newAcc = [...acc, ...questions];
|
||||
const oldest = users[questions.length - 1];
|
||||
|
||||
return fetchQuestions(newAcc, oldest.question_id);
|
||||
}
|
||||
|
||||
module.exports = fetchQuestions;
|
||||
51
server/utils/getData.js
Normal file
51
server/utils/getData.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
const Answer = require('server/db/models/Answer');
|
||||
const Comment = require('server/db/models/Comment');
|
||||
const Mail = require('server/db/models/Mail');
|
||||
const Question = require('server/db/models/Question');
|
||||
const User = require('server/db/models/User');
|
||||
const fetchData = require('server/utils/fetchData');
|
||||
|
||||
async function getAllData(Model, url, id, dataName) {
|
||||
console.log(`[INFO]: Refreshing ${dataName} database.`);
|
||||
let data = await fetchData(url, id, dataName);
|
||||
data = data.map((item) => ({
|
||||
...item,
|
||||
id: item[id],
|
||||
}));
|
||||
for (const item of data)
|
||||
await Model.findByIdAndUpdate(item[id], item, { upsert: true });
|
||||
return data;
|
||||
}
|
||||
|
||||
async function getAllAnswers({ question_id, username }) {
|
||||
if (question_id)
|
||||
return getAllData(Answer, `/questions/${question_id}/answers`, 'answer_id', 'answers')
|
||||
else if (username)
|
||||
return getAllData(Answer, `/users/${username}/answers`, 'answer_id', 'answers')
|
||||
}
|
||||
|
||||
async function getAllComments({ question_id }) {
|
||||
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 getAllQuestions({ username }) {
|
||||
if (username)
|
||||
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')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAllAnswers,
|
||||
getAllComments,
|
||||
getAllQuestions,
|
||||
getAllUsers
|
||||
};
|
||||
Reference in a new issue