UserMembershipHandler.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. const { ObjectId } = require('mongodb')
  2. const { promisifyAll, callbackify } = require('@overleaf/promise-utils')
  3. const EntityModels = {
  4. Institution: require('../../models/Institution').Institution,
  5. Subscription: require('../../models/Subscription').Subscription,
  6. Publisher: require('../../models/Publisher').Publisher,
  7. }
  8. const UserMembershipViewModel = require('./UserMembershipViewModel')
  9. const UserGetter = require('../User/UserGetter')
  10. const {
  11. UserIsManagerError,
  12. UserNotFoundError,
  13. UserAlreadyAddedError,
  14. } = require('./UserMembershipErrors')
  15. const UserMembershipHandler = {
  16. async getEntityWithoutAuthorizationCheck(entityId, entityConfig) {
  17. const query = buildEntityQuery(entityId, entityConfig)
  18. return await EntityModels[entityConfig.modelName].findOne(query).exec()
  19. },
  20. async createEntity(entityId, entityConfig) {
  21. const data = buildEntityQuery(entityId, entityConfig)
  22. return await EntityModels[entityConfig.modelName].create(data).exec()
  23. },
  24. async getUsers(entity, entityConfig) {
  25. const attributes = entityConfig.fields.read
  26. return await getPopulatedListOfMembers(entity, attributes)
  27. },
  28. async addUser(entity, entityConfig, email) {
  29. const attribute = entityConfig.fields.write
  30. const user = await UserGetter.promises.getUserByAnyEmail(email)
  31. if (!user) {
  32. throw new UserNotFoundError()
  33. }
  34. if (entity[attribute].some(managerId => managerId.equals(user._id))) {
  35. throw new UserAlreadyAddedError()
  36. }
  37. await addUserToEntity(entity, attribute, user)
  38. return UserMembershipViewModel.build(user)
  39. },
  40. async removeUser(entity, entityConfig, userId) {
  41. const attribute = entityConfig.fields.write
  42. if (entity.admin_id ? entity.admin_id.equals(userId) : undefined) {
  43. throw new UserIsManagerError()
  44. }
  45. return await removeUserFromEntity(entity, attribute, userId)
  46. },
  47. }
  48. UserMembershipHandler.promises = promisifyAll(UserMembershipHandler)
  49. module.exports = {
  50. getEntityWithoutAuthorizationCheck: callbackify(
  51. UserMembershipHandler.getEntityWithoutAuthorizationCheck
  52. ),
  53. createEntity: callbackify(UserMembershipHandler.createEntity),
  54. getUsers: callbackify(UserMembershipHandler.getUsers),
  55. addUser: callbackify(UserMembershipHandler.addUser),
  56. removeUser: callbackify(UserMembershipHandler.removeUser),
  57. promises: UserMembershipHandler,
  58. }
  59. async function getPopulatedListOfMembers(entity, attributes) {
  60. const userObjects = []
  61. for (const attribute of attributes) {
  62. for (const userObject of entity[attribute] || []) {
  63. // userObject can be an email as String, a user id as ObjectId or an
  64. // invite as Object with an email attribute as String. We want to pass to
  65. // UserMembershipViewModel either an email as (String) or a user id (ObjectId)
  66. const userIdOrEmail = userObject.email || userObject
  67. userObjects.push(userIdOrEmail)
  68. }
  69. }
  70. const users = await Promise.all(
  71. userObjects.map(userObject =>
  72. UserMembershipViewModel.promises.buildAsync(userObject)
  73. )
  74. )
  75. for (const user of users) {
  76. if (
  77. user?._id &&
  78. entity?.admin_id &&
  79. user._id.toString() === entity.admin_id.toString()
  80. ) {
  81. user.isEntityAdmin = true
  82. }
  83. }
  84. return users
  85. }
  86. async function addUserToEntity(entity, attribute, user) {
  87. const fieldUpdate = {}
  88. fieldUpdate[attribute] = user._id
  89. return await entity.updateOne({ $addToSet: fieldUpdate }).exec()
  90. }
  91. async function removeUserFromEntity(entity, attribute, userId) {
  92. const fieldUpdate = {}
  93. fieldUpdate[attribute] = userId
  94. return await entity.updateOne({ $pull: fieldUpdate }).exec()
  95. }
  96. function buildEntityQuery(entityId, entityConfig) {
  97. if (ObjectId.isValid(entityId.toString())) {
  98. entityId = new ObjectId(entityId)
  99. }
  100. const query = Object.assign({}, entityConfig.baseQuery)
  101. query[entityConfig.fields.primaryKey] = entityId
  102. return query
  103. }