diff --git a/packages/component-email/.gitignore b/packages/component-email/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..3614a810088d89d9ccaa28d82401545634874a18 --- /dev/null +++ b/packages/component-email/.gitignore @@ -0,0 +1,8 @@ +_build/ +api/ +logs/ +node_modules/ +uploads/ +.env.* +.env +config/local*.* \ No newline at end of file diff --git a/packages/component-email/README.md b/packages/component-email/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/packages/component-email/index.js b/packages/component-email/index.js new file mode 100644 index 0000000000000000000000000000000000000000..aa3821894b376c9ce130bf477e3bcd843eb06f82 --- /dev/null +++ b/packages/component-email/index.js @@ -0,0 +1,5 @@ +module.exports = { + backend: () => app => { + require('./src/Emails')(app) + }, +} diff --git a/packages/component-email/package.json b/packages/component-email/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4081947842d0624718e44c8bc2fc21b6e091132b --- /dev/null +++ b/packages/component-email/package.json @@ -0,0 +1,37 @@ +{ + "name": "pubsweet-component-email", + "version": "0.0.1", + "description": "email component for faraday", + "license": "MIT", + "author": "Collaborative Knowledge Foundation", + "files": ["src"], + "main": "index.js", + "scripts": { + "test": "jest" + }, + "repository": { + "type": "git", + "url": "https://gitlab.coko.foundation/xpub/xpub-faraday", + "path": "component-user-manager" + }, + "dependencies": { + "body-parser": "^1.17.2", + "chance": "^1.0.13" + }, + "peerDependencies": { + "@pubsweet/logger": "^0.0.1", + "pubsweet-server": "^1.0.1", + "pubsweet-component-mail-service": "0.0.1" + }, + "devDependencies": { + "jest": "^22.1.1", + "supertest": "^3.0.0" + }, + "jest": { + "verbose": true, + "testRegex": "/src/.*.test.js$" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/component-email/src/Emails.js b/packages/component-email/src/Emails.js new file mode 100644 index 0000000000000000000000000000000000000000..d16e6458100839851d2e0a848199462eee5e3f5d --- /dev/null +++ b/packages/component-email/src/Emails.js @@ -0,0 +1,17 @@ +const bodyParser = require('body-parser') + +const CollectionsInvitations = app => { + app.use(bodyParser.json()) + const basePath = '/api/emails' + const routePath = './routes/emails' + const authBearer = app.locals.passport.authenticate('bearer', { + session: false, + }) + app.post( + basePath, + authBearer, + require(`${routePath}/post`)(app.locals.models), + ) +} + +module.exports = CollectionsInvitations diff --git a/packages/component-email/src/helpers/Email.js b/packages/component-email/src/helpers/Email.js new file mode 100644 index 0000000000000000000000000000000000000000..ed9fcd9c959c6585a30fbf4b2e3276792ff62b80 --- /dev/null +++ b/packages/component-email/src/helpers/Email.js @@ -0,0 +1,73 @@ +const mailService = require('pubsweet-component-mail-service') +const logger = require('@pubsweet/logger') +const helpers = require('./helpers') + +module.exports = { + setupAssignEmail: async (req, email, res, role) => { + const url = `${req.protocol}://${req.get('host')}` + let emailType + switch (role) { + case 'handlingEditor': + emailType = 'assign-handling-editor' + break + case 'author': + emailType = 'add-author' + break + default: + return res + .status(400) + .json({ error: `Role ${role} cannot be used with an assigned email` }) + } + try { + await mailService.setupAssignEmail(email, emailType, url) + return res.status(200).json({}) + } catch (e) { + logger.error(e) + return res.status(500).json({ error: 'Email could not be sent.' }) + } + }, + setupNewUserEmail: async (req, res, email, role, UserModel) => { + let user + try { + user = UserModel.findByEmail(email) + } catch (e) { + const notFoundError = await helpers.handleNotFoundError(e, 'user') + return res.status(notFoundError.status).json({ + error: notFoundError.message, + }) + } + if (user.passwordResetToken === undefined) { + return res + .status(400) + .json({ error: 'User does not have a password reset token' }) + } + const url = `${req.protocol}://${req.get('host')}` + let emailType + switch (role) { + case 'handlingEditor': + case 'editorInChief': + case 'admin': + emailType = 'invite' + break + case 'author': + emailType = 'invite-author' + break + default: + return res.status(400).json({ + error: `Role ${role} cannot be used with a password reset email`, + }) + } + try { + await mailService.setupInviteEmail( + email, + emailType, + user.passwordResetToken, + url, + ) + return res.status(200).json({}) + } catch (e) { + logger.error(e) + return res.status(500).json({ error: 'Email could not be sent.' }) + } + }, +} diff --git a/packages/component-email/src/helpers/helpers.js b/packages/component-email/src/helpers/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..4d77281d7bf6ff50381402709abb8f17f36a12cb --- /dev/null +++ b/packages/component-email/src/helpers/helpers.js @@ -0,0 +1,31 @@ +const logger = require('@pubsweet/logger') + +const checkForUndefinedParams = (...params) => { + if (params.includes(undefined)) { + return false + } + + return true +} + +const handleNotFoundError = async (error, item) => { + const response = { + success: false, + status: 500, + message: 'Something went wrong', + } + if (error.name === 'NotFoundError') { + logger.error(`invalid ${item} id`) + response.status = 404 + response.message = `${item} not found` + return response + } + + logger.error(error) + return response +} + +module.exports = { + checkForUndefinedParams, + handleNotFoundError, +} diff --git a/packages/component-email/src/routes/emails/post.js b/packages/component-email/src/routes/emails/post.js new file mode 100644 index 0000000000000000000000000000000000000000..435a8c312cca22bfc698e157fd04f03947092977 --- /dev/null +++ b/packages/component-email/src/routes/emails/post.js @@ -0,0 +1,23 @@ +const logger = require('@pubsweet/logger') +const helpers = require('../../helpers/helpers') +const emailHelper = require('../../helpers/Email') + +module.exports = models => async (req, res) => { + const { email, type, role } = req.body + if (!helpers.checkForUndefinedParams(email, type, role)) { + res.status(400).json({ error: 'Email and type are required' }) + logger.error('User ID and role are missing') + return + } + + switch (type) { + case 'invite': + return emailHelper.setupNewUserEmail(req, res, email, role, models.User) + case 'assign': + return emailHelper.setupAssignEmail(req, email, res, role) + default: + return res + .status(400) + .json({ error: `Email type ${type} is not defined` }) + } +}