| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import mongodb from 'mongodb-legacy'
- import { callbackify } from '@overleaf/promise-utils'
- import { Institution } from '../../models/Institution.mjs'
- import { Subscription } from '../../models/Subscription.mjs'
- import { Publisher } from '../../models/Publisher.mjs'
- import UserMembershipViewModel from './UserMembershipViewModel.mjs'
- import UserGetter from '../User/UserGetter.mjs'
- import UserMembershipErrors from './UserMembershipErrors.mjs'
- import Modules from '../../infrastructure/Modules.mjs'
- import mongoose from '../../infrastructure/Mongoose.mjs'
- const { ObjectId } = mongodb
- const EntityModels = { Institution, Subscription, Publisher }
- const UserMembershipHandler = {
- async getEntityWithoutAuthorizationCheck(entityId, entityConfig) {
- const query = buildEntityQuery(entityId, entityConfig)
- return await EntityModels[entityConfig.modelName].findOne(query).exec()
- },
- async createEntity(entityId, entityConfig) {
- const data = buildEntityQuery(entityId, entityConfig)
- return await EntityModels[entityConfig.modelName].create(data)
- },
- async getUsers(entity, entityConfig) {
- const attributes = entityConfig.fields.read
- return await getPopulatedListOfMembers(entity, attributes)
- },
- async addUser(entity, entityConfig, email, auditInfo) {
- const attribute = entityConfig.fields.write
- const user = await UserGetter.promises.getUserByAnyEmail(email)
- if (!user) {
- throw new UserMembershipErrors.UserNotFoundError()
- }
- if (entity[attribute].some(managerId => managerId.equals(user._id))) {
- throw new UserMembershipErrors.UserAlreadyAddedError()
- }
- // if the entity is a Subscription with managed users enabled, then audit log the event
- if (
- entityConfig.modelName === 'Subscription' &&
- entity.managedUsersEnabled
- ) {
- const session = await mongoose.startSession()
- try {
- await session.withTransaction(async () => {
- const auditLog = {
- groupId: entity._id,
- operation: 'group-role-changed',
- initiatorId: auditInfo.initiatorId,
- ipAddress: auditInfo.ipAddress,
- info: {
- userId: user._id,
- role: 'manager',
- },
- }
- await Modules.promises.hooks.fire(
- 'addGroupAuditLogEntry',
- auditLog,
- session
- )
- })
- } finally {
- await session.endSession()
- }
- }
- await addUserToEntity(entity, attribute, user)
- return UserMembershipViewModel.build(user)
- },
- async removeUser(entity, entityConfig, userId, auditInfo) {
- const attribute = entityConfig.fields.write
- if (entity.admin_id ? entity.admin_id.equals(userId) : undefined) {
- throw new UserMembershipErrors.UserIsManagerError()
- }
- // if the entity is a Subscription with managed users enabled, then audit log the event
- if (
- entityConfig.modelName === 'Subscription' &&
- entity.managedUsersEnabled
- ) {
- const auditLog = {
- groupId: entity._id,
- operation: 'group-role-changed',
- initiatorId: auditInfo.initiatorId,
- ipAddress: auditInfo.ipAddress,
- info: {
- userId,
- role: 'member',
- },
- }
- await Modules.promises.hooks.fire('addGroupAuditLogEntry', auditLog)
- }
- return await removeUserFromEntity(entity, attribute, userId)
- },
- }
- async function getPopulatedListOfMembers(entity, attributes) {
- const userObjects = []
- for (const attribute of attributes) {
- for (const userObject of entity[attribute] || []) {
- // userObject can be an email as String, a user id as ObjectId or an
- // invite as Object with an email attribute as String. We want to pass to
- // UserMembershipViewModel either an email as (String) or a user id (ObjectId)
- const userIdOrEmail = userObject.email || userObject
- userObjects.push(userIdOrEmail)
- }
- }
- const users = await UserMembershipViewModel.promises.buildAsync(userObjects)
- for (const user of users) {
- if (
- user?._id &&
- entity?.admin_id &&
- user._id.toString() === entity.admin_id.toString()
- ) {
- user.isEntityAdmin = true
- }
- if (
- user?._id &&
- entity?.manager_ids &&
- entity.manager_ids.includes(user._id)
- ) {
- user.isEntityManager = true
- }
- if (
- user?._id &&
- entity?.member_ids &&
- entity.member_ids.includes(user._id)
- ) {
- user.isEntityMember = true
- }
- }
- return users
- }
- async function addUserToEntity(entity, attribute, user) {
- const fieldUpdate = {}
- fieldUpdate[attribute] = user._id
- return await entity.updateOne({ $addToSet: fieldUpdate }).exec()
- }
- async function removeUserFromEntity(entity, attribute, userId) {
- const fieldUpdate = {}
- fieldUpdate[attribute] = userId
- return await entity.updateOne({ $pull: fieldUpdate }).exec()
- }
- function buildEntityQuery(entityId, entityConfig) {
- if (ObjectId.isValid(entityId.toString())) {
- entityId = new ObjectId(entityId)
- }
- const query = Object.assign({}, entityConfig.baseQuery)
- query[entityConfig.fields.primaryKey] = entityId
- return query
- }
- export default {
- getEntityWithoutAuthorizationCheck: callbackify(
- UserMembershipHandler.getEntityWithoutAuthorizationCheck
- ),
- createEntity: callbackify(UserMembershipHandler.createEntity),
- getUsers: callbackify(UserMembershipHandler.getUsers),
- addUser: callbackify(UserMembershipHandler.addUser),
- removeUser: callbackify(UserMembershipHandler.removeUser),
- promises: UserMembershipHandler,
- }
|