Merge branch 'c4' into dev
This commit is contained in:
commit
55514b408b
17 changed files with 224 additions and 40 deletions
64
server/badges.json
Normal file
64
server/badges.json
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"badges": [
|
||||
{
|
||||
"title": "Great Question",
|
||||
"text": "Have a question with net total points of >100",
|
||||
"rank": "Gold"
|
||||
},
|
||||
{
|
||||
"title": "Good Question",
|
||||
"text": "Have a question with net total points of >25",
|
||||
"rank": "Silver"
|
||||
},
|
||||
{
|
||||
"title": "Nice Question",
|
||||
"text": "Have a question with net total points of >10",
|
||||
"rank": "Bronze"
|
||||
},
|
||||
{
|
||||
"title": "Great Answer",
|
||||
"text": "Have a answer with net total points of >100",
|
||||
"rank": "Gold"
|
||||
},
|
||||
{
|
||||
"title": "Good Answer",
|
||||
"text": "Have a answer with net total points of >25",
|
||||
"rank": "Silver"
|
||||
},
|
||||
{
|
||||
"title": "Nice Answer",
|
||||
"text": "Have a answer with net total points of >10",
|
||||
"rank": "Bronze"
|
||||
},
|
||||
{
|
||||
"title": "Socratic",
|
||||
"text": "Have at least 10000 points",
|
||||
"rank": "Gold"
|
||||
},
|
||||
{
|
||||
"title": "Inquisitive",
|
||||
"text": "Have at least 3000 points",
|
||||
"rank": "Silver"
|
||||
},
|
||||
{
|
||||
"title": "Curious",
|
||||
"text": "Have at least 100 points",
|
||||
"rank": "Bronze"
|
||||
},
|
||||
{
|
||||
"title": "Zombie",
|
||||
"text": "Have a question that is reopened",
|
||||
"rank": "Gold"
|
||||
},
|
||||
{
|
||||
"title": "Protected",
|
||||
"text": "Have a question that is protected",
|
||||
"rank": "Silver"
|
||||
},
|
||||
{
|
||||
"title": "Scholar",
|
||||
"text": "Accept an answer",
|
||||
"rank": "Bronze"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
const mongoose = require('mongoose');
|
||||
const calculateAnswerBadges = require('../../utils/badges/answerBadges');
|
||||
const User = require('./User');
|
||||
|
||||
const Answer = mongoose.Schema(
|
||||
{
|
||||
|
|
@ -15,4 +17,10 @@ const Answer = mongoose.Schema(
|
|||
{ timestamps: { createdAt: false, updatedAt: true } }
|
||||
);
|
||||
|
||||
Answer.post('findOneAndUpdate', (doc) => {
|
||||
const badges = calculateAnswerBadges(doc.points);
|
||||
|
||||
User.findOneAndUpdate({ username: doc.creator }, { $addToSet: { tags: { $each: badges } } });
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Answer', Answer);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,9 @@
|
|||
const mongoose = require('mongoose');
|
||||
|
||||
const Answer = mongoose.Schema(
|
||||
{
|
||||
question_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Question' },
|
||||
answer_id: { type: String, required: true },
|
||||
creator: { type: String, required: true },
|
||||
text: { type: String, required: true },
|
||||
upvotes: { type: Number, required: true, default: 0 },
|
||||
downvotes: { type: Number, required: true, default: 0 },
|
||||
accepted: { type: Boolean, required: true, default: false },
|
||||
createdAt: { type: Date, required: true },
|
||||
lastCommentFetch: { type: Date, default: new Date(0) },
|
||||
},
|
||||
{ timestamps: { createdAt: false, updatedAt: true } }
|
||||
);
|
||||
const Badge = mongoose.Schema({
|
||||
title: { type: String, required: true },
|
||||
text: { type: String, required: true },
|
||||
rank: { type: String, required: true, enum: ['Gold', 'Silver', 'Bronze'] },
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Answer', Answer);
|
||||
module.exports = mongoose.model('Badge', Badge);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
const mongoose = require('mongoose');
|
||||
const calculateQuestionBadges = require('../../utils/badges/questionBadges');
|
||||
const User = require('./User');
|
||||
|
||||
const Question = mongoose.Schema(
|
||||
{
|
||||
|
|
@ -27,4 +29,10 @@ const Question = mongoose.Schema(
|
|||
{ timestamps: { createdAt: false, updatedAt: true } }
|
||||
);
|
||||
|
||||
Question.post('findOneAndUpdate', (doc) => {
|
||||
const badges = calculateQuestionBadges(doc.points);
|
||||
|
||||
User.findOneAndUpdate({ username: doc.creator }, { $addToSet: { tags: { $each: badges } } });
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Question', Question);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const mongoose = require('mongoose');
|
||||
const calculateUserBadges = require('server/utils/badges/userBadges');
|
||||
|
||||
const User = mongoose.Schema(
|
||||
{
|
||||
|
|
@ -9,8 +10,21 @@ const User = mongoose.Schema(
|
|||
lastMailFetch: { type: Date, default: new Date(0) },
|
||||
lastAnswerFetch: { type: Date, default: new Date(0) },
|
||||
user_id: { type: String, required: true, unique: true },
|
||||
badges: [String],
|
||||
},
|
||||
{ timestamps: { createdAt: false, updatedAt: true } }
|
||||
);
|
||||
|
||||
User.post('findOneAndUpdate', async (doc) => {
|
||||
const badges = calculateUserBadges(doc.points);
|
||||
|
||||
console.log(`first: ${doc.badges}`);
|
||||
|
||||
doc.badges = [...new Set([...doc.badges, ...badges])];
|
||||
|
||||
console.log(doc.badges);
|
||||
|
||||
doc.save();
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('User', User);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ const ReadMail = require('./mail/Read');
|
|||
|
||||
router.get('/', tokenAuth, GetMail);
|
||||
router.post('/', tokenAuth, SendMail);
|
||||
router.patch('/', tokenAuth, ReadMail);
|
||||
router.patch('/:mail_id', tokenAuth, ReadMail);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ const Mail = require('server/db/models/Mail');
|
|||
const config = require('server/config.json');
|
||||
|
||||
async function Read(req, res) {
|
||||
const { id } = req.body;
|
||||
const { mail_id } = req.params;
|
||||
|
||||
const cachedMail = await Mail.findByIdAndUpdate(id, { read: true });
|
||||
const cachedMail = await Mail.findByIdAndUpdate(mail_id, { read: true });
|
||||
|
||||
return cachedMail ? res.sendStatus(200) : res.status(404).send(config.errorNotFound);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,14 @@ const createRequest = require('server/utils/api');
|
|||
|
||||
async function CreateQuestion(req, res) {
|
||||
const user = req.user;
|
||||
const { title, text } = req.body;
|
||||
const { title, text, tags } = req.body;
|
||||
|
||||
if (!title || !text) return res.status(400).send(config.errorIncomplete);
|
||||
|
||||
if (tags && tags.length > 5) {
|
||||
return res.status(400).send(config.errorIncomplete);
|
||||
}
|
||||
|
||||
const { success, question } = await createRequest('post', `/questions`, {
|
||||
creator: user.username,
|
||||
title,
|
||||
|
|
@ -17,7 +21,7 @@ async function CreateQuestion(req, res) {
|
|||
|
||||
if (!success) return res.status(500).send(config.errorGeneric);
|
||||
|
||||
const newQuestion = await Question.create({ ...question, _id: question.question_id });
|
||||
const newQuestion = await Question.create({ ...question, tags, _id: question.question_id });
|
||||
|
||||
// Increment user points by 1
|
||||
await createRequest('patch', `/users/${user.username}/points`, {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ async function EditAnswerAccepted(req, res) {
|
|||
if (!question) return res.status(404).send(config.errorNotFound);
|
||||
const {hasBounty} = question;
|
||||
// Verify user owns question and question does not already have an accepted answer
|
||||
if (question.creator !== user.username || question.hasAccepted)
|
||||
if (question.creator !== user.username || question.hasAccepted) {
|
||||
return res.status(403).send(config.errorForbidden);
|
||||
}
|
||||
|
||||
// Patch question with BDPA server
|
||||
const patchAnswer = await createRequest(
|
||||
|
|
|
|||
|
|
@ -18,10 +18,7 @@ async function EditQuestionStatusProtected(req, res) {
|
|||
if (!question) return res.status(404).send(config.errorNotFound);
|
||||
|
||||
// Verify question does not have incompatible status
|
||||
if (
|
||||
question.status === 'closed' ||
|
||||
question.status === 'protected'
|
||||
) {
|
||||
if (question.status === 'closed' || question.status === 'protected') {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
error: 'This question is already closed or protected.',
|
||||
|
|
@ -48,11 +45,11 @@ async function EditQuestionStatusProtected(req, res) {
|
|||
status: 'protected',
|
||||
});
|
||||
|
||||
const { success } = await createRequest(
|
||||
'patch',
|
||||
`/questions/${question_id}`,
|
||||
{ status: 'protected' }
|
||||
);
|
||||
await User.findOneAndUpdate({ username: creator }, { $push: { badges: 'Protected' } });
|
||||
|
||||
const { success } = await createRequest('patch', `/questions/${question_id}`, {
|
||||
status: 'protected',
|
||||
});
|
||||
await Question.findByIdAndUpdate(question_id, { status: 'protected' });
|
||||
|
||||
return success
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const config = require('server/config.json');
|
||||
const Question = require('server/db/models/Question');
|
||||
const { getQuestion, refreshQuestion } = require('server/utils/question');
|
||||
const { getQuestion } = require('server/utils/question');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
const createRequest = require('server/utils/api');
|
||||
|
||||
|
|
@ -18,10 +18,7 @@ async function EditQuestionStatusReopened(req, res) {
|
|||
if (!question) return res.status(404).send(config.errorNotFound);
|
||||
|
||||
// Make sure that question has compatible status
|
||||
if (
|
||||
question.status === 'protected' ||
|
||||
question.status === 'open'
|
||||
) {
|
||||
if (question.status === 'protected' || question.status === 'open') {
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
error: 'This question is already open.',
|
||||
|
|
@ -48,11 +45,11 @@ async function EditQuestionStatusReopened(req, res) {
|
|||
status: 'open',
|
||||
});
|
||||
|
||||
const { success } = await createRequest(
|
||||
'patch',
|
||||
`/questions/${question_id}`,
|
||||
{ status: 'open' }
|
||||
);
|
||||
await User.findOneAndUpdate({ username: creator }, { $push: { badges: 'Zombie' } });
|
||||
|
||||
const { success } = await createRequest('patch', `/questions/${question_id}`, {
|
||||
status: 'open',
|
||||
});
|
||||
await Question.findByIdAndUpdate(question_id, { status: 'open' });
|
||||
|
||||
return success
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const basicAuth = require('server/middleware/basicAuth');
|
|||
const tokenAuth = require('server/middleware/tokenAuth');
|
||||
|
||||
const Answers = require('./user/Answers');
|
||||
const GetBadges = require('./user/GetBadges');
|
||||
const Delete = require('./user/Delete');
|
||||
const Edit = require('./user/Edit');
|
||||
const GetUser = require('./user/GetUser');
|
||||
|
|
@ -20,6 +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.post('/login', basicAuth, Login);
|
||||
router.get('/remember', tokenAuth, Remember);
|
||||
router.delete('/logout', tokenAuth, Logout);
|
||||
|
|
|
|||
24
server/routes/user/GetBadges.js
Normal file
24
server/routes/user/GetBadges.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const Badge = require('server/db/models/Badge');
|
||||
|
||||
async function GetBadges(req, res) {
|
||||
const { user } = req;
|
||||
|
||||
const badges = await Badge.find();
|
||||
|
||||
const response = badges.reduce(
|
||||
(acc, badge) => {
|
||||
if (user.badges.includes(badge.title)) {
|
||||
acc.obtained.append(badge);
|
||||
} else {
|
||||
acc.unobtained.append(badge);
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{ obtained: [], unobtained: [] }
|
||||
);
|
||||
|
||||
return res.send(response);
|
||||
}
|
||||
|
||||
module.exports = GetBadges;
|
||||
|
|
@ -2,6 +2,7 @@ const createRequest = require('server/utils/api');
|
|||
const config = require('server/config.json');
|
||||
const User = require('server/db/models/User');
|
||||
const getUserLevel = require('server/utils/getUserLevel');
|
||||
const Badge = require('server/db/models/Badge');
|
||||
|
||||
async function GetUser(req, res) {
|
||||
const { username } = req.params;
|
||||
|
|
@ -27,6 +28,27 @@ async function GetUser(req, res) {
|
|||
new: true,
|
||||
});
|
||||
|
||||
const badges = await Badge.find({ title: { $in: user.badges } });
|
||||
|
||||
const badgeCount = badges.reduce(
|
||||
(acc, badge) => {
|
||||
if (badge.rank === 'Gold') {
|
||||
acc.gold = acc.gold++;
|
||||
} else if (badge.rank === 'Silver') {
|
||||
acc.silver = acc.silver++;
|
||||
} else if (badge.rank === 'Bronze') {
|
||||
acc.bronze = acc.bronze++;
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
gold: 0,
|
||||
silver: 0,
|
||||
bronze: 0,
|
||||
}
|
||||
);
|
||||
|
||||
return res.send({
|
||||
user: {
|
||||
username: newUser.username,
|
||||
|
|
@ -34,6 +56,7 @@ async function GetUser(req, res) {
|
|||
points: newUser.points,
|
||||
level: getUserLevel(newUser.points),
|
||||
},
|
||||
badgeCount,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
17
server/utils/badges/answerBadges.js
Normal file
17
server/utils/badges/answerBadges.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
function calculateAnswerBadges(points) {
|
||||
let badges = [];
|
||||
|
||||
if (points >= 100) {
|
||||
badges.push('Great Answer');
|
||||
}
|
||||
if (points >= 25) {
|
||||
badges.push('Good Answer');
|
||||
}
|
||||
if (points >= 10) {
|
||||
badges.push('Nice Answer');
|
||||
}
|
||||
|
||||
return badges;
|
||||
}
|
||||
|
||||
module.exports = calculateAnswerBadges;
|
||||
17
server/utils/badges/questionBadges.js
Normal file
17
server/utils/badges/questionBadges.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
function calculateQuestionBadges(points) {
|
||||
let badges = [];
|
||||
|
||||
if (points >= 100) {
|
||||
badges.push('Great Question');
|
||||
}
|
||||
if (points >= 25) {
|
||||
badges.push('Good Question');
|
||||
}
|
||||
if (points >= 10) {
|
||||
badges.push('Nice Question');
|
||||
}
|
||||
|
||||
return badges;
|
||||
}
|
||||
|
||||
module.exports = calculateQuestionBadges;
|
||||
17
server/utils/badges/userBadges.js
Normal file
17
server/utils/badges/userBadges.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
function calculateUserBadges(points) {
|
||||
let badges = [];
|
||||
|
||||
if (points >= 10000) {
|
||||
badges.push('Socratic');
|
||||
}
|
||||
if (points >= 3000) {
|
||||
badges.push('Inquisitive');
|
||||
}
|
||||
if (points >= 100) {
|
||||
badges.push('Curious');
|
||||
}
|
||||
|
||||
return badges;
|
||||
}
|
||||
|
||||
module.exports = calculateUserBadges;
|
||||
Reference in a new issue