mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Fix ObjectId/String comparison in ensureRootDocumentIsValid (#4229)
GitOrigin-RevId: 8af2a74cd24cb5bfdfdcd1a25c16b94a66fa0843
This commit is contained in:
parent
7b5aa23285
commit
a1f66a5252
3 changed files with 116 additions and 101 deletions
|
@ -151,6 +151,11 @@ const ProjectEntityHandler = {
|
||||||
DocstoreManager.getDoc(projectId, docId, options, callback)
|
DocstoreManager.getDoc(projectId, docId, options, callback)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ObjectID | string} projectId
|
||||||
|
* @param {ObjectID | string} docId
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
getDocPathByProjectIdAndDocId(projectId, docId, callback) {
|
getDocPathByProjectIdAndDocId(projectId, docId, callback) {
|
||||||
ProjectGetter.getProjectWithoutDocLines(projectId, (err, project) => {
|
ProjectGetter.getProjectWithoutDocLines(projectId, (err, project) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
|
@ -159,6 +164,26 @@ const ProjectEntityHandler = {
|
||||||
if (project == null) {
|
if (project == null) {
|
||||||
return callback(new Errors.NotFoundError('no project'))
|
return callback(new Errors.NotFoundError('no project'))
|
||||||
}
|
}
|
||||||
|
ProjectEntityHandler.getDocPathFromProjectByDocId(
|
||||||
|
project,
|
||||||
|
docId,
|
||||||
|
(err, docPath) => {
|
||||||
|
if (err) return callback(Errors.OError.tag(err))
|
||||||
|
if (docPath == null) {
|
||||||
|
return callback(new Errors.NotFoundError('no doc'))
|
||||||
|
}
|
||||||
|
callback(null, docPath)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Project} project
|
||||||
|
* @param {ObjectID | string} docId
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
getDocPathFromProjectByDocId(project, docId, callback) {
|
||||||
function recursivelyFindDocInFolder(basePath, docId, folder) {
|
function recursivelyFindDocInFolder(basePath, docId, folder) {
|
||||||
const docInCurrentFolder = (folder.docs || []).find(
|
const docInCurrentFolder = (folder.docs || []).find(
|
||||||
currentDoc => currentDoc._id.toString() === docId.toString()
|
currentDoc => currentDoc._id.toString() === docId.toString()
|
||||||
|
@ -185,11 +210,7 @@ const ProjectEntityHandler = {
|
||||||
docId,
|
docId,
|
||||||
project.rootFolder[0]
|
project.rootFolder[0]
|
||||||
)
|
)
|
||||||
if (docPath == null) {
|
|
||||||
return callback(new Errors.NotFoundError('no doc'))
|
|
||||||
}
|
|
||||||
callback(null, docPath)
|
callback(null, docPath)
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_getAllFolders(projectId, callback) {
|
_getAllFolders(projectId, callback) {
|
||||||
|
|
|
@ -205,13 +205,13 @@ module.exports = ProjectRootDocManager = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ObjectId | string} project_id
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
ensureRootDocumentIsValid(project_id, callback) {
|
ensureRootDocumentIsValid(project_id, callback) {
|
||||||
if (callback == null) {
|
ProjectGetter.getProjectWithoutDocLines(
|
||||||
callback = function (error) {}
|
|
||||||
}
|
|
||||||
return ProjectGetter.getProject(
|
|
||||||
project_id,
|
project_id,
|
||||||
{ rootDoc_id: 1 },
|
|
||||||
function (error, project) {
|
function (error, project) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
|
@ -221,30 +221,18 @@ module.exports = ProjectRootDocManager = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project.rootDoc_id != null) {
|
if (project.rootDoc_id != null) {
|
||||||
return ProjectEntityHandler.getAllDocPathsFromProjectById(
|
ProjectEntityHandler.getDocPathFromProjectByDocId(
|
||||||
project_id,
|
project,
|
||||||
function (error, docPaths) {
|
project.rootDoc_id,
|
||||||
if (error != null) {
|
(err, docPath) => {
|
||||||
return callback(error)
|
if (docPath) return callback()
|
||||||
}
|
ProjectEntityUpdateHandler.unsetRootDoc(project_id, () =>
|
||||||
let rootDocValid = false
|
|
||||||
for (const doc_id in docPaths) {
|
|
||||||
const _path = docPaths[doc_id]
|
|
||||||
if (doc_id === project.rootDoc_id) {
|
|
||||||
rootDocValid = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rootDocValid) {
|
|
||||||
return callback()
|
|
||||||
} else {
|
|
||||||
return ProjectEntityUpdateHandler.unsetRootDoc(project_id, () =>
|
|
||||||
ProjectRootDocManager.setRootDocAutomatically(
|
ProjectRootDocManager.setRootDocAutomatically(
|
||||||
project_id,
|
project_id,
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return ProjectRootDocManager.setRootDocAutomatically(
|
return ProjectRootDocManager.setRootDocAutomatically(
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
const { expect } = require('chai')
|
const { expect } = require('chai')
|
||||||
|
const { ObjectId } = require('mongodb')
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
const modulePath =
|
const modulePath =
|
||||||
'../../../../app/src/Features/Project/ProjectRootDocManager.js'
|
'../../../../app/src/Features/Project/ProjectRootDocManager.js'
|
||||||
|
@ -20,12 +21,15 @@ const SandboxedModule = require('sandboxed-module')
|
||||||
describe('ProjectRootDocManager', function () {
|
describe('ProjectRootDocManager', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.project_id = 'project-123'
|
this.project_id = 'project-123'
|
||||||
this.docPaths = {
|
this.docPaths = {}
|
||||||
'doc-id-1': '/chapter1.tex',
|
this.docId1 = new ObjectId()
|
||||||
'doc-id-2': '/main.tex',
|
this.docId2 = new ObjectId()
|
||||||
'doc-id-3': '/nested/chapter1a.tex',
|
this.docId3 = new ObjectId()
|
||||||
'doc-id-4': '/nested/chapter1b.tex',
|
this.docId4 = new ObjectId()
|
||||||
}
|
this.docPaths[this.docId1] = '/chapter1.tex'
|
||||||
|
this.docPaths[this.docId2] = '/main.tex'
|
||||||
|
this.docPaths[this.docId3] = '/nested/chapter1a.tex'
|
||||||
|
this.docPaths[this.docId4] = '/nested/chapter1b.tex'
|
||||||
this.sl_req_id = 'sl-req-id-123'
|
this.sl_req_id = 'sl-req-id-123'
|
||||||
this.callback = sinon.stub()
|
this.callback = sinon.stub()
|
||||||
this.globbyFiles = ['a.tex', 'b.tex', 'main.tex']
|
this.globbyFiles = ['a.tex', 'b.tex', 'main.tex']
|
||||||
|
@ -60,7 +64,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.docs = {
|
this.docs = {
|
||||||
'/chapter1.tex': {
|
'/chapter1.tex': {
|
||||||
_id: 'doc-id-1',
|
_id: this.docId1,
|
||||||
lines: [
|
lines: [
|
||||||
'something else',
|
'something else',
|
||||||
'\\begin{document}',
|
'\\begin{document}',
|
||||||
|
@ -69,7 +73,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'/main.tex': {
|
'/main.tex': {
|
||||||
_id: 'doc-id-2',
|
_id: this.docId2,
|
||||||
lines: [
|
lines: [
|
||||||
'different line',
|
'different line',
|
||||||
'\\documentclass{article}',
|
'\\documentclass{article}',
|
||||||
|
@ -77,11 +81,11 @@ describe('ProjectRootDocManager', function () {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'/nested/chapter1a.tex': {
|
'/nested/chapter1a.tex': {
|
||||||
_id: 'doc-id-3',
|
_id: this.docId3,
|
||||||
lines: ['Hello world'],
|
lines: ['Hello world'],
|
||||||
},
|
},
|
||||||
'/nested/chapter1b.tex': {
|
'/nested/chapter1b.tex': {
|
||||||
_id: 'doc-id-4',
|
_id: this.docId4,
|
||||||
lines: ['Hello world'],
|
lines: ['Hello world'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -102,7 +106,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
it('should set the root doc to the doc containing a documentclass', function () {
|
it('should set the root doc to the doc containing a documentclass', function () {
|
||||||
return this.ProjectEntityUpdateHandler.setRootDoc
|
return this.ProjectEntityUpdateHandler.setRootDoc
|
||||||
.calledWith(this.project_id, 'doc-id-2')
|
.calledWith(this.project_id, this.docId2)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -111,11 +115,11 @@ describe('ProjectRootDocManager', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.docs = {
|
this.docs = {
|
||||||
'/chapter1.tex': {
|
'/chapter1.tex': {
|
||||||
_id: 'doc-id-1',
|
_id: this.docId1,
|
||||||
lines: ['\\begin{document}', 'Hello world', '\\end{document}'],
|
lines: ['\\begin{document}', 'Hello world', '\\end{document}'],
|
||||||
},
|
},
|
||||||
'/main.Rtex': {
|
'/main.Rtex': {
|
||||||
_id: 'doc-id-2',
|
_id: this.docId2,
|
||||||
lines: ['\\documentclass{article}', '\\input{chapter1}'],
|
lines: ['\\documentclass{article}', '\\input{chapter1}'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -130,7 +134,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
it('should set the root doc to the doc containing a documentclass', function () {
|
it('should set the root doc to the doc containing a documentclass', function () {
|
||||||
return this.ProjectEntityUpdateHandler.setRootDoc
|
return this.ProjectEntityUpdateHandler.setRootDoc
|
||||||
.calledWith(this.project_id, 'doc-id-2')
|
.calledWith(this.project_id, this.docId2)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -139,11 +143,11 @@ describe('ProjectRootDocManager', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.docs = {
|
this.docs = {
|
||||||
'/chapter1.tex': {
|
'/chapter1.tex': {
|
||||||
_id: 'doc-id-1',
|
_id: this.docId1,
|
||||||
lines: ['\\begin{document}', 'Hello world', '\\end{document}'],
|
lines: ['\\begin{document}', 'Hello world', '\\end{document}'],
|
||||||
},
|
},
|
||||||
'/style.bst': {
|
'/style.bst': {
|
||||||
_id: 'doc-id-2',
|
_id: this.docId2,
|
||||||
lines: ['%Example: \\documentclass{article}'],
|
lines: ['%Example: \\documentclass{article}'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -346,12 +350,6 @@ describe('ProjectRootDocManager', function () {
|
||||||
describe('setRootDocFromName', function () {
|
describe('setRootDocFromName', function () {
|
||||||
describe('when there is a suitable root doc', function () {
|
describe('when there is a suitable root doc', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.docPaths = {
|
|
||||||
'doc-id-1': '/chapter1.tex',
|
|
||||||
'doc-id-2': '/main.tex',
|
|
||||||
'doc-id-3': '/nested/chapter1a.tex',
|
|
||||||
'doc-id-4': '/nested/chapter1b.tex',
|
|
||||||
}
|
|
||||||
this.ProjectEntityHandler.getAllDocPathsFromProjectById = sinon
|
this.ProjectEntityHandler.getAllDocPathsFromProjectById = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(1, null, this.docPaths)
|
.callsArgWith(1, null, this.docPaths)
|
||||||
|
@ -373,7 +371,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
it('should set the root doc to main.tex', function () {
|
it('should set the root doc to main.tex', function () {
|
||||||
return this.ProjectEntityUpdateHandler.setRootDoc
|
return this.ProjectEntityUpdateHandler.setRootDoc
|
||||||
.calledWith(this.project_id, 'doc-id-2')
|
.calledWith(this.project_id, this.docId2.toString())
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -401,7 +399,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
it('should set the root doc to main.tex', function () {
|
it('should set the root doc to main.tex', function () {
|
||||||
return this.ProjectEntityUpdateHandler.setRootDoc
|
return this.ProjectEntityUpdateHandler.setRootDoc
|
||||||
.calledWith(this.project_id, 'doc-id-2')
|
.calledWith(this.project_id, this.docId2.toString())
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -429,7 +427,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
it('should set the root doc using the basename', function () {
|
it('should set the root doc using the basename', function () {
|
||||||
return this.ProjectEntityUpdateHandler.setRootDoc
|
return this.ProjectEntityUpdateHandler.setRootDoc
|
||||||
.calledWith(this.project_id, 'doc-id-3')
|
.calledWith(this.project_id, this.docId3.toString())
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -457,7 +455,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
it('should set the root doc to main.tex', function () {
|
it('should set the root doc to main.tex', function () {
|
||||||
return this.ProjectEntityUpdateHandler.setRootDoc
|
return this.ProjectEntityUpdateHandler.setRootDoc
|
||||||
.calledWith(this.project_id, 'doc-id-2')
|
.calledWith(this.project_id, this.docId2.toString())
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -498,7 +496,7 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
describe('when the root doc is set', function () {
|
describe('when the root doc is set', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.project.rootDoc_id = 'root-doc-id'
|
this.project.rootDoc_id = this.docId2
|
||||||
return this.ProjectRootDocManager.ensureRootDocumentIsSet(
|
return this.ProjectRootDocManager.ensureRootDocumentIsSet(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.callback
|
this.callback
|
||||||
|
@ -574,29 +572,32 @@ describe('ProjectRootDocManager', function () {
|
||||||
this.ProjectGetter.getProject = sinon
|
this.ProjectGetter.getProject = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(2, null, this.project)
|
.callsArgWith(2, null, this.project)
|
||||||
|
this.ProjectGetter.getProjectWithoutDocLines = sinon
|
||||||
|
.stub()
|
||||||
|
.callsArgWith(1, null, this.project)
|
||||||
this.ProjectEntityUpdateHandler.setRootDoc = sinon.stub().yields()
|
this.ProjectEntityUpdateHandler.setRootDoc = sinon.stub().yields()
|
||||||
this.ProjectEntityUpdateHandler.unsetRootDoc = sinon.stub().yields()
|
this.ProjectEntityUpdateHandler.unsetRootDoc = sinon.stub().yields()
|
||||||
this.ProjectEntityHandler.getAllDocPathsFromProjectById = sinon
|
this.ProjectRootDocManager.setRootDocAutomatically = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(1, null, this.docPaths)
|
.callsArgWith(1, null)
|
||||||
return (this.ProjectRootDocManager.setRootDocAutomatically = sinon
|
|
||||||
.stub()
|
|
||||||
.callsArgWith(1, null))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('when the root doc is set', function () {
|
describe('when the root doc is set', function () {
|
||||||
describe('when the root doc is valid', function () {
|
describe('when the root doc is valid', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.project.rootDoc_id = 'doc-id-2'
|
this.project.rootDoc_id = this.docId2
|
||||||
|
this.ProjectEntityHandler.getDocPathFromProjectByDocId = sinon
|
||||||
|
.stub()
|
||||||
|
.callsArgWith(2, null, this.docPaths[this.docId2])
|
||||||
return this.ProjectRootDocManager.ensureRootDocumentIsValid(
|
return this.ProjectRootDocManager.ensureRootDocumentIsValid(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should find the project fetching only the rootDoc_id field', function () {
|
it('should find the project without doc lines', function () {
|
||||||
return this.ProjectGetter.getProject
|
return this.ProjectGetter.getProjectWithoutDocLines
|
||||||
.calledWith(this.project_id, { rootDoc_id: 1 })
|
.calledWith(this.project_id)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -613,16 +614,19 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
describe('when the root doc is not valid', function () {
|
describe('when the root doc is not valid', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.project.rootDoc_id = 'bogus-doc-id'
|
this.project.rootDoc_id = new ObjectId()
|
||||||
|
this.ProjectEntityHandler.getDocPathFromProjectByDocId = sinon
|
||||||
|
.stub()
|
||||||
|
.callsArgWith(2, null, null)
|
||||||
return this.ProjectRootDocManager.ensureRootDocumentIsValid(
|
return this.ProjectRootDocManager.ensureRootDocumentIsValid(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should find the project fetching only the rootDoc_id field', function () {
|
it('should find the project without doc lines', function () {
|
||||||
return this.ProjectGetter.getProject
|
return this.ProjectGetter.getProjectWithoutDocLines
|
||||||
.calledWith(this.project_id, { rootDoc_id: 1 })
|
.calledWith(this.project_id)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -646,15 +650,15 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
describe('when the root doc is not set', function () {
|
describe('when the root doc is not set', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
return this.ProjectRootDocManager.ensureRootDocumentIsSet(
|
return this.ProjectRootDocManager.ensureRootDocumentIsValid(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should find the project fetching only the rootDoc_id fiel', function () {
|
it('should find the project without doc lines', function () {
|
||||||
return this.ProjectGetter.getProject
|
return this.ProjectGetter.getProjectWithoutDocLines
|
||||||
.calledWith(this.project_id, { rootDoc_id: 1 })
|
.calledWith(this.project_id)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -671,8 +675,10 @@ describe('ProjectRootDocManager', function () {
|
||||||
|
|
||||||
describe('when the project does not exist', function () {
|
describe('when the project does not exist', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, null)
|
this.ProjectGetter.getProjectWithoutDocLines = sinon
|
||||||
return this.ProjectRootDocManager.ensureRootDocumentIsSet(
|
.stub()
|
||||||
|
.callsArgWith(1, null, null)
|
||||||
|
return this.ProjectRootDocManager.ensureRootDocumentIsValid(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue