diff --git a/packages/component-invite/src/controllers/assignCollectionRole.js b/packages/component-invite/src/controllers/assignCollectionRole.js index 50c72eafb20bb901e7f14fbf0a515eee206d176f..1a87770deb0c43decea68ed059eb860c401585df 100644 --- a/packages/component-invite/src/controllers/assignCollectionRole.js +++ b/packages/component-invite/src/controllers/assignCollectionRole.js @@ -62,20 +62,15 @@ module.exports = async ( try { let user = await models.User.findByEmail(email) - const invitation = { - type: role, - hasAnswer: false, - isAccepted: false, - collectionId, - timestamp: Date.now(), - } - user.invitations = user.invitations || [] - user.invitations.push(invitation) - user = await user.save() - await teamHelper.setupManuscriptTeam(models, user, collectionId, role) + const team = await teamHelper.setupManuscriptTeam( + models, + user, + collectionId, + role, + ) - user = await models.User.find(user) + user = await teamHelper.setupInvitation(user, role, collectionId, team.id) try { await mailService.setupAssignEmail( diff --git a/packages/component-invite/src/helpers/Team.js b/packages/component-invite/src/helpers/Team.js index aa967186b165ae6141c764e6cc76bc249314f775..87c1a2dbe6a8d5b19275981e681f555f0b90db49 100644 --- a/packages/component-invite/src/helpers/Team.js +++ b/packages/component-invite/src/helpers/Team.js @@ -33,12 +33,9 @@ const createNewTeam = async (collectionId, role, userId, TeamModel) => { }, members: [userId], } - const team = new TeamModel(teamBody) - try { - await team.save() - } catch (e) { - logger.error(e) - } + let team = new TeamModel(teamBody) + team = await team.save() + return team } const setupEiCTeams = async (models, user) => { @@ -91,11 +88,13 @@ const setupManuscriptTeam = async (models, user, collectionId, role) => { try { team = await team.updateProperties(team) team = await team.save() + return team } catch (e) { logger.error(e) } } else { - await createNewTeam(collectionId, role, user.id, models.Team) + const team = await createNewTeam(collectionId, role, user.id, models.Team) + return team } } @@ -113,9 +112,33 @@ const getMatchingTeams = (teams, TeamModel, collectionId, role) => }) .filter(Boolean) +const setupInvitation = async (user, role, collectionId, teamId) => { + const invitation = { + type: role, + hasAnswer: false, + isAccepted: false, + collectionId, + timestamp: Date.now(), + teamId, + } + user.invitations = user.invitations || [] + user.invitations.push(invitation) + user = await user.save() + return user +} + +const removeTeamMember = async (teamId, userId, TeamModel) => { + const team = await TeamModel.find(teamId) + const members = team.members.filter(member => member !== userId) + team.members = members + await TeamModel.updateProperties(team) + await team.save() +} module.exports = { createNewTeam, setupEiCTeams, setupManuscriptTeam, getMatchingTeams, + setupInvitation, + removeTeamMember, } diff --git a/packages/component-invite/src/routes/postHandleInvitation.js b/packages/component-invite/src/routes/postHandleInvitation.js index e659a91dc9013e66e4f5c3450aa444063748b484..d9ff99d5025c8dea2c024bb38a6b46013430560d 100644 --- a/packages/component-invite/src/routes/postHandleInvitation.js +++ b/packages/component-invite/src/routes/postHandleInvitation.js @@ -1,5 +1,6 @@ const logger = require('@pubsweet/logger') const helpers = require('../helpers/helpers') +const teamHelper = require('../helpers/Team') module.exports = models => async (req, res) => { const { type, accept } = req.body @@ -17,6 +18,7 @@ module.exports = models => async (req, res) => { return } const { collectionId } = req.params + // console.log('UI', user.invitations) const filteredInvitations = user.invitations.filter( invitation => invitation.collectionId === collectionId && invitation.type === type, @@ -38,10 +40,15 @@ module.exports = models => async (req, res) => { matchingInvitation.hasAnswer = true if (accept === true) { matchingInvitation.isAccepted = true + await user.save() } else { - // TODO: remove the user from the team if invitation is refused + await teamHelper.removeTeamMember( + matchingInvitation.teamId, + user.id, + models.Team, + ) } - await user.save() + res.status(204).json() return } catch (e) { diff --git a/packages/component-invite/src/routes/postInvite.js b/packages/component-invite/src/routes/postInvite.js index 113f8b21a436110a610d08c694d1a777773796fd..5e9d312a99676492e75532fa8ece95018bc4bba9 100644 --- a/packages/component-invite/src/routes/postInvite.js +++ b/packages/component-invite/src/routes/postInvite.js @@ -19,7 +19,7 @@ module.exports = models => async (req, res) => { return require('../controllers/assignCollectionRole')( email, role, - reqUser, + req.user, res, collectionId, models, diff --git a/packages/component-invite/src/tests/fixtures/teams.js b/packages/component-invite/src/tests/fixtures/teams.js index 28cdaf9a8e5bc9b914988f860a8b947f4f8f55ae..bcc5690ed8b674c625d10a8098960f48a593621b 100644 --- a/packages/component-invite/src/tests/fixtures/teams.js +++ b/packages/component-invite/src/tests/fixtures/teams.js @@ -1,5 +1,7 @@ const users = require('./users') +const collections = require('./collections') +const { standardCollection } = collections const { editorInChief, handlingEditor, reviewer } = users const teams = { eicTeam: { @@ -26,11 +28,12 @@ const teams = { name: 'HandlingEditor', object: { type: 'collection', - id: '123', + id: standardCollection.id, }, members: [handlingEditor.id], save: jest.fn(() => teams.heTeam), updateProperties: jest.fn(() => teams.heTeam), + id: 'he123', }, reviewerTeam: { teamType: { diff --git a/packages/component-invite/src/tests/fixtures/users.js b/packages/component-invite/src/tests/fixtures/users.js index 92c45e66f05efe41724ce0b1936086b55ce51a2d..86f6c66be75d1fcc462d96b98861d003915f4e80 100644 --- a/packages/component-invite/src/tests/fixtures/users.js +++ b/packages/component-invite/src/tests/fixtures/users.js @@ -1,6 +1,5 @@ -const collections = require('./collections') - -const { standardCollection } = collections +// const { heInvitation } = require('./invitations') +const { standardCollection } = require('./collections') const users = { admin: { @@ -41,6 +40,7 @@ const users = { isAccepted: false, collectionId: standardCollection.id, timestamp: Date.now(), + teamId: 'he123', }, ], save: jest.fn(() => users.handlingEditor), diff --git a/packages/component-invite/src/tests/helpers/Model.js b/packages/component-invite/src/tests/helpers/Model.js new file mode 100644 index 0000000000000000000000000000000000000000..40fecc6e1812f276d9be4944e9cdef786b177d17 --- /dev/null +++ b/packages/component-invite/src/tests/helpers/Model.js @@ -0,0 +1,53 @@ +const fixtures = require('../fixtures/fixtures') + +const UserMock = require('../mocks/User') +const TeamMock = require('../mocks/Team') + +const build = (collection, findUser, emailUser, team) => { + const models = { + User: {}, + Collection: { + find: jest.fn( + () => + collection instanceof Error + ? Promise.reject(collection) + : Promise.resolve(collection), + ), + }, + Team: {}, + } + UserMock.find = jest.fn(user => { + const foundUser = Object.values(fixtures.users).find( + fixUser => fixUser.id === user.id, + ) + + if (foundUser === undefined) { + return Promise.reject(findUser) + } + + return Promise.resolve(findUser) + }) + + UserMock.findByEmail = jest.fn( + () => + emailUser instanceof Error + ? Promise.reject(emailUser) + : Promise.resolve(emailUser), + ) + + TeamMock.find = jest.fn( + () => + team instanceof Error ? Promise.reject(team) : Promise.resolve(team), + ) + TeamMock.updateProperties = jest.fn( + () => + team instanceof Error ? Promise.reject(team) : Promise.resolve(team), + ) + TeamMock.all = jest.fn(() => Object.values(fixtures.teams)) + + models.User = UserMock + models.Team = TeamMock + return models +} + +module.exports = { build } diff --git a/packages/component-invite/src/tests/postHandleInvitation.test.js b/packages/component-invite/src/tests/postHandleInvitation.test.js index 6eaca0e9cbbe053906989f4335e6c4d278a68247..795cdb4ea8180d1a29e458677a95f36c37a157ab 100644 --- a/packages/component-invite/src/tests/postHandleInvitation.test.js +++ b/packages/component-invite/src/tests/postHandleInvitation.test.js @@ -3,39 +3,21 @@ process.env.SUPPRESS_NO_CONFIG_WARNING = true const httpMocks = require('node-mocks-http') const fixtures = require('./fixtures/fixtures') -const UserMock = require('./mocks/User') const cloneDeep = require('lodash/cloneDeep') +const Model = require('./helpers/Model') jest.mock('pubsweet-component-mail-service', () => ({ setupAssignEmail: jest.fn(), })) -const buildModels = (collection, user) => { - const models = { - User: {}, - Collection: { - find: jest.fn( - () => - collection instanceof Error - ? Promise.reject(collection) - : Promise.resolve(collection), - ), - }, - } - UserMock.find = jest.fn( - () => - user instanceof Error ? Promise.reject(user) : Promise.resolve(user), - ) - models.User = UserMock - return models -} - const notFoundError = new Error() notFoundError.name = 'NotFoundError' notFoundError.status = 404 const { handlingEditor } = fixtures.users const { standardCollection } = fixtures.collections +const { heTeam } = fixtures.teams + const postInvitationPath = '../routes/postHandleInvitation' describe('Post handle invitation route handler', () => { it('should return success when the handling editor accepts work on a collection', async () => { @@ -50,9 +32,8 @@ describe('Post handle invitation route handler', () => { req.user = acceptingHE req.params.collectionId = standardCollection.id const res = httpMocks.createResponse() - const models = buildModels(standardCollection, acceptingHE) + const models = Model.build(standardCollection, acceptingHE, null, heTeam) await require(postInvitationPath)(models)(req, res) - expect(res.statusCode).toBe(204) expect(acceptingHE.invitations[0].hasAnswer).toBeTruthy() expect(acceptingHE.invitations[0].isAccepted).toBeTruthy() @@ -69,7 +50,7 @@ describe('Post handle invitation route handler', () => { req.user = refusingHE req.params.collectionId = standardCollection.id const res = httpMocks.createResponse() - const models = buildModels(standardCollection, refusingHE) + const models = Model.build(standardCollection, refusingHE, null, heTeam) await require(postInvitationPath)(models)(req, res) expect(res.statusCode).toBe(204) @@ -86,7 +67,7 @@ describe('Post handle invitation route handler', () => { req.user = handlingEditor req.params.collectionId = standardCollection.id const res = httpMocks.createResponse() - const models = buildModels(standardCollection, handlingEditor) + const models = Model.build(standardCollection, handlingEditor) await require(postInvitationPath)(models)(req, res) expect(res.statusCode).toBe(400) @@ -104,7 +85,7 @@ describe('Post handle invitation route handler', () => { req.user = handlingEditor req.params.collectionId = standardCollection.id const res = httpMocks.createResponse() - const models = buildModels(notFoundError, handlingEditor) + const models = Model.build(notFoundError, handlingEditor) await require(postInvitationPath)(models)(req, res) expect(res.statusCode).toBe(404) @@ -124,7 +105,7 @@ describe('Post handle invitation route handler', () => { req.user = noInvitationEditor req.params.collectionId = standardCollection.id const res = httpMocks.createResponse() - const models = buildModels(standardCollection, noInvitationEditor) + const models = Model.build(standardCollection, noInvitationEditor) await require(postInvitationPath)(models)(req, res) expect(res.statusCode).toBe(400) @@ -142,7 +123,7 @@ describe('Post handle invitation route handler', () => { req.user = handlingEditor req.params.collectionId = standardCollection.id const res = httpMocks.createResponse() - const models = buildModels(standardCollection, handlingEditor) + const models = Model.build(standardCollection, handlingEditor) await require(postInvitationPath)(models)(req, res) expect(res.statusCode).toBe(400) @@ -162,7 +143,7 @@ describe('Post handle invitation route handler', () => { req.user = handlingEditor req.params.collectionId = '123' const res = httpMocks.createResponse() - const models = buildModels(standardCollection, handlingEditor) + const models = Model.build(standardCollection, handlingEditor) await require(postInvitationPath)(models)(req, res) expect(res.statusCode).toBe(400) diff --git a/packages/component-invite/src/tests/postInvite.test.js b/packages/component-invite/src/tests/postInvite.test.js index bb215f379101b0f6c9c29913660a2dc45513c6cf..17e7e9c12d89722970783c9e026f9aac8b1d1593 100644 --- a/packages/component-invite/src/tests/postInvite.test.js +++ b/packages/component-invite/src/tests/postInvite.test.js @@ -4,10 +4,8 @@ process.env.SUPPRESS_NO_CONFIG_WARNING = true const httpMocks = require('node-mocks-http') const random = require('lodash/random') const fixtures = require('./fixtures/fixtures') - -const UserMock = require('./mocks/User') const Chance = require('chance') -const TeamMock = require('./mocks/Team') +const Model = require('./helpers/Model') jest.mock('pubsweet-component-mail-service', () => ({ setupInviteEmail: jest.fn(), @@ -17,49 +15,6 @@ const chance = new Chance() const globalRoles = ['editorInChief', 'author', 'admin'] const manuscriptRoles = ['handlingEditor', 'reviewer'] -const buildModels = (collection, findUser, emailUser, team) => { - const models = { - User: {}, - Collection: { - find: jest.fn( - () => - collection instanceof Error - ? Promise.reject(collection) - : Promise.resolve(collection), - ), - }, - Team: {}, - } - UserMock.find = jest.fn(user => { - const foundUser = Object.values(fixtures.users).find( - fixUser => fixUser.id === user.id, - ) - - if (foundUser === undefined) { - return Promise.reject(findUser) - } - - return Promise.resolve(foundUser) - }) - - UserMock.findByEmail = jest.fn( - () => - emailUser instanceof Error - ? Promise.reject(emailUser) - : Promise.resolve(emailUser), - ) - - TeamMock.find = jest.fn( - () => - team instanceof Error ? Promise.reject(team) : Promise.resolve(team), - ) - TeamMock.all = jest.fn(() => Object.values(fixtures.teams)) - - models.User = UserMock - models.Team = TeamMock - return models -} - const body = { email: chance.email(), role: globalRoles[random(0, globalRoles.length - 1)], @@ -85,7 +40,7 @@ describe('Post invite route handler', () => { }) req.user = admin const res = httpMocks.createResponse() - const models = buildModels(notFoundError, admin, notFoundError) + const models = Model.build(notFoundError, admin, notFoundError) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(200) @@ -101,7 +56,7 @@ describe('Post invite route handler', () => { req.user = admin req.params.collectionId = '123' const res = httpMocks.createResponse() - const models = buildModels(notFoundError, admin) + const models = Model.build(notFoundError, admin) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(403) const data = JSON.parse(res._getData()) @@ -117,7 +72,7 @@ describe('Post invite route handler', () => { }) req.user = admin const res = httpMocks.createResponse() - const models = buildModels(notFoundError, admin) + const models = Model.build(notFoundError, admin) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(403) const data = JSON.parse(res._getData()) @@ -132,7 +87,7 @@ describe('Post invite route handler', () => { }) req.user = admin const res = httpMocks.createResponse() - const models = buildModels(notFoundError, admin) + const models = Model.build(notFoundError, admin) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(400) const data = JSON.parse(res._getData()) @@ -148,7 +103,7 @@ describe('Post invite route handler', () => { req.user = editorInChief req.params.collectionId = '123' const res = httpMocks.createResponse() - const models = buildModels(notFoundError, editorInChief) + const models = Model.build(notFoundError, editorInChief) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(403) const data = JSON.parse(res._getData()) @@ -163,7 +118,7 @@ describe('Post invite route handler', () => { req.user = editorInChief const res = httpMocks.createResponse() - const models = buildModels(notFoundError, editorInChief) + const models = Model.build(notFoundError, editorInChief) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(403) const data = JSON.parse(res._getData()) @@ -180,7 +135,7 @@ describe('Post invite route handler', () => { req.user = handlingEditor const res = httpMocks.createResponse() - const models = buildModels(notFoundError, handlingEditor) + const models = Model.build(notFoundError, handlingEditor) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(403) const data = JSON.parse(res._getData()) @@ -196,7 +151,7 @@ describe('Post invite route handler', () => { }) req.user = admin const res = httpMocks.createResponse() - const models = buildModels(notFoundError, admin, editorInChief) + const models = Model.build(notFoundError, admin, editorInChief) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(400) @@ -214,7 +169,7 @@ describe('Post invite route handler', () => { req.user = editorInChief req.params.collectionId = '123' const res = httpMocks.createResponse() - const models = buildModels(standardCollection, author, author) + const models = Model.build(standardCollection, editorInChief, author) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(200) @@ -234,7 +189,7 @@ describe('Post invite route handler', () => { req.user = handlingEditor req.params.collectionId = '123' const res = httpMocks.createResponse() - const models = buildModels(standardCollection, handlingEditor, author) + const models = Model.build(standardCollection, handlingEditor, author) await require(postInvitePath)(models)(req, res) expect(res.statusCode).toBe(200)