Merge pull request #2618 from overleaf/ew-clear-root-doc-on-delete

Clear root doc on delete

GitOrigin-RevId: 4121d198f5253417bca2284c5f750c088debcb8c
This commit is contained in:
Eric Mc Sween 2020-02-27 07:46:37 -05:00 committed by Copybot
parent 17969c50ce
commit 1da929fcdb
4 changed files with 154 additions and 60 deletions

View file

@ -10,7 +10,6 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
@ -35,59 +34,52 @@ const COMPILE_TIMEOUT_MS = 10 * 60 * 1000
module.exports = CompileController = {
compile(req, res, next) {
if (next == null) {
next = function(error) {}
}
res.setTimeout(COMPILE_TIMEOUT_MS)
const project_id = req.params.Project_id
const isAutoCompile = !!(req.query != null
? req.query.auto_compile
: undefined)
const isAutoCompile = !!req.query.auto_compile
const user_id = AuthenticationController.getLoggedInUserId(req)
const options = {
isAutoCompile
}
if ((req.body != null ? req.body.rootDoc_id : undefined) != null) {
if (req.body.rootDoc_id) {
options.rootDoc_id = req.body.rootDoc_id
} else if (
__guard__(
req.body != null ? req.body.settingsOverride : undefined,
x => x.rootDoc_id
) != null
req.body.settingsOverride &&
req.body.settingsOverride.rootDoc_id
) {
// Can be removed after deploy
options.rootDoc_id = req.body.settingsOverride.rootDoc_id
}
if (req.body != null ? req.body.compiler : undefined) {
if (req.body.compiler) {
options.compiler = req.body.compiler
}
if (req.body != null ? req.body.draft : undefined) {
if (req.body.draft) {
options.draft = req.body.draft
}
if (
['validate', 'error', 'silent'].includes(
req.body != null ? req.body.check : undefined
)
) {
if (['validate', 'error', 'silent'].includes(req.body.check)) {
options.check = req.body.check
}
if (req.body != null ? req.body.incrementalCompilesEnabled : undefined) {
if (req.body.incrementalCompilesEnabled) {
options.incrementalCompilesEnabled = true
}
return CompileManager.compile(project_id, user_id, options, function(
error,
status,
outputFiles,
clsiServerId,
limits,
validationProblems
) {
if (error != null) {
return next(error)
}
res.contentType('application/json')
return res.status(200).send(
JSON.stringify({
CompileManager.compile(
project_id,
user_id,
options,
(
error,
status,
outputFiles,
clsiServerId,
limits,
validationProblems
) => {
if (error) {
return next(error)
}
res.json({
status,
outputFiles,
compileGroup: limits != null ? limits.compileGroup : undefined,
@ -95,8 +87,8 @@ module.exports = CompileController = {
validationProblems,
pdfDownloadDomain: Settings.pdfDownloadDomain
})
)
})
}
)
},
stopCompile(req, res, next) {
@ -540,9 +532,3 @@ module.exports = CompileController = {
})
}
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}

View file

@ -314,8 +314,12 @@ async function moveEntity(projectId, entityId, destFolderId, entityType) {
async function deleteEntity(projectId, entityId, entityType, callback) {
const project = await ProjectGetter.promises.getProjectWithoutLock(
projectId,
{ name: true, rootFolder: true, overleaf: true }
{ name: true, rootFolder: true, overleaf: true, rootDoc_id: true }
)
const deleteRootDoc =
project.rootDoc_id &&
entityId &&
project.rootDoc_id.toString() === entityId.toString()
const { element: entity, path } = await ProjectLocator.promises.findElement({
project,
element_id: entityId,
@ -325,7 +329,8 @@ async function deleteEntity(projectId, entityId, entityType, callback) {
Project,
projectId,
path.mongo,
entityId
entityId,
deleteRootDoc
)
return { entity, path, projectBeforeDeletion: project, newProject }
}
@ -414,19 +419,24 @@ async function _insertDeletedFileReference(projectId, fileRef) {
).exec()
}
async function _removeElementFromMongoArray(model, modelId, path, elementId) {
async function _removeElementFromMongoArray(
model,
modelId,
path,
elementId,
deleteRootDoc = false
) {
const nonArrayPath = path.slice(0, path.lastIndexOf('.'))
const newDoc = model
.findOneAndUpdate(
{ _id: modelId },
{
$pull: { [nonArrayPath]: { _id: elementId } },
$inc: { version: 1 }
},
{ new: true }
)
.exec()
return newDoc
const options = { new: true }
const query = { _id: modelId }
const update = {
$pull: { [nonArrayPath]: { _id: elementId } },
$inc: { version: 1 }
}
if (deleteRootDoc) {
update.$unset = { rootDoc_id: 1 }
}
return model.findOneAndUpdate(query, update, options).exec()
}
function _countElements(project) {

View file

@ -6,6 +6,7 @@ const fs = require('fs')
const Settings = require('settings-sharelatex')
const _ = require('underscore')
const { Project } = require('../../../app/src/models/Project')
const ProjectGetter = require('../../../app/src/Features/Project/ProjectGetter.js')
const MockDocUpdaterApi = require('./helpers/MockDocUpdaterApi')
@ -1098,6 +1099,105 @@ describe('ProjectStructureChanges', function() {
})
})
describe('deleting docs', function() {
beforeEach(function(done) {
createExampleProject(owner, (err, projectId) => {
if (err) {
return done(err)
}
this.exampleProjectId = projectId
createExampleFolder(owner, projectId, (err, folderId) => {
if (err) {
return done(err)
}
this.exampleFolderId = folderId
createExampleDoc(owner, projectId, (err, docId) => {
if (err) {
return done(err)
}
this.exampleDocId = docId
MockDocUpdaterApi.clearProjectStructureUpdates()
ProjectGetter.getProject(
this.exampleProjectId,
(error, project) => {
if (error) {
throw error
}
this.project0 = project
done()
}
)
})
})
})
})
describe('when rootDoc_id matches doc being deleted', function() {
beforeEach(function(done) {
Project.update(
{ _id: this.exampleProjectId },
{ $set: { rootDoc_id: this.exampleDocId } },
done
)
})
it('should clear rootDoc_id', function(done) {
deleteItem(
owner,
this.exampleProjectId,
'doc',
this.exampleDocId,
() => {
ProjectGetter.getProject(
this.exampleProjectId,
(error, project) => {
if (error) {
throw error
}
expect(project.rootDoc_id).to.be.undefined
done()
}
)
}
)
})
})
describe('when rootDoc_id does not match doc being deleted', function() {
beforeEach(function(done) {
this.exampleRootDocId = new ObjectId()
Project.update(
{ _id: this.exampleProjectId },
{ $set: { rootDoc_id: this.exampleRootDocId } },
done
)
})
it('should not clear rootDoc_id', function(done) {
deleteItem(
owner,
this.exampleProjectId,
'doc',
this.exampleDocId,
() => {
ProjectGetter.getProject(
this.exampleProjectId,
(error, project) => {
if (error) {
throw error
}
expect(project.rootDoc_id.toString()).to.equal(
this.exampleRootDocId.toString()
)
done()
}
)
}
)
})
})
})
describe('tpds', function() {
let projectName, exampleProjectId, oldVersion, rootFolderId

View file

@ -120,14 +120,12 @@ describe('CompileController', function() {
})
it('should set the content-type of the response to application/json', function() {
return this.res.contentType
.calledWith('application/json')
.should.equal(true)
this.res.type.should.equal('application/json')
})
it('should send a successful response reporting the status and files', function() {
this.res.statusCode.should.equal(200)
return this.res.body.should.equal(
this.res.body.should.equal(
JSON.stringify({
status: this.status,
outputFiles: this.outputFiles