Skip to content
Snippets Groups Projects
Commit 219679ee authored by Alexandru Munteanu's avatar Alexandru Munteanu
Browse files

Merge branch 'faraday-master' of gitlab.coko.foundation:xpub/xpub into faraday-master

parents bb5c9b33 8e665cd3
No related branches found
No related tags found
No related merge requests found
Showing
with 436 additions and 663 deletions
_build/
api/
logs/
node_modules/
uploads/
.env.*
.env
config/local*.*
\ No newline at end of file
# AWS S3 File Upload
In order to use `component-xpub-aws-s3` you first need to have a `.env` file containing AWS data in the root folder of the starting point of your applications.
The `.env` file should look like this:
```bash
AWS_ACCESS_KEY = exampleKey
AWS_SECRET_KEY = exampleKey/sads/21
AWS_REGION = region-name
AWS_BUCKET = bucket-name
```
Then, as soon as possible in your app you should add the `dotenv` package:
```js
require('dotenv').config()
```
# `component-xpub-aws-s3` API
A list of endpoints that help you upload, download and delete S3 files.
## Upload a file [POST]
#### Request
`POST /api/file`
#### Request body
```
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryWfPNVh4wuWBlyEyQ
------WebKitFormBoundaryWfPNVh4wuWBlyEyQ
Content-Disposition: form-data; name="fileType"
supplementary
------WebKitFormBoundaryWfPNVh4wuWBlyEyQ
Content-Disposition: form-data; name="fragmentId"
545
------WebKitFormBoundaryWfPNVh4wuWBlyEyQ
Content-Disposition: form-data; name="file"; filename="attachment.txt"
Content-Type: text/plain
[file content goes there]
------WebKitFormBoundaryWfPNVh4wuWBlyEyQ
```
#### Response
```json
{
"id": "fragment-id/file-id",
"name": "Document Name.doc",
"size": 452097
}
```
## Retrieve file signed URL [GET]
This endpoint allows you to retrieve a file's signed URL that can be used to download the file.
#### Request
`GET /api/file/{fileId}`
| URI Parameter | Requiered | Requirements | Description |
| -------- | -------- | -------- | -------- |
| fileId | Yes | String | The ID of the file |
#### Response
```json
HTTP/1.1 200
{
"signedUrl": "aws-url"
}
```
## Delete file [DELETE]
#### Request
`DELETE /api/file/{fileId}`
| URI Parameter | Requiered | Requirements | Description |
| -------- | -------- | -------- | -------- |
| fileId | Yes | String | The ID of the file |
#### Response
```json
HTTP/1.1 204
```
---
const path = require('path')
module.exports = {
'pubsweet-component-aws-s3': {
validations: path.resolve(__dirname, './upload-validations-test'),
},
}
const Joi = require('joi')
module.exports = {
manuscripts: Joi.any()
.valid([
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
'application/msword',
])
.error(new Error('Only Word documents and PDFs are allowed')),
supplementary: Joi.any(),
coverLetter: Joi.any()
.valid([
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
'application/msword',
])
.error(new Error('Only Word documents and PDFs are allowed')),
}
require('dotenv').config()
module.exports = {
backend: () => app => require('./src/FileBackend')(app),
}
{
"name": "pubsweet-components-aws-s3",
"version": "0.0.1",
"description": "xpub aws s3 configured for faraday",
"license": "MIT",
"files": [
"src"
],
"scripts": {
"test": "jest"
},
"repository": {
"type": "git",
"url": "https://gitlab.coko.foundation/xpub/xpub"
},
"dependencies": {
"aws-sdk": "^2.185.0",
"body-parser": "^1.17.2",
"multer": "^1.3.0",
"multer-s3": "^2.7.0",
"node-mocks-http": "^1.6.6",
"nodemailer": "^4.4.2"
},
"peerDependencies": {
"@pubsweet/logger": "^0.0.1",
"pubsweet": "^1.1.1",
"pubsweet-client": "^1.1.1",
"pubsweet-server": "^1.0.1"
},
"devDependencies": {
"jest": "^22.1.1",
"supertest": "^3.0.0"
}
}
const AWS = require('aws-sdk')
const logger = require('@pubsweet/logger')
const config = require('config')
const _ = require('lodash')
const s3Config = _.get(config, 'pubsweet-component-aws-s3')
const FileBackend = app => {
const authBearer = app.locals.passport.authenticate('bearer', {
session: false,
})
AWS.config.update({
secretAccessKey: s3Config.secretAccessKey,
accessKeyId: s3Config.accessKeyId,
region: s3Config.region,
})
const s3 = new AWS.S3()
const upload = require('./middeware/upload').setupMulter(s3)
app.post(
'/api/file',
authBearer,
upload.single('file'),
require('./routeHandlers/postFile'),
)
app.get('/api/file/:fragmentId/:fileId', authBearer, async (req, res) => {
const params = {
Bucket: s3Config.bucket,
Key: `${req.params.fragmentId}/${req.params.fileId}`,
}
s3.getSignedUrl('getObject', params, (err, data) => {
if (err) {
res.status(err.statusCode).json({ error: err.message })
logger.error(err.message)
return
}
res.status(200).json({
signedUrl: data,
})
})
})
app.delete('/api/file/:fragmentId/:fileId', authBearer, async (req, res) => {
const params = {
Bucket: s3Config.bucket,
Key: `${req.params.fragmentId}/${req.params.fileId}`,
}
s3.deleteObject(params, (err, data) => {
if (err) {
res.status(err.statusCode).json({ error: err.message })
logger.error(err.message)
return
}
res.status(204).json()
})
})
}
module.exports = FileBackend
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
process.env.SUPPRESS_NO_CONFIG_WARNING = true
const httpMocks = require('node-mocks-http')
describe('ValidateFile for multer fileFilter', () => {
it('should return TRUE when fileType is supplementary', () => {
const validateFile = require('./middeware/upload').validateFile(
...buildValidateFileParams('supplementary', 'image/png'),
)
expect(validateFile).toBe(true)
})
it('should return TRUE when fileType is manuscripts or coverLetter and the file is either Word Doc or PDF', () => {
const randFileType = getRandValueFromArray(['manuscripts', 'coverLetter'])
const randMimeType = getRandValueFromArray([
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
])
const validateFile = require('./middeware/upload').validateFile(
...buildValidateFileParams(randFileType, randMimeType),
)
expect(validateFile).toBe(true)
})
it('should return FALSE when fileType is manuscripts or coverLetter and the file is neither Word Doc or PDF', () => {
const randFileType = getRandValueFromArray(['manuscripts', 'coverLetter'])
const randMimeType = getRandValueFromArray([
'text/plain',
'text/html',
'image/jpeg',
'image/png',
])
const validateFile = require('./middeware/upload').validateFile(
...buildValidateFileParams(randFileType, randMimeType),
)
expect(validateFile).toBe(false)
})
})
describe('Upload file route handler', () => {
it('should return success when the file passed validation', async () => {
const file = {
key: '123abc',
originalname: 'file.txt',
size: 128,
}
const req = httpMocks.createRequest({
file,
})
const res = httpMocks.createResponse()
await require('./routeHandlers/postFile')(req, res)
expect(res.statusCode).toBe(200)
const data = JSON.parse(res._getData())
expect(data.id).toEqual(file.key)
expect(data.name).toEqual(file.originalname)
expect(data.size).toEqual(file.size)
})
it('should return an error when the file failed validation', async () => {
const req = httpMocks.createRequest({
fileValidationError: 'Only Word documents and PDFs are allowed',
})
const res = httpMocks.createResponse()
await require('./routeHandlers/postFile')(req, res)
expect(res.statusCode).toBe(400)
const data = JSON.parse(res._getData())
expect(data.error).toEqual(req.fileValidationError)
})
})
const getRandValueFromArray = arr => arr[Math.floor(Math.random() * arr.length)]
const buildValidateFileParams = (fileType, mimetype) => {
const req = {
body: {
fileType,
},
}
const file = {
mimetype,
}
const cb = (p1, p2) => {
if (p2 === true) return true
return false
}
return [req, file, cb]
}
const multer = require('multer')
const multerS3 = require('multer-s3')
const uuid = require('uuid')
const Joi = require('joi')
const _ = require('lodash')
const config = require('config')
const s3Config = _.get(config, 'pubsweet-component-aws-s3')
const uploadValidations = require(s3Config.validations)
const setupMulter = s3 => {
const upload = multer({
storage: multerS3({
s3,
bucket: s3Config.bucket,
contentType: (req, file, cb) => {
cb(null, file.mimetype)
},
key: (req, file, cb) => {
const fileKey = `${req.body.fragmentId}/${uuid.v4()}`
cb(null, fileKey)
},
}),
fileFilter: (req, file, cb) => validateFile(req, file, cb),
})
return upload
}
const validateFile = (req, file, cb) => {
const { fileType } = req.body
const { mimetype } = file
const valid = Joi.validate({ [fileType]: mimetype }, uploadValidations)
if (valid.error) {
req.fileValidationError = valid.error.message
return cb(null, false)
}
return cb(null, true)
}
module.exports = {
setupMulter,
validateFile,
}
const logger = require('@pubsweet/logger')
module.exports = async (req, res) => {
if (req.fileValidationError !== undefined) {
logger.error(req.fileValidationError)
return res.status(400).json({ error: req.fileValidationError })
}
logger.debug(`${req.file.originalname} has been uploaded`)
res.status(200).json({
id: req.file.key,
name: req.file.originalname,
size: req.file.size,
})
}
const nodemailer = require('nodemailer')
const AWS = require('aws-sdk')
const config = require('config')
const _ = require('lodash')
const logger = require('@pubsweet/logger')
const AWS = require('aws-sdk')
const sesConfig = _.get(config, 'pubsweet-component-aws-ses')
const mailerConfig = config.get('mailer')
module.exports = {
sendEmail: (toEmail, subject, textBody, htmlBody) => {
AWS.config.update({
secretAccessKey: sesConfig.secretAccessKey,
accessKeyId: sesConfig.accessKeyId,
region: sesConfig.region,
})
const transporter = nodemailer.createTransport({
SES: new AWS.SES(),
SES: new AWS.SES({
secretAccessKey: process.env.AWS_SES_SECRET_KEY,
accessKeyId: process.env.AWS_SES_ACCESS_KEY,
region: process.env.AWS_SES_REGION,
}),
})
transporter.sendMail(
{
from: sesConfig.sender,
from: mailerConfig.from,
to: toEmail,
subject,
text: textBody,
......
module.exports = {
mailer: {
from: 'test@example.com',
},
'invite-reset-password': {
url:
process.env.PUBSWEET_INVITE_PASSWORD_RESET_URL ||
'http://localhost:3000/invite',
},
roles: {
global: ['admin', 'editorInChief', 'author'],
collection: ['handlingEditor', 'reviewer'],
inviteRights: {
admin: ['admin', 'editorInChief', 'author'],
editorInChief: ['handlingEditor'],
handlingEditor: ['reviewer'],
},
},
}
......@@ -6,12 +6,17 @@
"files": [
"src"
],
"scripts": {
"test": "jest"
},
"repository": {
"type": "git",
"url": "https://gitlab.coko.foundation/xpub/xpub"
"url": "https://gitlab.coko.foundation/xpub/xpub",
"path": "component-invite"
},
"dependencies": {
"body-parser": "^1.17.2"
"body-parser": "^1.17.2",
"chance": "^1.0.13"
},
"peerDependencies": {
"@pubsweet/logger": "^0.0.1",
......@@ -22,5 +27,17 @@
"devDependencies": {
"jest": "^22.1.1",
"supertest": "^3.0.0"
},
"jest": {
"moduleNameMapper": {
"\\.s?css$": "identity-obj-proxy"
},
"transformIgnorePatterns": [
"/node_modules/(?!@?pubsweet)"
],
"testPathIgnorePatterns": [
"/node_modules",
"config/"
]
}
}
const bodyParser = require('body-parser')
const logger = require('@pubsweet/logger')
const uuid = require('uuid')
const crypto = require('crypto')
const mailService = require('pubsweet-component-mail-service')
const get = require('lodash/get')
const pick = require('lodash/pick')
const config = require('config')
const configRoles = config.get('roles')
const Invite = app => {
app.use(bodyParser.json())
const authBearer = app.locals.passport.authenticate('bearer', {
session: false,
})
app.post('/api/users/invite/:collectionId?', authBearer, async (req, res) => {
const { email, role, firstName, lastName, affiliation, title } = req.body
if (!checkForUndefinedParams(email, role)) {
res.status(400).json({ error: 'Email and role are required' })
logger.error('some parameters are missing')
return
}
const hasInviteRight = existingRole =>
configRoles.inviteRights[existingRole].includes(role)
const collectionId = get(req, 'params.collectionId')
const reqUser = await app.locals.models.User.find(req.user)
let collection
if (collectionId && reqUser.roles !== undefined) {
if (!configRoles.collection.includes(role)) {
res
.status(400)
.json({ error: `Role ${role} cannot be set on collections` })
logger.error(`invitation has been attempted with invalid role: ${role}`)
return
}
if (!reqUser.roles.some(hasInviteRight)) {
res.status(403).json({
error: `${reqUser.roles} cannot invite a ${role}`,
})
logger.error(`incorrect role when inviting a user`)
return
}
try {
collection = await app.locals.models.Collection.find(collectionId)
} catch (e) {
if (e.name === 'NotFoundError') {
res.status(404).json({ error: 'Collection not found' })
logger.error(`invalid collection id when inviting a ${role}`)
return
}
res.status(500).json({ error: 'Something went wrong' })
logger.error(e)
return
}
} else if (reqUser.admin === true) {
reqUser.roles = []
reqUser.roles.push('admin') // this should be moved in pubsweet server
} else {
res.status(403).json({
error: `${reqUser.roles ||
'undefined roles'} cannot invite a ${role} without a collection`,
})
logger.error(`request user does not have any defined roles`)
return
}
if (!reqUser.roles.some(hasInviteRight)) {
res.status(403).json({
error: `${reqUser.roles} cannot invite a ${role}`,
})
logger.error(`incorrect role when inviting a ${role}`)
return
}
try {
const user = await app.locals.models.User.findByEmail(email)
if (user) {
res.status(400).json({ error: 'User already exists' })
logger.error('admin tried to invite existing user')
return
}
} catch (e) {
if (e.name !== 'NotFoundError') {
res.status(500).json({ error: e.details[0].message })
logger.error(e)
return
}
const userBody = {
username: uuid.v4().slice(0, 8),
email,
password: uuid.v4(),
roles: [role],
passwordResetToken: crypto.randomBytes(32).toString('hex'),
isConfirmed: false,
firstName,
lastName,
affiliation,
title,
admin: role === 'admin',
}
let newUser = new app.locals.models.User(userBody)
newUser = await newUser.save()
let emailType = 'invite-editor-in-chief'
if (collection) {
let permissions, group, name
switch (newUser.roles[0]) {
case 'handlingEditor':
emailType = 'invite-handling-editor'
permissions = 'editor'
group = 'editor'
name = 'Handling Editor'
break
case 'reviewer':
emailType = 'invite-reviewer'
permissions = 'reviewer'
group = 'reviewer'
name = 'Reviewer'
break
default:
break
}
const teamBody = {
teamType: {
name: newUser.roles[0],
permissions,
},
group,
name,
object: {
type: 'collection',
id: collection.id,
},
members: [newUser.id],
}
const team = new app.locals.models.Team(teamBody)
await team.save()
}
await mailService.setupEmail(
newUser.email,
emailType,
newUser.passwordResetToken,
)
res.status(200).json(newUser)
}
})
app.get('/api/users/invite', async (req, res) => {
const { email, token } = req.query
if (!checkForUndefinedParams(email, token)) {
res.status(400).json({ error: 'missing required params' })
return
}
const validateResponse = await validateEmailAndToken(
email,
token,
app.locals.models.User,
)
if (validateResponse.success === false) {
res
.status(validateResponse.status)
.json({ error: validateResponse.message })
return
}
const resBody = pick(validateResponse.user, [
'firstName',
'lastName',
'affiliation',
'title',
])
res.status(200).json(resBody)
})
app.post(
'/api/users/invite/:collectionId?',
authBearer,
require('./routes/post')(app.locals.models),
)
app.get('/api/users/invite', require('./routes/get')(app.locals.models))
app.post(
'/api/users/invite/password/reset',
bodyParser.json(),
async (req, res) => {
if (!checkForUndefinedParams(req.body)) {
res.status(400).json({ error: 'missing required params' })
return
}
const { password } = req.body
if (password.length < 7) {
res
.status(400)
.json({ error: 'password needs to be at least 7 characters long' })
logger.error(
`the user added an invalid password length: ${password.length}`,
)
return
}
const updateFields = {
password,
firstName: req.body.firstName,
lastName: req.body.lastName,
affiliation: req.body.affiliation,
title: req.body.title,
isConfirmed: true,
}
const validateResponse = await validateEmailAndToken(
req.body.email,
req.body.token,
app.locals.models.User,
)
if (validateResponse.success === false) {
res
.status(validateResponse.status)
.json({ error: validateResponse.message })
return
}
if (validateResponse.user.isConfirmed) {
res.status(400).json({ error: 'User is already confirmed' })
return
}
let newUser = Object.assign(
validateResponse.user,
updateFields,
validateResponse.user,
)
delete newUser.passwordResetToken
newUser = await newUser.save()
res.status(200).json(newUser)
},
require('./routes/reset')(app.locals.models),
)
}
const checkForUndefinedParams = (...params) => {
if (params.includes(undefined)) {
return false
}
return true
}
const validateEmailAndToken = async (email, token, userModel) => {
try {
const user = await userModel.findByEmail(email)
if (user) {
if (token !== user.passwordResetToken) {
logger.error(
`invite pw reset tokens do not match: REQ ${token} vs. DB ${
user.passwordResetToken
}`,
)
return {
success: false,
status: 400,
message: 'invalid request',
}
}
return { success: true, user }
}
} catch (e) {
if (e.name === 'NotFoundError') {
logger.error('invite pw reset on non-existing user')
return {
success: false,
status: 404,
message: 'user not found',
}
} else if (e.name === 'ValidationError') {
logger.error('invite pw reset validation error')
return {
success: false,
status: 400,
message: e.details[0].message,
}
}
logger.error(e)
return {
success: false,
status: 500,
message: e.details[0].message,
}
}
}
module.exports = Invite
const logger = require('@pubsweet/logger')
const uuid = require('uuid')
const crypto = require('crypto')
const checkForUndefinedParams = (...params) => {
if (params.includes(undefined)) {
return false
}
return true
}
const validateEmailAndToken = async (email, token, userModel) => {
try {
const user = await userModel.findByEmail(email)
if (user) {
if (token !== user.passwordResetToken) {
logger.error(
`invite pw reset tokens do not match: REQ ${token} vs. DB ${
user.passwordResetToken
}`,
)
return {
success: false,
status: 400,
message: 'invalid request',
}
}
return { success: true, user }
}
} catch (e) {
if (e.name === 'NotFoundError') {
logger.error('invite pw reset on non-existing user')
return {
success: false,
status: 404,
message: 'user not found',
}
} else if (e.name === 'ValidationError') {
logger.error('invite pw reset validation error')
return {
success: false,
status: 400,
message: e.details[0].message,
}
}
logger.error(e)
return {
success: false,
status: 500,
message: e.details[0].message,
}
}
}
const hasInviteRight = (configRoles, userRoles, role) => {
const includesRole = existingRole =>
configRoles.inviteRights[existingRole].includes(role)
if (!userRoles.some(includesRole)) {
logger.error(`incorrect role when inviting a user`)
return {
success: false,
status: 403,
message: `${userRoles} cannot invite a ${role}`,
}
}
return {
success: 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
}
const createNewTeam = async (collectionId, emailType, user, TeamModel) => {
let permissions, group, name
switch (user.roles[0]) {
case 'handlingEditor':
emailType = 'invite-handling-editor'
permissions = 'editor'
group = 'editor'
name = 'Handling Editor'
break
case 'reviewer':
emailType = 'invite-reviewer'
permissions = 'reviewer'
group = 'reviewer'
name = 'Reviewer'
break
default:
break
}
const teamBody = {
teamType: {
name: user.roles[0],
permissions,
},
group,
name,
object: {
type: 'collection',
id: collectionId,
},
members: [user.id],
}
const team = new TeamModel(teamBody)
await team.save()
return emailType
}
const createNewUser = async (
email,
role,
firstName,
lastName,
affiliation,
title,
UserModel,
) => {
const userBody = {
username: uuid.v4().slice(0, 8),
email,
password: uuid.v4(),
roles: [role],
passwordResetToken: crypto.randomBytes(32).toString('hex'),
isConfirmed: false,
firstName,
lastName,
affiliation,
title,
admin: role === 'admin',
}
let newUser = new UserModel(userBody)
newUser = await newUser.save()
return newUser
}
module.exports = {
checkForUndefinedParams,
validateEmailAndToken,
hasInviteRight,
handleNotFoundError,
createNewTeam,
createNewUser,
}
const helpers = require('../helpers/helpers')
const pick = require('lodash/pick')
module.exports = models => async (req, res) => {
const { email, token } = req.query
if (!helpers.checkForUndefinedParams(email, token)) {
res.status(400).json({ error: 'missing required params' })
return
}
const validateResponse = await helpers.validateEmailAndToken(
email,
token,
models.User,
)
if (validateResponse.success === false) {
res
.status(validateResponse.status)
.json({ error: validateResponse.message })
return
}
const resBody = pick(validateResponse.user, [
'firstName',
'lastName',
'affiliation',
'title',
])
res.status(200).json(resBody)
}
const logger = require('@pubsweet/logger')
const mailService = require('pubsweet-component-mail-service')
const get = require('lodash/get')
const config = require('config')
const helpers = require('../helpers/helpers')
const configRoles = config.get('roles')
module.exports = models => async (req, res) => {
const { email, role, firstName, lastName, affiliation, title } = req.body
if (!helpers.checkForUndefinedParams(email, role)) {
res.status(400).json({ error: 'Email and role are required' })
logger.error('some parameters are missing')
return
}
const collectionId = get(req, 'params.collectionId')
const reqUser = await models.User.find(req.user)
let collection
if (reqUser.admin && collectionId) {
res.status(403).json({
error: `admin cannot invite an ${role} to a collection`,
})
logger.error(`admin tried to invite a ${role} to a collection`)
return
} else if (reqUser.admin) {
reqUser.roles = reqUser.roles || ['admin']
const inviteRight = helpers.hasInviteRight(configRoles, reqUser.roles, role)
if (!inviteRight.success) {
res.status(inviteRight.status).json({
error: inviteRight.message,
})
logger.error(`incorrect role when inviting a user`)
return
}
} else if (collectionId) {
if (!configRoles.collection.includes(role)) {
res
.status(400)
.json({ error: `Role ${role} cannot be set on collections` })
logger.error(`invitation has been attempted with invalid role: ${role}`)
return
}
const inviteRight = helpers.hasInviteRight(configRoles, reqUser.roles, role)
if (!inviteRight.success) {
res.status(inviteRight.status).json({
error: inviteRight.message,
})
return
}
try {
collection = await models.Collection.find(collectionId)
} catch (e) {
const notFoundError = helpers.handleNotFoundError(e, 'collection')
res.status(notFoundError.status).json({
error: notFoundError.message,
})
return
}
} else {
res.status(403).json({
error: `${reqUser.roles ||
'undefined roles'} cannot invite a ${role} without a collection`,
})
logger.error(`request user does not have any defined roles`)
return
}
try {
const user = await models.User.findByEmail(email)
if (user) {
res.status(400).json({ error: 'User already exists' })
logger.error('admin tried to invite existing user')
return
}
} catch (e) {
if (e.name !== 'NotFoundError') {
res.status(500).json({ error: e.details[0].message })
logger.error(e)
return
}
const newUser = await helpers.createNewUser(
email,
role,
firstName,
lastName,
affiliation,
title,
models.User,
)
let emailType = 'invite-editor-in-chief'
emailType = !collection
? emailType
: await helpers.createNewTeam(
collection.id,
emailType,
newUser,
models.Team,
)
await mailService.setupEmail(
newUser.email,
emailType,
newUser.passwordResetToken,
)
res.status(200).json(newUser)
}
}
const logger = require('@pubsweet/logger')
const helpers = require('../helpers/helpers')
module.exports = models => async (req, res) => {
if (!helpers.checkForUndefinedParams(req.body)) {
res.status(400).json({ error: 'missing required params' })
return
}
const { password } = req.body
if (password.length < 7) {
res
.status(400)
.json({ error: 'password needs to be at least 7 characters long' })
logger.error(
`the user added an invalid password length: ${password.length}`,
)
return
}
const updateFields = {
password,
firstName: req.body.firstName,
lastName: req.body.lastName,
affiliation: req.body.affiliation,
title: req.body.title,
isConfirmed: true,
}
const validateResponse = await helpers.validateEmailAndToken(
req.body.email,
req.body.token,
models.User,
)
if (validateResponse.success === false) {
res
.status(validateResponse.status)
.json({ error: validateResponse.message })
return
}
if (validateResponse.user.isConfirmed) {
res.status(400).json({ error: 'User is already confirmed' })
return
}
let newUser = Object.assign(
validateResponse.user,
updateFields,
validateResponse.user,
)
delete newUser.passwordResetToken
newUser = await newUser.save()
res.status(200).json(newUser)
}
const users = require('./users')
module.exports = {
standardCollection: {
id: '2c4fb766-a798-4c32-b857-c5d21a2ab331',
title: 'Standard Collection',
type: 'collection',
fragments: [],
owners: [users.admin.id],
save: jest.fn(),
},
}
const users = require('./users')
const collections = require('./collections')
module.exports = {
users,
collections,
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment