From ea9458ca024017ee7aa317f1cdf321320e638a0e Mon Sep 17 00:00:00 2001
From: Sebastian Mihalache <sebastian.mihalache@gmail.con>
Date: Wed, 20 Jun 2018 15:55:17 +0300
Subject: [PATCH] fix tests

---
 .../src/fixtures/fragments.js                 |   2 +-
 .../src/helpers/Model.js                      |   4 +-
 .../src/services/Collection.js                |   2 +-
 .../src/services/Email.js                     |   2 +-
 .../src/services/Fragment.js                  |  39 ++-
 .../src/services/User.js                      |   8 +-
 .../config/authsome-helpers.js                |  59 +++-
 .../tests/collectionsInvitations/get.test.js  | 137 --------
 .../config/authsome-helpers.js                |  59 +++-
 .../config/authsome-mode.js                   | 306 +++++++++---------
 .../routes/fragmentsRecommendations/patch.js  |   8 +-
 .../routes/fragmentsRecommendations/post.js   |   7 +-
 .../fragmentsRecommendations/post.test.js     |  23 +-
 .../config/authsome-helpers.js                |  59 +++-
 .../config/authsome-mode.js                   | 306 +++++++++---------
 .../src/FragmentsUsers.js                     |  17 +-
 .../src/routes/fragmentsUsers/post.js         |   2 +-
 .../xpub-faraday/config/authsome-helpers.js   |  15 +-
 packages/xpub-faraday/config/authsome-mode.js |   2 +
 19 files changed, 539 insertions(+), 518 deletions(-)
 delete mode 100644 packages/component-invite/src/tests/collectionsInvitations/get.test.js

diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js
index ab41ab428..5810c6fdd 100644
--- a/packages/component-fixture-manager/src/fixtures/fragments.js
+++ b/packages/component-fixture-manager/src/fixtures/fragments.js
@@ -41,7 +41,7 @@ const fragments = {
     ],
     authors: [
       {
-        userId: submittingAuthor.id,
+        id: submittingAuthor.id,
         isSubmitting: true,
         isCorresponding: false,
       },
diff --git a/packages/component-fixture-manager/src/helpers/Model.js b/packages/component-fixture-manager/src/helpers/Model.js
index 04bdb01f9..9ff60517c 100644
--- a/packages/component-fixture-manager/src/helpers/Model.js
+++ b/packages/component-fixture-manager/src/helpers/Model.js
@@ -16,6 +16,7 @@ const build = fixtures => {
       find: jest.fn(id => findMock(id, 'fragments', fixtures)),
     },
   }
+
   UserMock.find = jest.fn(id => findMock(id, 'users', fixtures))
   UserMock.findByEmail = jest.fn(email => findByEmailMock(email, fixtures))
   UserMock.all = jest.fn(() => Object.values(fixtures.users))
@@ -25,6 +26,7 @@ const build = fixtures => {
   UserMock.updateProperties = jest.fn(user =>
     updatePropertiesMock(user, 'users'),
   )
+
   TeamMock.find = jest.fn(id => findMock(id, 'teams', fixtures))
   TeamMock.updateProperties = jest.fn(team =>
     updatePropertiesMock(team, 'teams', fixtures),
@@ -41,7 +43,7 @@ const findMock = (id, type, fixtures) => {
     fixtureObj => fixtureObj.id === id,
   )
 
-  if (foundObj === undefined) return Promise.reject(notFoundError)
+  if (!foundObj) return Promise.reject(notFoundError)
   return Promise.resolve(foundObj)
 }
 
diff --git a/packages/component-helper-service/src/services/Collection.js b/packages/component-helper-service/src/services/Collection.js
index c0fb4fddd..fd58224e1 100644
--- a/packages/component-helper-service/src/services/Collection.js
+++ b/packages/component-helper-service/src/services/Collection.js
@@ -36,7 +36,7 @@ class Collection {
 
   async updateStatus({ newStatus }) {
     this.collection.status = newStatus
-    this.collection.visibleStatus = statuses[this.collection.status].private
+    this.collection.visibleStatus = statuses[this.collection.status].public
     await this.collection.save()
   }
 
diff --git a/packages/component-helper-service/src/services/Email.js b/packages/component-helper-service/src/services/Email.js
index 49fb18189..7e7bcd451 100644
--- a/packages/component-helper-service/src/services/Email.js
+++ b/packages/component-helper-service/src/services/Email.js
@@ -332,7 +332,7 @@ class Email {
   }
 
   async setupReviewerUnassignEmail({ user, authorName }) {
-    const { collection, fragment: { title } } = this
+    const { collection, parsedFragment: { title = '' } } = this
 
     await mailService.sendNotificationEmail({
       toEmail: user.email,
diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js
index c03dcdda7..37c3a22ea 100644
--- a/packages/component-helper-service/src/services/Fragment.js
+++ b/packages/component-helper-service/src/services/Fragment.js
@@ -1,13 +1,16 @@
+const get = require('lodash/get')
+
 class Fragment {
   constructor({ fragment }) {
     this.fragment = fragment
   }
+
   async getFragmentData({ handlingEditor = {} }) {
-    const { fragment: { metadata, recommendations = [], id } } = this
+    const { fragment: { metadata = {}, recommendations = [], id } } = this
     const heRecommendation = recommendations.find(
       rec => rec.userId === handlingEditor.id,
     )
-    let { title, abstract } = metadata
+    let { title = '', abstract = '' } = metadata
     const { type } = metadata
     title = title.replace(/<(.|\n)*?>/g, '')
     abstract = abstract ? abstract.replace(/<(.|\n)*?>/g, '') : ''
@@ -42,20 +45,26 @@ class Fragment {
   }
 
   async getAuthorData({ UserModel }) {
-    const { fragment: { authors } } = this
-    const submittingAuthorData = authors.find(
-      author => author.isSubmitting === true,
-    )
-    const submittingAuthor = await UserModel.find(submittingAuthorData.id)
-    const authorsPromises = authors.map(async author => {
-      const user = await UserModel.find(author.id)
-      return `${user.firstName} ${user.lastName}`
-    })
-    const authorsList = await Promise.all(authorsPromises)
+    const { fragment: { authors = [] } } = this
+    const submittingAuthorData = authors.find(author => author.isSubmitting)
 
-    return {
-      authorsList,
-      submittingAuthor,
+    try {
+      const submittingAuthor = await UserModel.find(
+        get(submittingAuthorData, 'id'),
+      )
+
+      const authorsPromises = authors.map(async author => {
+        const user = await UserModel.find(author.id)
+        return `${user.firstName} ${user.lastName}`
+      })
+      const authorsList = await Promise.all(authorsPromises)
+
+      return {
+        authorsList,
+        submittingAuthor,
+      }
+    } catch (e) {
+      throw e
     }
   }
 
diff --git a/packages/component-helper-service/src/services/User.js b/packages/component-helper-service/src/services/User.js
index ed69cd655..7d9d3e520 100644
--- a/packages/component-helper-service/src/services/User.js
+++ b/packages/component-helper-service/src/services/User.js
@@ -31,12 +31,8 @@ class User {
 
     let newUser = new UserModel(userBody)
 
-    try {
-      newUser = await newUser.save()
-      return newUser
-    } catch (e) {
-      logger.error(e)
-    }
+    newUser = await newUser.save()
+    return newUser
   }
 
   async setupNewUser({ url, role, invitationType, body = {} }) {
diff --git a/packages/component-invite/config/authsome-helpers.js b/packages/component-invite/config/authsome-helpers.js
index 164a9ce8a..55148df34 100644
--- a/packages/component-invite/config/authsome-helpers.js
+++ b/packages/component-invite/config/authsome-helpers.js
@@ -59,8 +59,12 @@ const filterObjectData = (
   return object
 }
 
-const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => {
-  const teams = await Promise.all(
+const getTeamsByPermissions = async (
+  teamIds = [],
+  permissions = [],
+  TeamModel,
+) =>
+  (await Promise.all(
     teamIds.map(async teamId => {
       const team = await TeamModel.find(teamId)
       if (!permissions.includes(team.teamType.permissions)) {
@@ -68,15 +72,60 @@ const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => {
       }
       return team
     }),
+  )).filter(Boolean)
+
+const heIsInvitedToFragment = async ({ user, Team, collectionId }) =>
+  (await getTeamsByPermissions(user.teams, ['handlingEditor'], Team)).some(
+    // user is a member of the team with access to the fragment's parent collection
+    t => t.members.includes(user.id) && t.object.id === collectionId,
   )
 
-  return teams.filter(Boolean)
+const getUserPermissions = async ({
+  user,
+  Team,
+  mapFn = t => ({
+    objectId: t.object.id,
+    objectType: t.object.type,
+    role: t.teamType.permissions,
+  }),
+}) =>
+  (await Promise.all(user.teams.map(teamId => Team.find(teamId)))).map(mapFn)
+
+const isOwner = ({ user: { id }, object }) => {
+  if (object.owners.includes(id)) return true
+  return !!object.owners.find(own => own.id === id)
+}
+
+const hasPermissionForObject = async ({ user, object, Team, roles = [] }) => {
+  const userPermissions = await getUserPermissions({
+    user,
+    Team,
+  })
+
+  return !!userPermissions.find(p => {
+    const hasObject =
+      p.objectId === get(object, 'fragment.id') ||
+      p.objectId === get(object, 'fragment.collectionId')
+    if (roles.length > 0) {
+      return hasObject && roles.includes(p.role)
+    }
+    return hasObject
+  })
 }
 
+const isHandlingEditor = ({ user, object }) =>
+  get(object, 'collection.handlingEditor.id') === user.id
+
 module.exports = {
+  filterObjectData,
   parseAuthorsData,
   setPublicStatuses,
-  filterRefusedInvitations,
-  filterObjectData,
   getTeamsByPermissions,
+  filterRefusedInvitations,
+  //
+  isOwner,
+  isHandlingEditor,
+  getUserPermissions,
+  heIsInvitedToFragment,
+  hasPermissionForObject,
 }
diff --git a/packages/component-invite/src/tests/collectionsInvitations/get.test.js b/packages/component-invite/src/tests/collectionsInvitations/get.test.js
deleted file mode 100644
index d630fa94c..000000000
--- a/packages/component-invite/src/tests/collectionsInvitations/get.test.js
+++ /dev/null
@@ -1,137 +0,0 @@
-process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
-process.env.SUPPRESS_NO_CONFIG_WARNING = true
-
-const cloneDeep = require('lodash/cloneDeep')
-const fixturesService = require('pubsweet-component-fixture-service')
-const requests = require('../requests')
-
-const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
-  sendReviewerInvitationEmail: jest.fn(),
-}))
-const path = '../routes/collectionsInvitations/get'
-const route = {
-  path: '/api/collections/:collectionId/invitations/:invitationId?',
-}
-describe('Get collection invitations route handler', () => {
-  let testFixtures = {}
-  let models
-  beforeEach(() => {
-    testFixtures = cloneDeep(fixtures)
-    models = Model.build(testFixtures)
-  })
-  it('should return success when the request data is correct', async () => {
-    const { editorInChief, handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
-    const res = await requests.sendRequest({
-      userId: editorInChief.id,
-      route,
-      models,
-      path,
-      query: {
-        role: 'handlingEditor',
-        userId: handlingEditor.id,
-      },
-      params: {
-        collectionId: collection.id,
-      },
-    })
-
-    expect(res.statusCode).toBe(200)
-    const data = JSON.parse(res._getData())
-    expect(data.length).toBeGreaterThan(0)
-  })
-  it('should return an error when parameters are missing', async () => {
-    const { editorInChief } = testFixtures.users
-    const res = await requests.sendRequest({
-      userId: editorInChief.id,
-      route,
-      models,
-      path,
-    })
-    expect(res.statusCode).toBe(400)
-    const data = JSON.parse(res._getData())
-    expect(data.error).toEqual('Role is required')
-  })
-  it('should return an error when the collection does not exist', async () => {
-    const { editorInChief, handlingEditor } = testFixtures.users
-    const res = await requests.sendRequest({
-      userId: editorInChief.id,
-      route,
-      models,
-      path,
-      query: {
-        role: 'handlingEditor',
-        userId: handlingEditor.id,
-      },
-      params: {
-        collectionId: 'invalid-id',
-      },
-    })
-    expect(res.statusCode).toBe(404)
-    const data = JSON.parse(res._getData())
-    expect(data.error).toEqual('collection not found')
-  })
-  it('should return an error when the role is invalid', async () => {
-    const { editorInChief, handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
-    const res = await requests.sendRequest({
-      userId: editorInChief.id,
-      route,
-      models,
-      path,
-      query: {
-        role: 'invalidRole',
-        userId: handlingEditor.id,
-      },
-      params: {
-        collectionId: collection.id,
-      },
-    })
-    expect(res.statusCode).toBe(400)
-    const data = JSON.parse(res._getData())
-    expect(data.error).toEqual(`Role invalidRole is invalid`)
-  })
-  it('should return success with an empty array when the collection does not have a the requested role team', async () => {
-    const { editorInChief, handlingEditor } = testFixtures.users
-    const { collection } = testFixtures.collections
-    delete collection.invitations
-    const res = await requests.sendRequest({
-      userId: editorInChief.id,
-      route,
-      models,
-      path,
-      query: {
-        role: 'author',
-        userId: handlingEditor.id,
-      },
-      params: {
-        collectionId: collection.id,
-      },
-    })
-    expect(res.statusCode).toBe(200)
-    const data = JSON.parse(res._getData())
-    expect(data).toHaveLength(0)
-  })
-  it('should return an error when a user does not have invitation rights', async () => {
-    const { author } = testFixtures.users
-    const { collection } = testFixtures.collections
-    const res = await requests.sendRequest({
-      userId: author.id,
-      route,
-      models,
-      path,
-      query: {
-        role: 'handlingEditor',
-      },
-      params: {
-        collectionId: collection.id,
-      },
-    })
-    expect(res.statusCode).toBe(403)
-    const data = JSON.parse(res._getData())
-    expect(data.error).toEqual('Unauthorized.')
-  })
-})
diff --git a/packages/component-manuscript-manager/config/authsome-helpers.js b/packages/component-manuscript-manager/config/authsome-helpers.js
index 164a9ce8a..55148df34 100644
--- a/packages/component-manuscript-manager/config/authsome-helpers.js
+++ b/packages/component-manuscript-manager/config/authsome-helpers.js
@@ -59,8 +59,12 @@ const filterObjectData = (
   return object
 }
 
-const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => {
-  const teams = await Promise.all(
+const getTeamsByPermissions = async (
+  teamIds = [],
+  permissions = [],
+  TeamModel,
+) =>
+  (await Promise.all(
     teamIds.map(async teamId => {
       const team = await TeamModel.find(teamId)
       if (!permissions.includes(team.teamType.permissions)) {
@@ -68,15 +72,60 @@ const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => {
       }
       return team
     }),
+  )).filter(Boolean)
+
+const heIsInvitedToFragment = async ({ user, Team, collectionId }) =>
+  (await getTeamsByPermissions(user.teams, ['handlingEditor'], Team)).some(
+    // user is a member of the team with access to the fragment's parent collection
+    t => t.members.includes(user.id) && t.object.id === collectionId,
   )
 
-  return teams.filter(Boolean)
+const getUserPermissions = async ({
+  user,
+  Team,
+  mapFn = t => ({
+    objectId: t.object.id,
+    objectType: t.object.type,
+    role: t.teamType.permissions,
+  }),
+}) =>
+  (await Promise.all(user.teams.map(teamId => Team.find(teamId)))).map(mapFn)
+
+const isOwner = ({ user: { id }, object }) => {
+  if (object.owners.includes(id)) return true
+  return !!object.owners.find(own => own.id === id)
+}
+
+const hasPermissionForObject = async ({ user, object, Team, roles = [] }) => {
+  const userPermissions = await getUserPermissions({
+    user,
+    Team,
+  })
+
+  return !!userPermissions.find(p => {
+    const hasObject =
+      p.objectId === get(object, 'fragment.id') ||
+      p.objectId === get(object, 'fragment.collectionId')
+    if (roles.length > 0) {
+      return hasObject && roles.includes(p.role)
+    }
+    return hasObject
+  })
 }
 
+const isHandlingEditor = ({ user, object }) =>
+  get(object, 'collection.handlingEditor.id') === user.id
+
 module.exports = {
+  filterObjectData,
   parseAuthorsData,
   setPublicStatuses,
-  filterRefusedInvitations,
-  filterObjectData,
   getTeamsByPermissions,
+  filterRefusedInvitations,
+  //
+  isOwner,
+  isHandlingEditor,
+  getUserPermissions,
+  heIsInvitedToFragment,
+  hasPermissionForObject,
 }
diff --git a/packages/component-manuscript-manager/config/authsome-mode.js b/packages/component-manuscript-manager/config/authsome-mode.js
index 8a92a1301..20e0d6918 100644
--- a/packages/component-manuscript-manager/config/authsome-mode.js
+++ b/packages/component-manuscript-manager/config/authsome-mode.js
@@ -1,69 +1,8 @@
-const get = require('lodash/get')
-const pickBy = require('lodash/pickBy')
-const omit = require('lodash/omit')
-const helpers = require('./authsome-helpers')
-
-async function teamPermissions(user, operation, object, context) {
-  const { models } = context
-  const permissions = ['handlingEditor', 'author', 'reviewer']
-  const teams = await helpers.getTeamsByPermissions(
-    user.teams,
-    permissions,
-    context.models.Team,
-  )
-
-  let collectionsPermissions = await Promise.all(
-    teams.map(async team => {
-      let collection
-      if (team.object.type === 'collection') {
-        collection = await models.Collection.find(team.object.id)
-      } else if (team.object.type === 'fragment') {
-        const fragment = await models.Fragment.find(team.object.id)
-        collection = await models.Collection.find(fragment.collectionId)
-      }
-      if (
-        collection.status === 'rejected' &&
-        team.teamType.permissions === 'reviewer'
-      )
-        return null
-      const collPerm = {
-        id: collection.id,
-        permission: team.teamType.permissions,
-      }
-      const objectType = get(object, 'type')
-      if (objectType === 'fragment') {
-        if (collection.fragments.includes(object.id))
-          collPerm.fragmentId = object.id
-        else return null
-      }
-
-      if (objectType === 'collection')
-        if (object.id !== collection.id) return null
-      return collPerm
-    }),
-  )
-  collectionsPermissions = collectionsPermissions.filter(cp => cp !== null)
-  if (collectionsPermissions.length === 0) return false
-
-  return {
-    filter: filterParam => {
-      if (!filterParam.length) {
-        return helpers.filterObjectData(
-          collectionsPermissions,
-          filterParam,
-          user,
-        )
-      }
+const config = require('config')
+const { get, pickBy, omit } = require('lodash')
 
-      const collections = filterParam
-        .map(coll =>
-          helpers.filterObjectData(collectionsPermissions, coll, user),
-        )
-        .filter(Boolean)
-      return collections
-    },
-  }
-}
+const statuses = config.get('statuses')
+const helpers = require('./authsome-helpers')
 
 function unauthenticatedUser(operation, object) {
   // Public/unauthenticated users can GET /collections, filtered by 'published'
@@ -111,133 +50,182 @@ function unauthenticatedUser(operation, object) {
   return false
 }
 
+const publicStatusesPermissions = ['author', 'reviewer']
+const createPaths = ['/collections', '/collections/:collectionId/fragments']
+
 async function authenticatedUser(user, operation, object, context) {
-  // Allow the authenticated user to POST a collection (but not with a 'filtered' property)
-  if (operation === 'POST' && object.path === '/collections') {
-    return {
-      filter: collection => omit(collection, 'filtered'),
+  if (operation === 'GET') {
+    if (get(object, 'path') === '/collections') {
+      return {
+        filter: async collections => {
+          const userPermissions = await helpers.getUserPermissions({
+            user,
+            Team: context.models.Team,
+          })
+          return collections.filter(collection => {
+            if (collection.owners.includes(user.id)) {
+              return true
+            }
+            const collectionPermission = userPermissions.find(
+              p => p.objectId === collection.id,
+            )
+            if (collectionPermission) {
+              return true
+            }
+
+            const fragmentPermission = userPermissions.find(p =>
+              collection.fragments.includes(p.objectId),
+            )
+            if (fragmentPermission) {
+              return true
+            }
+            return false
+          })
+        },
+      }
     }
-  }
 
-  if (
-    operation === 'POST' &&
-    object.path === '/collections/:collectionId/fragments'
-  ) {
-    return true
-  }
+    if (object === '/users') {
+      return true
+    }
 
-  // allow authenticate owners full pass for a collection
-  if (get(object, 'type') === 'collection') {
-    if (operation === 'PATCH') {
+    if (get(object, 'type') === 'collection') {
+      if (helpers.isOwner({ user, object })) {
+        return true
+      }
       return {
-        filter: collection => omit(collection, 'filtered'),
+        filter: async collection => {
+          const status = get(collection, 'status') || 'draft'
+          const userPermissions = await helpers.getUserPermissions({
+            user,
+            Team: context.models.Team,
+          })
+          if (collection.owners.map(o => o.id).includes(user.id)) {
+            return collection
+          }
+
+          const collectionPermission = userPermissions.find(
+            p => p.objectId === collection.id,
+          )
+          if (
+            publicStatusesPermissions.includes(
+              get(collectionPermission, 'role'),
+            )
+          ) {
+            collection.visibleStatus = statuses[status].public
+          }
+          return collection
+        },
       }
     }
-    if (object.owners.includes(user.id)) return true
-    const owner = object.owners.find(own => own.id === user.id)
-    if (owner !== undefined) return true
-  }
 
-  // Allow owners of a collection to GET its teams, e.g.
-  // GET /api/collections/1/teams
-  if (operation === 'GET' && get(object, 'path') === '/teams') {
-    const collectionId = get(object, 'params.collectionId')
-    if (collectionId) {
-      const collection = await context.models.Collection.find(collectionId)
-      if (collection.owners.includes(user.id)) {
+    if (get(object, 'type') === 'fragment') {
+      if (helpers.isOwner({ user, object })) {
         return true
       }
-    }
-  }
 
-  if (
-    operation === 'GET' &&
-    get(object, 'type') === 'team' &&
-    get(object, 'object.type') === 'collection'
-  ) {
-    const collection = await context.models.Collection.find(
-      get(object, 'object.id'),
-    )
-    if (collection.owners.includes(user.id)) {
-      return true
-    }
-  }
+      const userPermissions = await helpers.getUserPermissions({
+        user,
+        Team: context.models.Team,
+      })
 
-  // Advanced example
-  // Allow authenticated users to create a team based around a collection
-  // if they are one of the owners of this collection
-  if (['POST', 'PATCH'].includes(operation) && get(object, 'type') === 'team') {
-    if (get(object, 'object.type') === 'collection') {
-      const collection = await context.models.Collection.find(
-        get(object, 'object.id'),
+      const permission = userPermissions.find(
+        p => p.objectId === object.id || p.objectId === object.collectionId,
       )
-      if (collection.owners.includes(user.id)) {
+
+      if (!permission) return false
+
+      return {
+        filter: fragment => {
+          // handle other roles
+          if (permission.role === 'reviewer') {
+            fragment.files = omit(fragment.files, ['coverLetter'])
+            fragment.authors = fragment.authors.map(a => omit(a, ['email']))
+          }
+          return fragment
+        },
+      }
+    }
+
+    // allow HE to get reviewer invitations
+    if (get(object, 'fragment.type') === 'fragment') {
+      const collectionId = get(object, 'fragment.collectionId')
+      const collection = await context.models.Collection.find(collectionId)
+
+      if (get(collection, 'handlingEditor.id') === user.id) {
         return true
       }
     }
-  }
 
-  // only allow the HE to create, delete an invitation, or get invitation details
-  if (
-    ['POST', 'GET', 'DELETE'].includes(operation) &&
-    get(object.collection, 'type') === 'collection' &&
-    object.path.includes('invitations')
-  ) {
-    const collection = await context.models.Collection.find(
-      get(object.collection, 'id'),
-    )
-    const handlingEditor = get(collection, 'handlingEditor')
-    if (!handlingEditor) return false
-    if (handlingEditor.id === user.id) return true
-    return false
+    if (get(object, 'type') === 'user') {
+      return true
+    }
   }
 
-  // only allow a reviewer and an HE to submit and to modify a recommendation
-  if (
-    ['POST', 'PATCH'].includes(operation) &&
-    object.path.includes('recommendations')
-  ) {
-    const authsomeObject = get(object, 'authsomeObject')
-
-    const teams = await helpers.getTeamsByPermissions(
-      user.teams,
-      ['reviewer', 'handlingEditor'],
-      context.models.Team,
-    )
+  if (operation === 'POST') {
+    // allow everytone to create manuscripts and versions
+    if (createPaths.includes(object.path)) {
+      return true
+    }
 
-    if (teams.length === 0) return false
-    const matchingTeam = teams.find(
-      team => team.object.id === authsomeObject.id,
-    )
+    // allow HE to invite
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/invitations'
+    ) {
+      return helpers.isHandlingEditor({ user, object })
+    }
 
-    if (matchingTeam) return true
-    return false
+    // allow HE or assigned reviewers to recommend
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/recommendations'
+    ) {
+      return helpers.hasPermissionForObject({
+        user,
+        object,
+        Team: context.models.Team,
+        roles: ['reviewer', 'handlingEditor'],
+      })
+    }
   }
 
-  if (user.teams.length !== 0 && ['GET'].includes(operation)) {
-    const permissions = await teamPermissions(user, operation, object, context)
-
-    if (permissions) {
-      return permissions
+  if (operation === 'PATCH') {
+    if (get(object, 'type') === 'collection') {
+      return helpers.isOwner({ user, object })
     }
 
-    return false
-  }
+    if (get(object, 'type') === 'fragment') {
+      return helpers.isOwner({ user, object })
+    }
 
-  if (get(object, 'type') === 'fragment') {
-    const fragment = object
+    // allow reviewer to patch his recommendation
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/recommendations/:recommendationId'
+    ) {
+      return helpers.hasPermissionForObject({
+        user,
+        object,
+        Team: context.models.Team,
+        roles: ['reviewer'],
+      })
+    }
 
-    if (fragment.owners.includes(user.id)) {
+    if (get(object, 'type') === 'user' && get(object, 'id') === user.id) {
       return true
     }
   }
 
-  // A user can GET, DELETE and PATCH itself
-  if (get(object, 'type') === 'user' && get(object, 'id') === user.id) {
-    if (['GET', 'DELETE', 'PATCH'].includes(operation)) {
-      return true
+  if (operation === 'DELETE') {
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/invitations/:invitationId'
+    ) {
+      return helpers.isHandlingEditor({ user, object })
     }
   }
+
   // If no individual permissions exist (above), fallback to unauthenticated
   // user's permission
   return unauthenticatedUser(operation, object)
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
index e2dfc1a65..39ac00b46 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
@@ -17,9 +17,11 @@ module.exports = models => async (req, res) => {
       })
 
     fragment = await models.Fragment.find(fragmentId)
+
     const recommendation = fragment.recommendations.find(
       rec => rec.id === recommendationId,
     )
+
     if (!recommendation)
       return res.status(404).json({ error: 'Recommendation not found.' })
 
@@ -51,9 +53,11 @@ module.exports = models => async (req, res) => {
       })
       const baseUrl = services.getBaseUrl(req)
       const collectionHelper = new Collection({ collection })
+
       const authors = await fragmentHelper.getAuthorData({
         UserModel,
       })
+
       const email = new Email({
         UserModel,
         collection,
@@ -61,14 +65,16 @@ module.exports = models => async (req, res) => {
         baseUrl,
         authors,
       })
+
       email.setupHandlingEditorEmail({
         reviewSubmitted: true,
         reviewerName: `${user.firstName} ${user.lastName}`,
       })
+
       if (!['pendingApproval', 'revisionRequested'].includes(collection.status))
         collectionHelper.updateStatus({ newStatus: 'reviewCompleted' })
     }
-    await fragment.save()
+    fragment.save()
     return res.status(200).json(recommendation)
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'Item')
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
index 29e3bec20..302b95124 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
@@ -24,7 +24,6 @@ module.exports = models => async (req, res) => {
       return res.status(400).json({
         error: `Collection and fragment do not match.`,
       })
-
     fragment = await models.Fragment.find(fragmentId)
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'Item')
@@ -32,6 +31,7 @@ module.exports = models => async (req, res) => {
       error: notFoundError.message,
     })
   }
+
   const authsome = authsomeHelper.getAuthsome(models)
   const target = {
     fragment,
@@ -42,6 +42,7 @@ module.exports = models => async (req, res) => {
     return res.status(403).json({
       error: 'Unauthorized.',
     })
+
   fragment.recommendations = fragment.recommendations || []
   const newRecommendation = {
     id: uuid.v4(),
@@ -59,8 +60,10 @@ module.exports = models => async (req, res) => {
   const parsedFragment = await fragmentHelper.getFragmentData({
     handlingEditor: collection.handlingEditor,
   })
+
   const baseUrl = services.getBaseUrl(req)
   const authors = await fragmentHelper.getAuthorData({ UserModel })
+
   const email = new Email({
     UserModel,
     collection,
@@ -69,6 +72,7 @@ module.exports = models => async (req, res) => {
     authors,
   })
   const FragmentModel = models.Fragment
+
   if (reqUser.editorInChief || reqUser.admin) {
     if (recommendation === 'return-to-handling-editor') {
       collectionHelper.updateStatus({ newStatus: 'reviewCompleted' })
@@ -120,7 +124,6 @@ module.exports = models => async (req, res) => {
       })
     }
   }
-
   fragment.recommendations.push(newRecommendation)
   await fragment.save()
   return res.status(200).json(newRecommendation)
diff --git a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
index 30f7ee90b..c0c33bd5e 100644
--- a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
@@ -57,7 +57,7 @@ describe('Post fragments recommendations route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.error).toEqual('Recommendation type is required.')
   })
-  it('should return success when the parameters are correct', async () => {
+  it('should return success when creating a recommendation as a reviewer', async () => {
     const { reviewer } = testFixtures.users
     const { collection } = testFixtures.collections
     const { fragment } = testFixtures.fragments
@@ -78,6 +78,27 @@ describe('Post fragments recommendations route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.userId).toEqual(reviewer.id)
   })
+  it('should return success when creating a recommendation as a HE', async () => {
+    const { handlingEditor } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+
+    const res = await requests.sendRequest({
+      body,
+      userId: handlingEditor.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+    expect(data.userId).toEqual(handlingEditor.id)
+  })
   it('should return an error when the fragmentId does not match the collectionId', async () => {
     const { reviewer } = testFixtures.users
     const { collection } = testFixtures.collections
diff --git a/packages/component-user-manager/config/authsome-helpers.js b/packages/component-user-manager/config/authsome-helpers.js
index 164a9ce8a..55148df34 100644
--- a/packages/component-user-manager/config/authsome-helpers.js
+++ b/packages/component-user-manager/config/authsome-helpers.js
@@ -59,8 +59,12 @@ const filterObjectData = (
   return object
 }
 
-const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => {
-  const teams = await Promise.all(
+const getTeamsByPermissions = async (
+  teamIds = [],
+  permissions = [],
+  TeamModel,
+) =>
+  (await Promise.all(
     teamIds.map(async teamId => {
       const team = await TeamModel.find(teamId)
       if (!permissions.includes(team.teamType.permissions)) {
@@ -68,15 +72,60 @@ const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => {
       }
       return team
     }),
+  )).filter(Boolean)
+
+const heIsInvitedToFragment = async ({ user, Team, collectionId }) =>
+  (await getTeamsByPermissions(user.teams, ['handlingEditor'], Team)).some(
+    // user is a member of the team with access to the fragment's parent collection
+    t => t.members.includes(user.id) && t.object.id === collectionId,
   )
 
-  return teams.filter(Boolean)
+const getUserPermissions = async ({
+  user,
+  Team,
+  mapFn = t => ({
+    objectId: t.object.id,
+    objectType: t.object.type,
+    role: t.teamType.permissions,
+  }),
+}) =>
+  (await Promise.all(user.teams.map(teamId => Team.find(teamId)))).map(mapFn)
+
+const isOwner = ({ user: { id }, object }) => {
+  if (object.owners.includes(id)) return true
+  return !!object.owners.find(own => own.id === id)
+}
+
+const hasPermissionForObject = async ({ user, object, Team, roles = [] }) => {
+  const userPermissions = await getUserPermissions({
+    user,
+    Team,
+  })
+
+  return !!userPermissions.find(p => {
+    const hasObject =
+      p.objectId === get(object, 'fragment.id') ||
+      p.objectId === get(object, 'fragment.collectionId')
+    if (roles.length > 0) {
+      return hasObject && roles.includes(p.role)
+    }
+    return hasObject
+  })
 }
 
+const isHandlingEditor = ({ user, object }) =>
+  get(object, 'collection.handlingEditor.id') === user.id
+
 module.exports = {
+  filterObjectData,
   parseAuthorsData,
   setPublicStatuses,
-  filterRefusedInvitations,
-  filterObjectData,
   getTeamsByPermissions,
+  filterRefusedInvitations,
+  //
+  isOwner,
+  isHandlingEditor,
+  getUserPermissions,
+  heIsInvitedToFragment,
+  hasPermissionForObject,
 }
diff --git a/packages/component-user-manager/config/authsome-mode.js b/packages/component-user-manager/config/authsome-mode.js
index 8a92a1301..20e0d6918 100644
--- a/packages/component-user-manager/config/authsome-mode.js
+++ b/packages/component-user-manager/config/authsome-mode.js
@@ -1,69 +1,8 @@
-const get = require('lodash/get')
-const pickBy = require('lodash/pickBy')
-const omit = require('lodash/omit')
-const helpers = require('./authsome-helpers')
-
-async function teamPermissions(user, operation, object, context) {
-  const { models } = context
-  const permissions = ['handlingEditor', 'author', 'reviewer']
-  const teams = await helpers.getTeamsByPermissions(
-    user.teams,
-    permissions,
-    context.models.Team,
-  )
-
-  let collectionsPermissions = await Promise.all(
-    teams.map(async team => {
-      let collection
-      if (team.object.type === 'collection') {
-        collection = await models.Collection.find(team.object.id)
-      } else if (team.object.type === 'fragment') {
-        const fragment = await models.Fragment.find(team.object.id)
-        collection = await models.Collection.find(fragment.collectionId)
-      }
-      if (
-        collection.status === 'rejected' &&
-        team.teamType.permissions === 'reviewer'
-      )
-        return null
-      const collPerm = {
-        id: collection.id,
-        permission: team.teamType.permissions,
-      }
-      const objectType = get(object, 'type')
-      if (objectType === 'fragment') {
-        if (collection.fragments.includes(object.id))
-          collPerm.fragmentId = object.id
-        else return null
-      }
-
-      if (objectType === 'collection')
-        if (object.id !== collection.id) return null
-      return collPerm
-    }),
-  )
-  collectionsPermissions = collectionsPermissions.filter(cp => cp !== null)
-  if (collectionsPermissions.length === 0) return false
-
-  return {
-    filter: filterParam => {
-      if (!filterParam.length) {
-        return helpers.filterObjectData(
-          collectionsPermissions,
-          filterParam,
-          user,
-        )
-      }
+const config = require('config')
+const { get, pickBy, omit } = require('lodash')
 
-      const collections = filterParam
-        .map(coll =>
-          helpers.filterObjectData(collectionsPermissions, coll, user),
-        )
-        .filter(Boolean)
-      return collections
-    },
-  }
-}
+const statuses = config.get('statuses')
+const helpers = require('./authsome-helpers')
 
 function unauthenticatedUser(operation, object) {
   // Public/unauthenticated users can GET /collections, filtered by 'published'
@@ -111,133 +50,182 @@ function unauthenticatedUser(operation, object) {
   return false
 }
 
+const publicStatusesPermissions = ['author', 'reviewer']
+const createPaths = ['/collections', '/collections/:collectionId/fragments']
+
 async function authenticatedUser(user, operation, object, context) {
-  // Allow the authenticated user to POST a collection (but not with a 'filtered' property)
-  if (operation === 'POST' && object.path === '/collections') {
-    return {
-      filter: collection => omit(collection, 'filtered'),
+  if (operation === 'GET') {
+    if (get(object, 'path') === '/collections') {
+      return {
+        filter: async collections => {
+          const userPermissions = await helpers.getUserPermissions({
+            user,
+            Team: context.models.Team,
+          })
+          return collections.filter(collection => {
+            if (collection.owners.includes(user.id)) {
+              return true
+            }
+            const collectionPermission = userPermissions.find(
+              p => p.objectId === collection.id,
+            )
+            if (collectionPermission) {
+              return true
+            }
+
+            const fragmentPermission = userPermissions.find(p =>
+              collection.fragments.includes(p.objectId),
+            )
+            if (fragmentPermission) {
+              return true
+            }
+            return false
+          })
+        },
+      }
     }
-  }
 
-  if (
-    operation === 'POST' &&
-    object.path === '/collections/:collectionId/fragments'
-  ) {
-    return true
-  }
+    if (object === '/users') {
+      return true
+    }
 
-  // allow authenticate owners full pass for a collection
-  if (get(object, 'type') === 'collection') {
-    if (operation === 'PATCH') {
+    if (get(object, 'type') === 'collection') {
+      if (helpers.isOwner({ user, object })) {
+        return true
+      }
       return {
-        filter: collection => omit(collection, 'filtered'),
+        filter: async collection => {
+          const status = get(collection, 'status') || 'draft'
+          const userPermissions = await helpers.getUserPermissions({
+            user,
+            Team: context.models.Team,
+          })
+          if (collection.owners.map(o => o.id).includes(user.id)) {
+            return collection
+          }
+
+          const collectionPermission = userPermissions.find(
+            p => p.objectId === collection.id,
+          )
+          if (
+            publicStatusesPermissions.includes(
+              get(collectionPermission, 'role'),
+            )
+          ) {
+            collection.visibleStatus = statuses[status].public
+          }
+          return collection
+        },
       }
     }
-    if (object.owners.includes(user.id)) return true
-    const owner = object.owners.find(own => own.id === user.id)
-    if (owner !== undefined) return true
-  }
 
-  // Allow owners of a collection to GET its teams, e.g.
-  // GET /api/collections/1/teams
-  if (operation === 'GET' && get(object, 'path') === '/teams') {
-    const collectionId = get(object, 'params.collectionId')
-    if (collectionId) {
-      const collection = await context.models.Collection.find(collectionId)
-      if (collection.owners.includes(user.id)) {
+    if (get(object, 'type') === 'fragment') {
+      if (helpers.isOwner({ user, object })) {
         return true
       }
-    }
-  }
 
-  if (
-    operation === 'GET' &&
-    get(object, 'type') === 'team' &&
-    get(object, 'object.type') === 'collection'
-  ) {
-    const collection = await context.models.Collection.find(
-      get(object, 'object.id'),
-    )
-    if (collection.owners.includes(user.id)) {
-      return true
-    }
-  }
+      const userPermissions = await helpers.getUserPermissions({
+        user,
+        Team: context.models.Team,
+      })
 
-  // Advanced example
-  // Allow authenticated users to create a team based around a collection
-  // if they are one of the owners of this collection
-  if (['POST', 'PATCH'].includes(operation) && get(object, 'type') === 'team') {
-    if (get(object, 'object.type') === 'collection') {
-      const collection = await context.models.Collection.find(
-        get(object, 'object.id'),
+      const permission = userPermissions.find(
+        p => p.objectId === object.id || p.objectId === object.collectionId,
       )
-      if (collection.owners.includes(user.id)) {
+
+      if (!permission) return false
+
+      return {
+        filter: fragment => {
+          // handle other roles
+          if (permission.role === 'reviewer') {
+            fragment.files = omit(fragment.files, ['coverLetter'])
+            fragment.authors = fragment.authors.map(a => omit(a, ['email']))
+          }
+          return fragment
+        },
+      }
+    }
+
+    // allow HE to get reviewer invitations
+    if (get(object, 'fragment.type') === 'fragment') {
+      const collectionId = get(object, 'fragment.collectionId')
+      const collection = await context.models.Collection.find(collectionId)
+
+      if (get(collection, 'handlingEditor.id') === user.id) {
         return true
       }
     }
-  }
 
-  // only allow the HE to create, delete an invitation, or get invitation details
-  if (
-    ['POST', 'GET', 'DELETE'].includes(operation) &&
-    get(object.collection, 'type') === 'collection' &&
-    object.path.includes('invitations')
-  ) {
-    const collection = await context.models.Collection.find(
-      get(object.collection, 'id'),
-    )
-    const handlingEditor = get(collection, 'handlingEditor')
-    if (!handlingEditor) return false
-    if (handlingEditor.id === user.id) return true
-    return false
+    if (get(object, 'type') === 'user') {
+      return true
+    }
   }
 
-  // only allow a reviewer and an HE to submit and to modify a recommendation
-  if (
-    ['POST', 'PATCH'].includes(operation) &&
-    object.path.includes('recommendations')
-  ) {
-    const authsomeObject = get(object, 'authsomeObject')
-
-    const teams = await helpers.getTeamsByPermissions(
-      user.teams,
-      ['reviewer', 'handlingEditor'],
-      context.models.Team,
-    )
+  if (operation === 'POST') {
+    // allow everytone to create manuscripts and versions
+    if (createPaths.includes(object.path)) {
+      return true
+    }
 
-    if (teams.length === 0) return false
-    const matchingTeam = teams.find(
-      team => team.object.id === authsomeObject.id,
-    )
+    // allow HE to invite
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/invitations'
+    ) {
+      return helpers.isHandlingEditor({ user, object })
+    }
 
-    if (matchingTeam) return true
-    return false
+    // allow HE or assigned reviewers to recommend
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/recommendations'
+    ) {
+      return helpers.hasPermissionForObject({
+        user,
+        object,
+        Team: context.models.Team,
+        roles: ['reviewer', 'handlingEditor'],
+      })
+    }
   }
 
-  if (user.teams.length !== 0 && ['GET'].includes(operation)) {
-    const permissions = await teamPermissions(user, operation, object, context)
-
-    if (permissions) {
-      return permissions
+  if (operation === 'PATCH') {
+    if (get(object, 'type') === 'collection') {
+      return helpers.isOwner({ user, object })
     }
 
-    return false
-  }
+    if (get(object, 'type') === 'fragment') {
+      return helpers.isOwner({ user, object })
+    }
 
-  if (get(object, 'type') === 'fragment') {
-    const fragment = object
+    // allow reviewer to patch his recommendation
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/recommendations/:recommendationId'
+    ) {
+      return helpers.hasPermissionForObject({
+        user,
+        object,
+        Team: context.models.Team,
+        roles: ['reviewer'],
+      })
+    }
 
-    if (fragment.owners.includes(user.id)) {
+    if (get(object, 'type') === 'user' && get(object, 'id') === user.id) {
       return true
     }
   }
 
-  // A user can GET, DELETE and PATCH itself
-  if (get(object, 'type') === 'user' && get(object, 'id') === user.id) {
-    if (['GET', 'DELETE', 'PATCH'].includes(operation)) {
-      return true
+  if (operation === 'DELETE') {
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/invitations/:invitationId'
+    ) {
+      return helpers.isHandlingEditor({ user, object })
     }
   }
+
   // If no individual permissions exist (above), fallback to unauthenticated
   // user's permission
   return unauthenticatedUser(operation, object)
diff --git a/packages/component-user-manager/src/FragmentsUsers.js b/packages/component-user-manager/src/FragmentsUsers.js
index d1137db20..443397a6f 100644
--- a/packages/component-user-manager/src/FragmentsUsers.js
+++ b/packages/component-user-manager/src/FragmentsUsers.js
@@ -23,19 +23,12 @@ const FragmentsUsers = app => {
    *    HTTP/1.1 200 OK
    *    {
    *      "id": "a6184463-b17a-42f8-b02b-ae1d755cdc6b",
-   *      "type": "user",
-   *      "admin": false,
    *      "email": "email@example.com",
-   *      "teams": [
-   *        "c576695a-7cda-4e27-8e9c-31f3a0e9d592"
-   *      ],
-   *      "username": "email@example.com",
-   *      "fragments": [],
-   *      "collections": [],
-   *      "isConfirmed": false,
-   *      "editorInChief": false,
-   *      "handlingEditor": false,
-   *      "passwordResetToken": "04590a2b7f6c1f37cb84881d529e516fa6fc309c205a07f1341b2bfaa6f2b46c"
+   *      "firstName": "John",
+   *      "lastName": "Smith",
+   *      "affiliation": "MIT",
+   *      "isSubmitting": true,
+   *      "isCorresponding": false
    *    }
    * @apiErrorExample {json} Invite user errors
    *    HTTP/1.1 400 Bad Request
diff --git a/packages/component-user-manager/src/routes/fragmentsUsers/post.js b/packages/component-user-manager/src/routes/fragmentsUsers/post.js
index 06740101e..8dc8df3ed 100644
--- a/packages/component-user-manager/src/routes/fragmentsUsers/post.js
+++ b/packages/component-user-manager/src/routes/fragmentsUsers/post.js
@@ -63,7 +63,7 @@ module.exports = models => async (req, res) => {
     user = await UserModel.find(user.id)
 
     fragment.authors = fragment.authors || []
-    const match = fragment.authors.find(author => author.userId === user.id)
+    const match = fragment.authors.find(author => author.id === user.id)
 
     if (match) {
       return res.status(400).json({
diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js
index 3373de304..658f47bb6 100644
--- a/packages/xpub-faraday/config/authsome-helpers.js
+++ b/packages/xpub-faraday/config/authsome-helpers.js
@@ -96,17 +96,21 @@ const isOwner = ({ user: { id }, object }) => {
   return !!object.owners.find(own => own.id === id)
 }
 
-const hasPermissionForObject = async ({ user, object, Team }) => {
+const hasPermissionForObject = async ({ user, object, Team, roles = [] }) => {
   const userPermissions = await getUserPermissions({
     user,
     Team,
   })
 
-  return !!userPermissions.find(
-    p =>
+  return !!userPermissions.find(p => {
+    const hasObject =
       p.objectId === get(object, 'fragment.id') ||
-      p.objectId === get(object, 'fragment.collectionId'),
-  )
+      p.objectId === get(object, 'fragment.collectionId')
+    if (roles.length > 0) {
+      return hasObject && roles.includes(p.role)
+    }
+    return hasObject
+  })
 }
 
 const isHandlingEditor = ({ user, object }) =>
@@ -118,7 +122,6 @@ module.exports = {
   setPublicStatuses,
   getTeamsByPermissions,
   filterRefusedInvitations,
-  //
   isOwner,
   isHandlingEditor,
   getUserPermissions,
diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js
index 37e4ff7da..20e0d6918 100644
--- a/packages/xpub-faraday/config/authsome-mode.js
+++ b/packages/xpub-faraday/config/authsome-mode.js
@@ -185,6 +185,7 @@ async function authenticatedUser(user, operation, object, context) {
         user,
         object,
         Team: context.models.Team,
+        roles: ['reviewer', 'handlingEditor'],
       })
     }
   }
@@ -207,6 +208,7 @@ async function authenticatedUser(user, operation, object, context) {
         user,
         object,
         Team: context.models.Team,
+        roles: ['reviewer'],
       })
     }
 
-- 
GitLab