Skip to content

Commit

Permalink
Merge pull request #154 from codeforsanjose/mtw812-fixes
Browse files Browse the repository at this point in the history
#120 super admin
  • Loading branch information
JMStudiosJoe authored Aug 1, 2021
2 parents 47b7ab2 + facd827 commit 6dc43b9
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 52 deletions.
53 changes: 30 additions & 23 deletions backend/middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
};
13 changes: 12 additions & 1 deletion backend/models/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
79 changes: 79 additions & 0 deletions backend/routes/admins.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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":["[email protected]", "[email protected]"]}
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":"[email protected]", "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;
77 changes: 49 additions & 28 deletions backend/routes/questionnaireResponses.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,68 @@ const sendMassEmails = require('./sendEmail/sendEmail');
const ObjectID = require('mongodb').ObjectID;
const emailContents = require('../routes/sendEmail/emailContent.js');
const senderEmail = process.env.SENDER_EMAIL;

//TODO: revisit access control
router.route('/add').post((req, res) => {
const title = req.body.title;
const language = req.body.language;
const questionnaireResponse = req.body.questionnaireResponse;
const newQuestionnaireResponse = new QuestionnaireResponse({
title,
language,
questionnaireResponse,
});

newQuestionnaireResponse
.save()
.then(() => {
res.json('QuestionnaireResponse response added');
})
.catch((err) => console.log(err));
});

const auth = require('../middleware/auth');
router.use(auth); //all apis AFTER this line will require authentication as implemented in auth.js

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 }
]});
};

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) => {
Expand Down Expand Up @@ -199,24 +238,6 @@ router.route('/:id').get((req, res) => {
.catch((err) => console.log(err));
});

router.route('/add').post((req, res) => {
const title = req.body.title;
const language = req.body.language;
const questionnaireResponse = req.body.questionnaireResponse;
const newQuestionnaireResponse = new QuestionnaireResponse({
title,
language,
questionnaireResponse,
});

newQuestionnaireResponse
.save()
.then(() => {
res.json('QuestionnaireResponse response added');
})
.catch((err) => console.log(err));
});

router.route('/:id').delete((req, res) => {
QuestionnaireResponse.findByIdAndDelete(req.params.id)
.then((users) => res.json('questionnaire response Deleted'))
Expand Down

0 comments on commit 6dc43b9

Please sign in to comment.