| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- const logger = require('@overleaf/logger')
- const { Project } = require('../../models/Project')
- const ProjectGetter = require('../Project/ProjectGetter')
- const UserGetter = require('../User/UserGetter')
- const CollaboratorsHandler = require('./CollaboratorsHandler')
- const EmailHandler = require('../Email/EmailHandler')
- const Errors = require('../Errors/Errors')
- const PrivilegeLevels = require('../Authorization/PrivilegeLevels')
- const TpdsProjectFlusher = require('../ThirdPartyDataStore/TpdsProjectFlusher')
- const ProjectAuditLogHandler = require('../Project/ProjectAuditLogHandler')
- const AnalyticsManager = require('../Analytics/AnalyticsManager')
- module.exports = {
- promises: { transferOwnership },
- }
- async function transferOwnership(projectId, newOwnerId, options = {}) {
- const { allowTransferToNonCollaborators, sessionUserId } = options
- // Fetch project and user
- const [project, newOwner] = await Promise.all([
- _getProject(projectId),
- _getUser(newOwnerId),
- ])
- // Exit early if the transferee is already the project owner
- const previousOwnerId = project.owner_ref
- if (previousOwnerId.equals(newOwnerId)) {
- return
- }
- // Check that user is already a collaborator
- if (
- !allowTransferToNonCollaborators &&
- !_userIsCollaborator(newOwner, project)
- ) {
- throw new Errors.UserNotCollaboratorError({ info: { userId: newOwnerId } })
- }
- // Track the change of ownership in BigQuery.
- AnalyticsManager.recordEventForUser(
- previousOwnerId,
- 'project-ownership-transfer',
- { projectId, newOwnerId }
- )
- // Transfer ownership
- await ProjectAuditLogHandler.promises.addEntry(
- projectId,
- 'transfer-ownership',
- sessionUserId,
- { previousOwnerId, newOwnerId }
- )
- await _transferOwnership(projectId, previousOwnerId, newOwnerId)
- // Flush project to TPDS
- await TpdsProjectFlusher.promises.flushProjectToTpds(projectId)
- // Send confirmation emails
- const previousOwner = await UserGetter.promises.getUser(previousOwnerId)
- await _sendEmails(project, previousOwner, newOwner)
- }
- async function _getProject(projectId) {
- const project = await ProjectGetter.promises.getProject(projectId, {
- owner_ref: 1,
- collaberator_refs: 1,
- name: 1,
- })
- if (project == null) {
- throw new Errors.ProjectNotFoundError({ info: { projectId } })
- }
- return project
- }
- async function _getUser(userId) {
- const user = await UserGetter.promises.getUser(userId)
- if (user == null) {
- throw new Errors.UserNotFoundError({ info: { userId } })
- }
- return user
- }
- function _userIsCollaborator(user, project) {
- const collaboratorIds = project.collaberator_refs || []
- return collaboratorIds.some(collaboratorId => collaboratorId.equals(user._id))
- }
- async function _transferOwnership(projectId, previousOwnerId, newOwnerId) {
- await CollaboratorsHandler.promises.removeUserFromProject(
- projectId,
- newOwnerId
- )
- await Project.updateOne(
- { _id: projectId },
- { $set: { owner_ref: newOwnerId } }
- ).exec()
- await CollaboratorsHandler.promises.addUserIdToProject(
- projectId,
- newOwnerId,
- previousOwnerId,
- PrivilegeLevels.READ_AND_WRITE
- )
- }
- async function _sendEmails(project, previousOwner, newOwner) {
- if (previousOwner == null) {
- // The previous owner didn't exist. This is not supposed to happen, but
- // since we're changing the owner anyway, we'll just warn
- logger.warn(
- { projectId: project._id, ownerId: previousOwner._id },
- 'Project owner did not exist before ownership transfer'
- )
- } else {
- // Send confirmation emails
- await Promise.all([
- EmailHandler.promises.sendEmail(
- 'ownershipTransferConfirmationPreviousOwner',
- {
- to: previousOwner.email,
- project,
- newOwner,
- }
- ),
- EmailHandler.promises.sendEmail('ownershipTransferConfirmationNewOwner', {
- to: newOwner.email,
- project,
- previousOwner,
- }),
- ])
- }
- }
|