Files
overleaf-cep/services/web/app/src/Features/Project/ProjectGetter.js
Eric Mc Sween 2a88d7d9c9 Merge pull request #25152 from overleaf/em-ds-mobile-app
Endpoints for DS mobile app

GitOrigin-RevId: c7cf867bde60a0293c1c9f68f5a08515d0d2e904
2025-05-02 08:05:57 +00:00

164 lines
4.6 KiB
JavaScript

const { db } = require('../../infrastructure/mongodb')
const { normalizeQuery } = require('../Helpers/Mongo')
const OError = require('@overleaf/o-error')
const { Project } = require('../../models/Project')
const LockManager = require('../../infrastructure/LockManager')
const { DeletedProject } = require('../../models/DeletedProject')
const { callbackifyAll } = require('@overleaf/promise-utils')
const ProjectGetter = {
EXCLUDE_DEPTH: 8,
async getProjectWithoutDocLines(projectId) {
const excludes = {}
for (let i = 1; i <= ProjectGetter.EXCLUDE_DEPTH; i++) {
excludes[`rootFolder${Array(i).join('.folders')}.docs.lines`] = 0
}
return await ProjectGetter.getProject(projectId, excludes)
},
async getProjectWithOnlyFolders(projectId) {
const excludes = {}
for (let i = 1; i <= ProjectGetter.EXCLUDE_DEPTH; i++) {
excludes[`rootFolder${Array(i).join('.folders')}.docs`] = 0
excludes[`rootFolder${Array(i).join('.folders')}.fileRefs`] = 0
}
return await ProjectGetter.getProject(projectId, excludes)
},
async getProject(projectId, projection = {}) {
if (projectId == null) {
throw new Error('no project id provided')
}
if (typeof projection !== 'object') {
throw new Error('projection is not an object')
}
if (projection.rootFolder || Object.keys(projection).length === 0) {
const ProjectEntityMongoUpdateHandler = require('./ProjectEntityMongoUpdateHandler')
return await LockManager.promises.runWithLock(
ProjectEntityMongoUpdateHandler.LOCK_NAMESPACE,
projectId,
() => ProjectGetter.getProjectWithoutLock(projectId, projection)
)
} else {
return await ProjectGetter.getProjectWithoutLock(projectId, projection)
}
},
async getProjectWithoutLock(projectId, projection = {}) {
if (projectId == null) {
throw new Error('no project id provided')
}
if (typeof projection !== 'object') {
throw new Error('projection is not an object')
}
const query = normalizeQuery(projectId)
let project
try {
project = await db.projects.findOne(query, { projection })
} catch (error) {
OError.tag(error, 'error getting project', {
query,
projection,
})
throw error
}
return project
},
async getProjectIdByReadAndWriteToken(token) {
const project = await Project.findOne(
{ 'tokens.readAndWrite': token },
{ _id: 1 }
).exec()
if (project == null) {
return
}
return project._id
},
/**
* @return {Promise<any>}
*/
async findAllUsersProjects(userId, fields) {
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
const ownedProjects = await Project.find(
{ owner_ref: userId },
fields
).exec()
const projects =
await CollaboratorsGetter.promises.getProjectsUserIsMemberOf(
userId,
fields
)
const result = {
owned: ownedProjects || [],
readAndWrite: projects.readAndWrite || [],
readOnly: projects.readOnly || [],
tokenReadAndWrite: projects.tokenReadAndWrite || [],
tokenReadOnly: projects.tokenReadOnly || [],
review: projects.review || [],
}
// Remove duplicate projects. The order of result values is determined by the order they occur.
const tempAddedProjectsIds = new Set()
const filteredProjects = Object.entries(result).reduce((prev, current) => {
const [key, projects] = current
prev[key] = []
projects.forEach(project => {
const projectId = project._id.toString()
if (!tempAddedProjectsIds.has(projectId)) {
prev[key].push(project)
tempAddedProjectsIds.add(projectId)
}
})
return prev
}, {})
return filteredProjects
},
/**
* Return all projects with the given name that belong to the given user.
*
* Projects include the user's own projects as well as collaborations with
* read/write access.
*/
async findUsersProjectsByName(userId, projectName) {
const allProjects = await ProjectGetter.findAllUsersProjects(
userId,
'name archived trashed'
)
const { owned, readAndWrite } = allProjects
const projects = owned.concat(readAndWrite)
const lowerCasedProjectName = projectName.toLowerCase()
return projects.filter(
project => project.name.toLowerCase() === lowerCasedProjectName
)
},
async getUsersDeletedProjects(userId) {
return await DeletedProject.find({
'deleterData.deletedProjectOwnerId': userId,
}).exec()
},
}
module.exports = {
...callbackifyAll(ProjectGetter),
promises: ProjectGetter,
}