diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js index db3b6466..1c45810d 100644 --- a/backend/middleware/auth.js +++ b/backend/middleware/auth.js @@ -5,29 +5,36 @@ const ERRMSG = { error: { message: 'Not logged in or auth failed' } }; //route for authentication with client's jwt module.exports = (req, res, next) => { - try { - let token = req.get('Authorization').split(' ')[1]; - let decodedToken = jwt.decode(token); - if (decodedToken) { - let email = decodedToken.email; - Admin.findOne({ email: email }) - .exec() - .then((admin) => { - if (!admin) return res.status(404).json(ERRMSG); - else { - let adminObj = JSON.parse(JSON.stringify(admin)); - delete adminObj.password; - return adminObj; - } - }) - .then((body) => { - req.user = body; - next(); - }); - } else { - return res.status(401).json(ERRMSG); - } - } catch { + let token = ''; + if (req.header && req.header('Authorization')) { + token = req.header('Authorization').split(' ')[1]; + } + if (token) { + jwt.verify(token, process.env.JWT_KEY, function (err, decodedToken) { + if (err) { + return res.status(401).json(ERRMSG); + } + if (decodedToken) { + let email = decodedToken.email; + Admin.findOne({ email: email }) + .exec() + .then((admin) => { + if (!admin) return res.status(404).json(ERRMSG); + else { + let adminObj = JSON.parse(JSON.stringify(admin)); + delete adminObj.password; + return adminObj; + } + }) + .then((body) => { + req.user = body; + next(); + }); + } else { + return res.status(401).json(ERRMSG); + } + }); + } else { return res.status(401).json(ERRMSG); } }; diff --git a/backend/models/admin.js b/backend/models/admin.js index d3ee9089..34541d94 100644 --- a/backend/models/admin.js +++ b/backend/models/admin.js @@ -14,7 +14,18 @@ const adminSchema = new Schema({ type: String, required: true, }, - password: { type: String, required: true }, + password: { + type: String, + required: true + }, + issuper: { + type: Boolean, + required: false, + }, + questionnaires: { //list of questionnaires.title + type: [String], + required: false, + }, }); const Admin = mongoose.model('Admin', adminSchema); diff --git a/backend/routes/admins.js b/backend/routes/admins.js index 3ff63174..b0d85340 100644 --- a/backend/routes/admins.js +++ b/backend/routes/admins.js @@ -12,6 +12,8 @@ const SALT_ROUNDS = 10; const ERRMSG = { error: { message: 'Not logged in or auth failed' } }; const EMAIL_REGEX = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; +const auth = require('../middleware/auth'); + router.route('/').get((req, res) => { Admin.find() .then((admins) => { @@ -225,6 +227,83 @@ router.route('/translateContent').post((req, res) => { } }); +router.use(auth); //all apis AFTER this line will require authentication as implemented in auth.js + +//set one or more admins to be super admins: +//request body looks like the following: +// {"admins":["abcde@gmail.com", "xyz@123.org"]} +router.route('/super').post((req, res) => { + if (!req.body || !req.body.admins) { + return res.status(400) + .json('Admin identifiers not found'); + } + Admin.updateMany({email: {'$in': req.body.admins}}, + {issuper: true}) + .exec() + .then((result) => { + return res.status(200).json('Admins to super status - '+result.n+' selected, '+result.nModified+' updated'); + }) + .catch((err) => { + console.log(req.body, err); + return res.status(500).json('Error updating super admin status'); + }); +}); + +//link questionnaires to admin identified by email +const updateLinks = (email, titles, insert=true) => { + return Admin.findOne({email: email}) + .exec() + .then((admin) => { + if (admin) { + if (insert) { + titles.forEach((title) => { + if (!admin.questionnaires.includes(title)) {//don't add duplicates + admin.questionnaires.push(title); + } + }); + } else { + admin.questionnaires = admin.questionnaires.filter(title => !titles.includes(title)); + } + admin.save() + .then((admin) => { + console.log('Success updating admin and questionnaires links - ', admin.email); + }) + .catch((err) => { + console.log('Error updating admin and questionnaires links', err); + }); + } + }) + .catch((err) => { + console.log(err); + }); +} + +const updateQuestionnairesLinks = (req, res, insert=true) => { + if (!req.body || !req.body.links) { + return res.status(400) + .json('Admins and questionnaires links not found in the request'); + } + const linkPromises = req.body.links.map((link, idx) => { + return updateLinks(link.admin, link.questionnaires, insert); + }); + Promise.all(linkPromises).then((links) => { + return res.status(200) + .json('Admin and questionnaires links are updated'); + }) +} + +//link admin(s) with corresponding questionnaires (by 'title' since it's the unique id) +//request body looks like the following: +// {"links": [{"admin":"abc@gmail.com", "questionnaires":["CIIT_Workshop_Spring_2021"]}]}" +router.route('/questionnaires/link').post((req, res) => { + updateQuestionnairesLinks(req, res, true); +}); + +//unlink admin(s) with corresponding questionnaires +router.route('/questionnaires/unlink').post((req, res) => { + updateQuestionnairesLinks(req, res, false); +}); + router.route(''); module.exports = router; diff --git a/backend/routes/questionnaireResponses.js b/backend/routes/questionnaireResponses.js index 52d209c6..744f787a 100644 --- a/backend/routes/questionnaireResponses.js +++ b/backend/routes/questionnaireResponses.js @@ -6,29 +6,49 @@ const sendMassEmails = require('./sendEmail/sendEmail'); const ObjectID = require('mongodb').ObjectID; const emailContents = require('../routes/sendEmail/emailContent.js'); const senderEmail = process.env.SENDER_EMAIL; + const getAllResponses = () => { return QuestionnaireResponse.find({ $or: [ { deleted: { $exists: false} }, { deleted: false } - ]}); - }; + ]}); +}; + +const getResponsesForAdmin = (admin) => { + return QuestionnaireResponse.find({ + title: { $in: admin.questionnaires }, + $or: [ + { deleted: { $exists: false} }, + { deleted: false } + ]}); +}; + +const auth = require('../middleware/auth'); +router.use(auth); //all apis AFTER this line will require authentication as implemented in auth.js + router.route('/').get((req, res) => { - getAllResponses() - .then((allResponses) => { - const responsesInfo = { responses: allResponses }; - res.json(responsesInfo); - }) - .catch((err) => console.log(err)); + const getResponses = req.user.issuper ? getAllResponses(): getResponsesForAdmin(req.user); + + getResponses + .then((qResponses) => { + const responsesInfo = { responses: qResponses }; + res.json(responsesInfo); + }) + .catch((err) => console.log(err)) }); + // source https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript function validateEmail(email) { const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(String(email).toLowerCase()); } + router.route('/email').post((req, res) => { - getAllResponses().then((allResponses) => { - const responsesToEmail = allResponses.filter((item) => !item.emailSent); + const getResponses = req.user.issuper ? getAllResponses(): getResponsesForAdmin(req.user); + + getResponses.then((qResponses) => { + const responsesToEmail = qResponses.filter((item) => !item.emailSent); const totalEmailsToSend = responsesToEmail.length; const messsagesToSend = responsesToEmail .filter((response) => { @@ -199,6 +219,7 @@ router.route('/:id').get((req, res) => { .catch((err) => console.log(err)); }); +//TODO: move to before router.use(auth)? router.route('/add').post((req, res) => { const title = req.body.title; const language = req.body.language;