mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #8701 from overleaf/bg-simple-iterable-paths
simple iterable paths GitOrigin-RevId: f6906016888ccfc95c88858bdac4d2633fc1c5f4
This commit is contained in:
parent
be71ea690d
commit
5a3318f5b3
7 changed files with 53 additions and 15 deletions
15
services/web/app/src/Features/Project/IterablePath.js
Normal file
15
services/web/app/src/Features/Project/IterablePath.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Handles malformed filetrees - when fields such as `folder.docs`,
|
||||||
|
* `folder.folders` or `folder.fileRefs` are missing it returns an
|
||||||
|
* empty array.
|
||||||
|
*/
|
||||||
|
function iterablePaths(folder, field) {
|
||||||
|
if (!folder) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return folder[field] || []
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
iterablePaths,
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ const Errors = require('../Errors/Errors')
|
||||||
const ProjectGetter = require('./ProjectGetter')
|
const ProjectGetter = require('./ProjectGetter')
|
||||||
const { promisifyAll } = require('../../util/promises')
|
const { promisifyAll } = require('../../util/promises')
|
||||||
const OError = require('@overleaf/o-error')
|
const OError = require('@overleaf/o-error')
|
||||||
|
const { iterablePaths } = require('./IterablePath')
|
||||||
|
|
||||||
const ProjectEntityHandler = {
|
const ProjectEntityHandler = {
|
||||||
getAllDocs(projectId, callback) {
|
getAllDocs(projectId, callback) {
|
||||||
|
@ -26,7 +27,7 @@ const ProjectEntityHandler = {
|
||||||
}
|
}
|
||||||
const docs = {}
|
const docs = {}
|
||||||
for (const { path: folderPath, folder } of folders) {
|
for (const { path: folderPath, folder } of folders) {
|
||||||
for (const doc of folder.docs || []) {
|
for (const doc of iterablePaths(folder, 'docs')) {
|
||||||
const content = docContents[doc._id.toString()]
|
const content = docContents[doc._id.toString()]
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
docs[path.join(folderPath, doc.name)] = {
|
docs[path.join(folderPath, doc.name)] = {
|
||||||
|
@ -51,7 +52,7 @@ const ProjectEntityHandler = {
|
||||||
}
|
}
|
||||||
const files = {}
|
const files = {}
|
||||||
for (const { path: folderPath, folder } of folders) {
|
for (const { path: folderPath, folder } of folders) {
|
||||||
for (const file of folder.fileRefs || []) {
|
for (const file of iterablePaths(folder, 'fileRefs')) {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
files[path.join(folderPath, file.name)] = file
|
files[path.join(folderPath, file.name)] = file
|
||||||
}
|
}
|
||||||
|
@ -80,12 +81,12 @@ const ProjectEntityHandler = {
|
||||||
const docs = []
|
const docs = []
|
||||||
const files = []
|
const files = []
|
||||||
for (const { path: folderPath, folder } of folders) {
|
for (const { path: folderPath, folder } of folders) {
|
||||||
for (const doc of folder.docs || []) {
|
for (const doc of iterablePaths(folder, 'docs')) {
|
||||||
if (doc != null) {
|
if (doc != null) {
|
||||||
docs.push({ path: path.join(folderPath, doc.name), doc })
|
docs.push({ path: path.join(folderPath, doc.name), doc })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const file of folder.fileRefs || []) {
|
for (const file of iterablePaths(folder, 'fileRefs')) {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
files.push({ path: path.join(folderPath, file.name), file })
|
files.push({ path: path.join(folderPath, file.name), file })
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,7 @@ const ProjectEntityHandler = {
|
||||||
const folders = ProjectEntityHandler._getAllFoldersFromProject(project)
|
const folders = ProjectEntityHandler._getAllFoldersFromProject(project)
|
||||||
const docPath = {}
|
const docPath = {}
|
||||||
for (const { path: folderPath, folder } of folders) {
|
for (const { path: folderPath, folder } of folders) {
|
||||||
for (const doc of folder.docs || []) {
|
for (const doc of iterablePaths(folder, 'docs')) {
|
||||||
docPath[doc._id] = path.join(folderPath, doc.name)
|
docPath[doc._id] = path.join(folderPath, doc.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +172,7 @@ const ProjectEntityHandler = {
|
||||||
return path.join(basePath, docInCurrentFolder.name)
|
return path.join(basePath, docInCurrentFolder.name)
|
||||||
} else {
|
} else {
|
||||||
let docPath, childFolder
|
let docPath, childFolder
|
||||||
for (childFolder of folder.folders || []) {
|
for (childFolder of iterablePaths(folder, 'folders')) {
|
||||||
docPath = recursivelyFindDocInFolder(
|
docPath = recursivelyFindDocInFolder(
|
||||||
path.join(basePath, childFolder.name),
|
path.join(basePath, childFolder.name),
|
||||||
docId,
|
docId,
|
||||||
|
@ -211,7 +212,7 @@ const ProjectEntityHandler = {
|
||||||
const processFolder = (basePath, folder) => {
|
const processFolder = (basePath, folder) => {
|
||||||
folders.push({ path: basePath, folder })
|
folders.push({ path: basePath, folder })
|
||||||
if (folder.folders) {
|
if (folder.folders) {
|
||||||
for (const childFolder of folder.folders) {
|
for (const childFolder of iterablePaths(folder, 'folders')) {
|
||||||
if (childFolder.name != null) {
|
if (childFolder.name != null) {
|
||||||
const childPath = path.join(basePath, childFolder.name)
|
const childPath = path.join(basePath, childFolder.name)
|
||||||
processFolder(childPath, childFolder)
|
processFolder(childPath, childFolder)
|
||||||
|
|
|
@ -17,6 +17,7 @@ const ProjectLocator = require('./ProjectLocator')
|
||||||
const FolderStructureBuilder = require('./FolderStructureBuilder')
|
const FolderStructureBuilder = require('./FolderStructureBuilder')
|
||||||
const SafePath = require('./SafePath')
|
const SafePath = require('./SafePath')
|
||||||
const { DeletedFile } = require('../../models/DeletedFile')
|
const { DeletedFile } = require('../../models/DeletedFile')
|
||||||
|
const { iterablePaths } = require('./IterablePath')
|
||||||
|
|
||||||
const LOCK_NAMESPACE = 'mongoTransaction'
|
const LOCK_NAMESPACE = 'mongoTransaction'
|
||||||
const ENTITY_TYPE_TO_MONGO_PATH_SEGMENT = {
|
const ENTITY_TYPE_TO_MONGO_PATH_SEGMENT = {
|
||||||
|
@ -494,7 +495,7 @@ function _countElements(project) {
|
||||||
let total = 0
|
let total = 0
|
||||||
if (folder.folders) {
|
if (folder.folders) {
|
||||||
total += folder.folders.length
|
total += folder.folders.length
|
||||||
for (const subfolder of folder.folders) {
|
for (const subfolder of iterablePaths(folder, 'folders')) {
|
||||||
total += countFolder(subfolder)
|
total += countFolder(subfolder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ const TpdsUpdateSender = require('../ThirdPartyDataStore/TpdsUpdateSender')
|
||||||
const FileWriter = require('../../infrastructure/FileWriter')
|
const FileWriter = require('../../infrastructure/FileWriter')
|
||||||
const EditorRealTimeController = require('../Editor/EditorRealTimeController')
|
const EditorRealTimeController = require('../Editor/EditorRealTimeController')
|
||||||
const { promisifyAll } = require('../../util/promises')
|
const { promisifyAll } = require('../../util/promises')
|
||||||
|
const { iterablePaths } = require('./IterablePath')
|
||||||
|
|
||||||
const LOCK_NAMESPACE = 'sequentialProjectStructureUpdateLock'
|
const LOCK_NAMESPACE = 'sequentialProjectStructureUpdateLock'
|
||||||
const VALID_ROOT_DOC_EXTENSIONS = Settings.validRootDocExtensions
|
const VALID_ROOT_DOC_EXTENSIONS = Settings.validRootDocExtensions
|
||||||
|
@ -1608,16 +1609,16 @@ const ProjectEntityUpdateHandler = {
|
||||||
} else if (entityType.indexOf('folder') !== -1) {
|
} else if (entityType.indexOf('folder') !== -1) {
|
||||||
changes = { oldDocs: [], oldFiles: [] }
|
changes = { oldDocs: [], oldFiles: [] }
|
||||||
const _recurseFolder = (folder, folderPath) => {
|
const _recurseFolder = (folder, folderPath) => {
|
||||||
for (const doc of folder.docs) {
|
for (const doc of iterablePaths(folder, 'docs')) {
|
||||||
changes.oldDocs.push({ doc, path: Path.join(folderPath, doc.name) })
|
changes.oldDocs.push({ doc, path: Path.join(folderPath, doc.name) })
|
||||||
}
|
}
|
||||||
for (const file of folder.fileRefs) {
|
for (const file of iterablePaths(folder, 'fileRefs')) {
|
||||||
changes.oldFiles.push({
|
changes.oldFiles.push({
|
||||||
file,
|
file,
|
||||||
path: Path.join(folderPath, file.name),
|
path: Path.join(folderPath, file.name),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for (const childFolder of folder.folders) {
|
for (const childFolder of iterablePaths(folder, 'folders')) {
|
||||||
_recurseFolder(childFolder, Path.join(folderPath, childFolder.name))
|
_recurseFolder(childFolder, Path.join(folderPath, childFolder.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ const async = require('async')
|
||||||
const ProjectGetter = require('./ProjectGetter')
|
const ProjectGetter = require('./ProjectGetter')
|
||||||
const Errors = require('../Errors/Errors')
|
const Errors = require('../Errors/Errors')
|
||||||
const { promisifyMultiResult } = require('../../util/promises')
|
const { promisifyMultiResult } = require('../../util/promises')
|
||||||
|
const { iterablePaths } = require('./IterablePath')
|
||||||
|
|
||||||
function findElement(options, _callback) {
|
function findElement(options, _callback) {
|
||||||
// The search algorithm below potentially invokes the callback multiple
|
// The search algorithm below potentially invokes the callback multiple
|
||||||
|
@ -203,19 +204,19 @@ function _findElementByPathWithProject(
|
||||||
if (entityName == null) {
|
if (entityName == null) {
|
||||||
return cb(null, folder, 'folder')
|
return cb(null, folder, 'folder')
|
||||||
}
|
}
|
||||||
for (const file of folder.fileRefs || []) {
|
for (const file of iterablePaths(folder, 'fileRefs')) {
|
||||||
if (matchFn(file != null ? file.name : undefined, entityName)) {
|
if (matchFn(file != null ? file.name : undefined, entityName)) {
|
||||||
result = file
|
result = file
|
||||||
type = 'file'
|
type = 'file'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const doc of folder.docs || []) {
|
for (const doc of iterablePaths(folder, 'docs')) {
|
||||||
if (matchFn(doc != null ? doc.name : undefined, entityName)) {
|
if (matchFn(doc != null ? doc.name : undefined, entityName)) {
|
||||||
result = doc
|
result = doc
|
||||||
type = 'doc'
|
type = 'doc'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const childFolder of folder.folders || []) {
|
for (const childFolder of iterablePaths(folder, 'folders')) {
|
||||||
if (
|
if (
|
||||||
matchFn(childFolder != null ? childFolder.name : undefined, entityName)
|
matchFn(childFolder != null ? childFolder.name : undefined, entityName)
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ const { db, waitForDb } = require('../app/src/infrastructure/mongodb')
|
||||||
const Errors = require('../app/src/Features/Errors/Errors')
|
const Errors = require('../app/src/Features/Errors/Errors')
|
||||||
const FileStoreHandler = require('../app/src/Features/FileStore/FileStoreHandler')
|
const FileStoreHandler = require('../app/src/Features/FileStore/FileStoreHandler')
|
||||||
const ProjectEntityMongoUpdateHandler = require('../app/src/Features/Project/ProjectEntityMongoUpdateHandler')
|
const ProjectEntityMongoUpdateHandler = require('../app/src/Features/Project/ProjectEntityMongoUpdateHandler')
|
||||||
|
const { iterablePaths } = require('../app/src/Features/Project/IterablePath')
|
||||||
|
|
||||||
const OPTIONS = parseArgs()
|
const OPTIONS = parseArgs()
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ async function processProject(project) {
|
||||||
function findRefsInFolder(folder) {
|
function findRefsInFolder(folder) {
|
||||||
let docIds = folder.docs.map(doc => doc._id)
|
let docIds = folder.docs.map(doc => doc._id)
|
||||||
let fileIds = folder.fileRefs.map(file => file._id)
|
let fileIds = folder.fileRefs.map(file => file._id)
|
||||||
for (const subfolder of folder.folders) {
|
for (const subfolder of iterablePaths(folder, 'folders')) {
|
||||||
const subrefs = findRefsInFolder(subfolder)
|
const subrefs = findRefsInFolder(subfolder)
|
||||||
docIds = docIds.concat(subrefs.docIds)
|
docIds = docIds.concat(subrefs.docIds)
|
||||||
fileIds = fileIds.concat(subrefs.fileIds)
|
fileIds = fileIds.concat(subrefs.fileIds)
|
||||||
|
|
18
services/web/test/unit/src/Project/IterablePathTests.js
Normal file
18
services/web/test/unit/src/Project/IterablePathTests.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const { expect } = require('chai')
|
||||||
|
const {
|
||||||
|
iterablePaths,
|
||||||
|
} = require('../../../../app/src/Features/Project/IterablePath')
|
||||||
|
|
||||||
|
describe('iterablePaths', function () {
|
||||||
|
it('returns an empty array for empty folders', function () {
|
||||||
|
expect(iterablePaths(null, 'docs')).to.deep.equal([])
|
||||||
|
expect(iterablePaths({}, 'docs')).to.deep.equal([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns the `docs` object when it is iterable', function () {
|
||||||
|
const folder = {
|
||||||
|
docs: [{ _id: 1 }, { _id: 2 }],
|
||||||
|
}
|
||||||
|
expect(iterablePaths(folder, 'docs')).to.equal(folder.docs)
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue