const { Team, User, services, Collection, Invitation, Fragment, authsome: authsomeHelper, } = require('pubsweet-component-helper-service') const emailInvitations = require('./emails/invitations') const { last } = require('lodash') module.exports = models => async (req, res) => { const { email, role, firstName, lastName, affiliation, country } = req.body if ( !services.checkForUndefinedParams( email, role, firstName, lastName, affiliation, country, ) ) { res.status(400).json({ error: 'Missing parameters.' }) return } if (role !== 'reviewer') return res .status(400) .json({ error: `Role ${role} is invalid. Only reviewer is accepted.` }) const UserModel = models.User const reqUser = await UserModel.find(req.user) if (email === reqUser.email && !reqUser.admin) return res.status(400).json({ error: 'Cannot invite yourself.' }) const { collectionId, fragmentId } = req.params let collection, fragment try { collection = await models.Collection.find(collectionId) if (!collection.fragments.includes(fragmentId)) return res.status(400).json({ error: `Fragment ${fragmentId} does not match collection ${collectionId}.`, }) if (last(collection.fragments) !== fragmentId) return res.status(400).json({ error: `Fragment ${fragmentId} is an older version.`, }) fragment = await models.Fragment.find(fragmentId) } catch (e) { const notFoundError = await services.handleNotFoundError(e, 'item') return res.status(notFoundError.status).json({ error: notFoundError.message, }) } const { path } = req.route const authsome = authsomeHelper.getAuthsome(models) const target = { collection, path, } const canPost = await authsome.can(req.user, 'POST', target) if (!canPost) return res.status(403).json({ error: 'Unauthorized.', }) const collectionHelper = new Collection({ collection }) const baseUrl = services.getBaseUrl(req) const teamHelper = new Team({ TeamModel: models.Team, collectionId, fragmentId, }) const invitationHelper = new Invitation({ role }) try { const user = await UserModel.findByEmail(email) const canInvite = await authsome.can(req.user, '', { targetUser: user, }) if (!canInvite) { return res.status(400).json({ error: 'Invited user is inactive.' }) } await teamHelper.setupTeam({ user, role, objectType: 'fragment' }) invitationHelper.userId = user.id let invitation = invitationHelper.getInvitation({ invitations: fragment.invitations, }) let resend = false if (invitation) { if (invitation.hasAnswer) { return res .status(400) .json({ error: 'User has already replied to a previous invitation.' }) } invitation.invitedOn = Date.now() await fragment.save() resend = true } else { invitation = await invitationHelper.createInvitation({ parentObject: fragment, }) } const fragmentHelper = new Fragment({ fragment }) if ( collection.status === 'heAssigned' || (collection.status === 'reviewCompleted' && !fragmentHelper.hasReviewReport()) ) { collectionHelper.updateStatus({ newStatus: 'reviewersInvited' }) } emailInvitations.sendReviewInvitations({ resend, baseUrl, fragment, collection, invitation, invitedUser: user, UserModel: models.User, timestamp: invitation.invitedOn, }) return res.status(200).json(invitation) } catch (e) { const userHelper = new User({ UserModel }) const userData = req.body const { firstName, lastName, isPublons } = userData if (!services.checkForUndefinedParams(firstName, lastName)) { return res .status(400) .json({ error: 'First name and last name are required.' }) } if (isPublons && process.env.PUBLONS_MOCK_EMAIL) { const mockEmail = process.env.PUBLONS_MOCK_EMAIL userData.email = mockEmail.replace( '__NAME__', `${firstName.trim()}.${lastName.trim()}`, ) } let newUser try { newUser = await userHelper.createUser({ role, body: userData, }) } catch (e) { return res .status(400) .json({ error: `User already exists with email: ${userData.email}` }) } if (collection.status === 'heAssigned') await collectionHelper.updateStatus({ newStatus: 'reviewersInvited' }) await teamHelper.setupTeam({ user: newUser, role, objectType: 'fragment' }) invitationHelper.userId = newUser.id const invitation = await invitationHelper.createInvitation({ parentObject: fragment, }) emailInvitations.sendReviewInvitations({ baseUrl, fragment, collection, invitation, invitedUser: newUser, UserModel: models.User, timestamp: invitation.invitedOn, }) return res.status(200).json(invitation) } }