From 2692090f3f8c234f1118b82a77ddda70056986d7 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 24 Sep 2018 11:59:55 +0100 Subject: [PATCH 1/5] support a mainFile parameter for templates --- .../Project/ProjectRootDocManager.coffee | 20 ++++++ .../Templates/TemplatesController.coffee | 30 +++++--- .../project/editor/new_from_template.pug | 1 + .../Project/ProjectRootDocManagerTests.coffee | 71 +++++++++++++++++++ 4 files changed, 112 insertions(+), 10 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee b/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee index 4530fb67d3..d9e1d745df 100644 --- a/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee +++ b/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee @@ -31,3 +31,23 @@ module.exports = ProjectRootDocManager = ProjectEntityUpdateHandler.setRootDoc project_id, root_doc_id, callback else callback() + + setRootDocFromName: (project_id, rootDocName, callback = (error) ->) -> + ProjectEntityHandler.getAllDocPathsFromProject project_id, (error, docPaths) -> + return callback(error) if error? + # find the root doc from the filename + root_doc_id = null + for doc_id, path of docPaths + # docpaths have a leading / so allow matching "folder/filename" and "/folder/filename" + if path == rootDocName or path == "/#{rootDocName}" + root_doc_id = doc_id + # try a basename match if there was no match + if !root_doc_id + for doc_id, path of docPaths + if Path.basename(path) == Path.basename(rootDocName) + root_doc_id = doc_id + # set the root doc id if we found a match + if root_doc_id? + ProjectEntityUpdateHandler.setRootDoc project_id, root_doc_id, callback + else + callback() \ No newline at end of file diff --git a/services/web/app/coffee/Features/Templates/TemplatesController.coffee b/services/web/app/coffee/Features/Templates/TemplatesController.coffee index fce6c9502c..682e0649c9 100644 --- a/services/web/app/coffee/Features/Templates/TemplatesController.coffee +++ b/services/web/app/coffee/Features/Templates/TemplatesController.coffee @@ -24,6 +24,7 @@ module.exports = TemplatesController = data.templateId = templateId data.name = req.query.templateName data.compiler = req.query.latexEngine + data.mainFile = req.query.mainFile res.render path.resolve(__dirname, "../../../views/project/editor/new_from_template"), data createProjectFromV1Template: (req, res)-> @@ -43,6 +44,7 @@ module.exports = TemplatesController = currentUserId: currentUserId, compiler: req.body.compiler docId: req.body.docId + mainFile: req.body.mainFile templateId: req.body.templateId templateVersionId: req.body.templateVersionId }, @@ -62,19 +64,27 @@ module.exports = TemplatesController = if err? logger.err err:err, zipReq:zipReq, "problem building project from zip" return res.sendStatus 500 - setCompiler project._id, options.compiler, -> - fs.unlink dumpPath, -> - delete req.session.templateData - conditions = {_id:project._id} - update = { - fromV1TemplateId:options.templateId, - fromV1TemplateVersionId:options.templateVersionId - } - Project.update conditions, update, {}, (err)-> - res.redirect "/project/#{project._id}" + setMainFile project._id, options.mainFile, -> + # ignore any errors setting main file + setCompiler project._id, options.compiler, -> + fs.unlink dumpPath, -> + delete req.session.templateData + conditions = {_id:project._id} + update = { + fromV1TemplateId:options.templateId, + fromV1TemplateVersionId:options.templateVersionId + } + Project.update conditions, update, {}, (err)-> + res.redirect "/project/#{project._id}" setCompiler = (project_id, compiler, callback)-> if compiler? ProjectOptionsHandler.setCompiler project_id, compiler, callback else callback() + +setMainFile = (project_id, mainFile, callback) -> + if mainFile? + ProjectRootDocManager.setRootDocFromName project_id, mainFile, callback + else + callback() \ No newline at end of file diff --git a/services/web/app/views/project/editor/new_from_template.pug b/services/web/app/views/project/editor/new_from_template.pug index 6dc27a4241..b81d23904c 100644 --- a/services/web/app/views/project/editor/new_from_template.pug +++ b/services/web/app/views/project/editor/new_from_template.pug @@ -24,3 +24,4 @@ block content input(type="hidden" name="templateVersionId" value=templateVersionId) input(type="hidden" name="templateName" value=name) input(type="hidden" name="compiler" value=compiler) + input(type="hidden" name="mainFile" value=mainFile) diff --git a/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee b/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee index 9a8cde3ff5..8ced7d8d98 100644 --- a/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee +++ b/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee @@ -75,3 +75,74 @@ describe 'ProjectRootDocManager', -> it "should not set the root doc to the doc containing a documentclass", -> @ProjectEntityUpdateHandler.setRootDoc.called.should.equal false + describe "setRootDocFromName", -> + describe "when there is a suitable root doc", -> + beforeEach (done)-> + @docPaths = + "doc-id-1": "/chapter1.tex" + "doc-id-2": "/main.tex" + "doc-id-3": "/nested/chapter1a.tex" + "doc-id-4": "/nested/chapter1b.tex" + @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) + @ProjectRootDocManager.setRootDocFromName @project_id, '/main.tex', done + + it "should check the docs of the project", -> + @ProjectEntityHandler.getAllDocPathsFromProject.calledWith(@project_id) + .should.equal true + + it "should set the root doc to main.tex", -> + @ProjectEntityUpdateHandler.setRootDoc.calledWith(@project_id, "doc-id-2") + .should.equal true + + describe "when there is a suitable root doc but the leading slash is missing", -> + beforeEach (done)-> + @docPaths = + "doc-id-1": "/chapter1.tex" + "doc-id-2": "/main.tex" + "doc-id-3": "/nested/chapter1a.tex" + "doc-id-4": "/nested/chapter1b.tex" + @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) + @ProjectRootDocManager.setRootDocFromName @project_id, 'main.tex', done + + it "should check the docs of the project", -> + @ProjectEntityHandler.getAllDocPathsFromProject.calledWith(@project_id) + .should.equal true + + it "should set the root doc to main.tex", -> + @ProjectEntityUpdateHandler.setRootDoc.calledWith(@project_id, "doc-id-2") + .should.equal true + + describe "when there is a suitable root doc with a basename match", -> + beforeEach (done)-> + @docPaths = + "doc-id-1": "/chapter1.tex" + "doc-id-2": "/main.tex" + "doc-id-3": "/nested/chapter1a.tex" + "doc-id-4": "/nested/chapter1b.tex" + @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) + @ProjectRootDocManager.setRootDocFromName @project_id, 'chapter1a.tex', done + + it "should check the docs of the project", -> + @ProjectEntityHandler.getAllDocPathsFromProject.calledWith(@project_id) + .should.equal true + + it "should set the root doc using the basename", -> + @ProjectEntityUpdateHandler.setRootDoc.calledWith(@project_id, "doc-id-3") + .should.equal true + + describe "when there is no suitable root doc", -> + beforeEach (done)-> + @docPaths = + "doc-id-1": "/chapter1.tex" + "doc-id-2": "/main.tex" + "doc-id-3": "/nested/chapter1a.tex" + "doc-id-4": "/nested/chapter1b.tex" + @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) + @ProjectRootDocManager.setRootDocFromName @project_id, "other.tex", done + + it "should not set the root doc", -> + @ProjectEntityUpdateHandler.setRootDoc.called.should.equal false From 586e3814fe03133265ac1755aa2d2df0392b7269 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 24 Sep 2018 15:26:11 +0100 Subject: [PATCH 2/5] add missing require --- .../web/app/coffee/Features/Templates/TemplatesController.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/services/web/app/coffee/Features/Templates/TemplatesController.coffee b/services/web/app/coffee/Features/Templates/TemplatesController.coffee index 682e0649c9..3b066682bf 100644 --- a/services/web/app/coffee/Features/Templates/TemplatesController.coffee +++ b/services/web/app/coffee/Features/Templates/TemplatesController.coffee @@ -2,6 +2,7 @@ path = require('path') Project = require('../../../js/models/Project').Project ProjectUploadManager = require('../../../js/Features/Uploads/ProjectUploadManager') ProjectOptionsHandler = require('../../../js/Features/Project/ProjectOptionsHandler') +ProjectRootDocManager = require('../../../js/Features/Project/ProjectRootDocManager') AuthenticationController = require('../../../js/Features/Authentication/AuthenticationController') settings = require('settings-sharelatex') fs = require('fs') From 5954e450165731f5e2aa94bdee6d8d72b5586a96 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 24 Sep 2018 15:42:50 +0100 Subject: [PATCH 3/5] add missing require --- .../unit/coffee/Templates/TemplatesControllerTests.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/web/test/unit/coffee/Templates/TemplatesControllerTests.coffee b/services/web/test/unit/coffee/Templates/TemplatesControllerTests.coffee index 5cf52eca39..0cdc90cbda 100644 --- a/services/web/test/unit/coffee/Templates/TemplatesControllerTests.coffee +++ b/services/web/test/unit/coffee/Templates/TemplatesControllerTests.coffee @@ -24,6 +24,9 @@ describe 'TemplatesController', -> @dumpFolder = "dump/path" @ProjectOptionsHandler = {setCompiler:sinon.stub().callsArgWith(2)} @uuid = "1234" + @ProjectRootDocManager = { + setRootDocFromName: sinon.stub().callsArgWith(2) + } @ProjectDetailsHandler = getProjectDescription:sinon.stub() @Project = @@ -31,6 +34,7 @@ describe 'TemplatesController', -> @controller = SandboxedModule.require modulePath, requires: '../../../js/Features/Uploads/ProjectUploadManager':@ProjectUploadManager '../../../js/Features/Project/ProjectOptionsHandler':@ProjectOptionsHandler + '../../../js/Features/Project/ProjectRootDocManager':@ProjectRootDocManager '../../../js/Features/Authentication/AuthenticationController': @AuthenticationController = {getLoggedInUserId: sinon.stub()} './TemplatesPublisher':@TemplatesPublisher "logger-sharelatex": From 418bc10a189cfb2f7a15e7050e477fd6aba24649 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 24 Sep 2018 16:04:23 +0100 Subject: [PATCH 4/5] allow getting doc paths by project id --- .../Features/Project/ProjectEntityHandler.coffee | 6 ++++++ .../Features/Project/ProjectRootDocManager.coffee | 2 +- .../Project/ProjectRootDocManagerTests.coffee | 14 +++++++------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee b/services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee index 5994521b8e..2160fbc419 100644 --- a/services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee +++ b/services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee @@ -65,6 +65,12 @@ module.exports = ProjectEntityHandler = self = files.push({path: path.join(folderPath, file.name), file:file}) callback null, docs, files + getAllDocPathsFromProjectById: (project_id, callback) -> + ProjectGetter.getProjectWithoutDocLines project_id, (err, project) -> + return callback(err) if err? + return callback(Errors.NotFoundError("no project")) if !project? + self.getAllDocPathsFromProject project, callback + getAllDocPathsFromProject: (project, callback) -> logger.log project:project, "getting all docs for project" self._getAllFoldersFromProject project, (err, folders = {}) -> diff --git a/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee b/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee index d9e1d745df..b331c38aa6 100644 --- a/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee +++ b/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee @@ -33,7 +33,7 @@ module.exports = ProjectRootDocManager = callback() setRootDocFromName: (project_id, rootDocName, callback = (error) ->) -> - ProjectEntityHandler.getAllDocPathsFromProject project_id, (error, docPaths) -> + ProjectEntityHandler.getAllDocPathsFromProjectById project_id, (error, docPaths) -> return callback(error) if error? # find the root doc from the filename root_doc_id = null diff --git a/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee b/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee index 8ced7d8d98..d65b92043a 100644 --- a/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee +++ b/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee @@ -83,12 +83,12 @@ describe 'ProjectRootDocManager', -> "doc-id-2": "/main.tex" "doc-id-3": "/nested/chapter1a.tex" "doc-id-4": "/nested/chapter1b.tex" - @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityHandler.getAllDocPathsFromProjectById = sinon.stub().callsArgWith(1, null, @docPaths) @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) @ProjectRootDocManager.setRootDocFromName @project_id, '/main.tex', done it "should check the docs of the project", -> - @ProjectEntityHandler.getAllDocPathsFromProject.calledWith(@project_id) + @ProjectEntityHandler.getAllDocPathsFromProjectById.calledWith(@project_id) .should.equal true it "should set the root doc to main.tex", -> @@ -102,12 +102,12 @@ describe 'ProjectRootDocManager', -> "doc-id-2": "/main.tex" "doc-id-3": "/nested/chapter1a.tex" "doc-id-4": "/nested/chapter1b.tex" - @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityHandler.getAllDocPathsFromProjectById = sinon.stub().callsArgWith(1, null, @docPaths) @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) @ProjectRootDocManager.setRootDocFromName @project_id, 'main.tex', done it "should check the docs of the project", -> - @ProjectEntityHandler.getAllDocPathsFromProject.calledWith(@project_id) + @ProjectEntityHandler.getAllDocPathsFromProjectById.calledWith(@project_id) .should.equal true it "should set the root doc to main.tex", -> @@ -121,12 +121,12 @@ describe 'ProjectRootDocManager', -> "doc-id-2": "/main.tex" "doc-id-3": "/nested/chapter1a.tex" "doc-id-4": "/nested/chapter1b.tex" - @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityHandler.getAllDocPathsFromProjectById = sinon.stub().callsArgWith(1, null, @docPaths) @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) @ProjectRootDocManager.setRootDocFromName @project_id, 'chapter1a.tex', done it "should check the docs of the project", -> - @ProjectEntityHandler.getAllDocPathsFromProject.calledWith(@project_id) + @ProjectEntityHandler.getAllDocPathsFromProjectById.calledWith(@project_id) .should.equal true it "should set the root doc using the basename", -> @@ -140,7 +140,7 @@ describe 'ProjectRootDocManager', -> "doc-id-2": "/main.tex" "doc-id-3": "/nested/chapter1a.tex" "doc-id-4": "/nested/chapter1b.tex" - @ProjectEntityHandler.getAllDocPathsFromProject = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityHandler.getAllDocPathsFromProjectById = sinon.stub().callsArgWith(1, null, @docPaths) @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) @ProjectRootDocManager.setRootDocFromName @project_id, "other.tex", done From 0d4143205d1728bd1101b572fffeebab911b2d53 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 25 Sep 2018 09:04:56 +0100 Subject: [PATCH 5/5] strip quotes from mainFile --- .../Project/ProjectRootDocManager.coffee | 6 +++++- .../Project/ProjectRootDocManagerTests.coffee | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee b/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee index b331c38aa6..973d2b2ed6 100644 --- a/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee +++ b/services/web/app/coffee/Features/Project/ProjectRootDocManager.coffee @@ -35,11 +35,15 @@ module.exports = ProjectRootDocManager = setRootDocFromName: (project_id, rootDocName, callback = (error) ->) -> ProjectEntityHandler.getAllDocPathsFromProjectById project_id, (error, docPaths) -> return callback(error) if error? + # strip off leading and trailing quotes from rootDocName + rootDocName = rootDocName.replace(/^\'|\'$/g,"") + # prepend a slash for the root folder if not present + rootDocName = "/#{rootDocName}" if rootDocName[0] isnt '/' # find the root doc from the filename root_doc_id = null for doc_id, path of docPaths # docpaths have a leading / so allow matching "folder/filename" and "/folder/filename" - if path == rootDocName or path == "/#{rootDocName}" + if path == rootDocName root_doc_id = doc_id # try a basename match if there was no match if !root_doc_id diff --git a/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee b/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee index d65b92043a..47c2973e9f 100644 --- a/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee +++ b/services/web/test/unit/coffee/Project/ProjectRootDocManagerTests.coffee @@ -133,6 +133,25 @@ describe 'ProjectRootDocManager', -> @ProjectEntityUpdateHandler.setRootDoc.calledWith(@project_id, "doc-id-3") .should.equal true + describe "when there is a suitable root doc but the filename is in quotes", -> + beforeEach (done)-> + @docPaths = + "doc-id-1": "/chapter1.tex" + "doc-id-2": "/main.tex" + "doc-id-3": "/nested/chapter1a.tex" + "doc-id-4": "/nested/chapter1b.tex" + @ProjectEntityHandler.getAllDocPathsFromProjectById = sinon.stub().callsArgWith(1, null, @docPaths) + @ProjectEntityUpdateHandler.setRootDoc = sinon.stub().callsArgWith(2) + @ProjectRootDocManager.setRootDocFromName @project_id, "'main.tex'", done + + it "should check the docs of the project", -> + @ProjectEntityHandler.getAllDocPathsFromProjectById.calledWith(@project_id) + .should.equal true + + it "should set the root doc to main.tex", -> + @ProjectEntityUpdateHandler.setRootDoc.calledWith(@project_id, "doc-id-2") + .should.equal true + describe "when there is no suitable root doc", -> beforeEach (done)-> @docPaths =