| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- const { callbackify } = require('util')
- const request = require('request-promise-native')
- const settings = require('@overleaf/settings')
- const OError = require('@overleaf/o-error')
- const UserGetter = require('../User/UserGetter')
- module.exports = {
- initializeProject: callbackify(initializeProject),
- flushProject: callbackify(flushProject),
- resyncProject: callbackify(resyncProject),
- deleteProject: callbackify(deleteProject),
- deleteProjectHistory: callbackify(deleteProjectHistory),
- injectUserDetails: callbackify(injectUserDetails),
- promises: {
- initializeProject,
- flushProject,
- resyncProject,
- deleteProject,
- injectUserDetails,
- deleteProjectHistory,
- },
- }
- async function initializeProject() {
- if (
- !(
- settings.apis.project_history &&
- settings.apis.project_history.initializeHistoryForNewProjects
- )
- ) {
- return
- }
- try {
- const body = await request.post({
- url: `${settings.apis.project_history.url}/project`,
- })
- const project = JSON.parse(body)
- const overleafId = project && project.project && project.project.id
- if (!overleafId) {
- throw new Error('project-history did not provide an id', project)
- }
- return { overleaf_id: overleafId }
- } catch (err) {
- throw OError.tag(err, 'failed to initialize project history')
- }
- }
- async function flushProject(projectId) {
- try {
- await request.post({
- url: `${settings.apis.project_history.url}/project/${projectId}/flush`,
- })
- } catch (err) {
- throw OError.tag(err, 'failed to flush project to project history', {
- projectId,
- })
- }
- }
- async function deleteProjectHistory(projectId) {
- try {
- await request.delete({
- url: `${settings.apis.project_history.url}/project/${projectId}`,
- })
- } catch (err) {
- throw OError.tag(err, 'failed to delete project history', {
- projectId,
- })
- }
- }
- async function resyncProject(projectId, force = false) {
- try {
- await request.post({
- url: `${settings.apis.project_history.url}/project/${projectId}/resync`,
- qs: { force }, // TODO: only send if true?
- })
- } catch (err) {
- throw OError.tag(err, 'failed to resync project history', { projectId })
- }
- }
- async function deleteProject(projectId, historyId) {
- try {
- const tasks = [
- request.delete(
- `${settings.apis.project_history.url}/project/${projectId}`
- ),
- ]
- if (historyId != null) {
- tasks.push(
- request.delete({
- url: `${settings.apis.v1_history.url}/projects/${historyId}`,
- auth: {
- user: settings.apis.v1_history.user,
- pass: settings.apis.v1_history.pass,
- },
- })
- )
- }
- await Promise.all(tasks)
- } catch (err) {
- throw OError.tag(err, 'failed to clear project history', {
- projectId,
- historyId,
- })
- }
- }
- async function injectUserDetails(data) {
- // data can be either:
- // {
- // diff: [{
- // i: "foo",
- // meta: {
- // users: ["user_id", v1_user_id, ...]
- // ...
- // }
- // }, ...]
- // }
- // or
- // {
- // updates: [{
- // pathnames: ["main.tex"]
- // meta: {
- // users: ["user_id", v1_user_id, ...]
- // ...
- // },
- // ...
- // }, ...]
- // }
- // Either way, the top level key points to an array of objects with a meta.users property
- // that we need to replace user_ids with populated user objects.
- // Note that some entries in the users arrays may be v1 ids returned by the v1 history
- // service. v1 ids will be `numbers`
- let userIds = new Set()
- let v1UserIds = new Set()
- const entries = Array.isArray(data.diff)
- ? data.diff
- : Array.isArray(data.updates)
- ? data.updates
- : []
- for (const entry of entries) {
- for (const user of (entry.meta && entry.meta.users) || []) {
- if (typeof user === 'string') {
- userIds.add(user)
- } else if (typeof user === 'number') {
- v1UserIds.add(user)
- }
- }
- }
- userIds = Array.from(userIds)
- v1UserIds = Array.from(v1UserIds)
- const projection = { first_name: 1, last_name: 1, email: 1 }
- const usersArray = await UserGetter.promises.getUsers(userIds, projection)
- const users = {}
- for (const user of usersArray) {
- users[user._id.toString()] = _userView(user)
- }
- projection.overleaf = 1
- const v1IdentifiedUsersArray = await UserGetter.promises.getUsersByV1Ids(
- v1UserIds,
- projection
- )
- for (const user of v1IdentifiedUsersArray) {
- users[user.overleaf.id] = _userView(user)
- }
- for (const entry of entries) {
- if (entry.meta != null) {
- entry.meta.users = ((entry.meta && entry.meta.users) || []).map(user => {
- if (typeof user === 'string' || typeof user === 'number') {
- return users[user]
- } else {
- return user
- }
- })
- }
- }
- return data
- }
- function _userView(user) {
- const { _id, first_name: firstName, last_name: lastName, email } = user
- return { first_name: firstName, last_name: lastName, email, id: _id }
- }
|