فهرست منبع

Merge pull request #490 from sharelatex/hof-deleted-project-history

Pass project history id with updates
Alasdair Smith 8 سال پیش
والد
کامیت
ad1df3532f

+ 10 - 4
services/web/app/coffee/Features/DocumentUpdater/DocumentUpdaterHandler.coffee

@@ -121,15 +121,15 @@ module.exports = DocumentUpdaterHandler =
 			method: "DELETE"
 		}, project_id, "delete-thread", callback
 
-	resyncProjectHistory: (project_id, docs, files, callback) ->
+	resyncProjectHistory: (project_id, projectHistoryId, docs, files, callback) ->
 		logger.info {project_id, docs, files}, "resyncing project history in doc updater"
 		DocumentUpdaterHandler._makeRequest {
 			path: "/project/#{project_id}/history/resync"
-			json: { docs, files }
+			json: { docs, files, projectHistoryId }
 			method: "POST"
 		}, project_id, "resync-project-history", callback
 
-	updateProjectStructure : (project_id, userId, changes, callback = (error) ->)->
+	updateProjectStructure: (project_id, projectHistoryId, userId, changes, callback = (error) ->)->
 		return callback() if !settings.apis.project_history?.sendProjectStructureOps
 
 		Project.findOne {_id: project_id}, {version:true}, (err, currentProject) ->
@@ -144,7 +144,13 @@ module.exports = DocumentUpdaterHandler =
 			logger.log {project_id}, "updating project structure in doc updater"
 			DocumentUpdaterHandler._makeRequest {
 				path: "/project/#{project_id}"
-				json: { docUpdates, fileUpdates, userId, version: currentProject.version }
+				json: {
+					docUpdates,
+					fileUpdates,
+					userId,
+					version: currentProject.version
+					projectHistoryId
+				}
 				method: "POST"
 			}, project_id, "update-project-structure", callback
 

+ 27 - 15
services/web/app/coffee/Features/Documents/DocumentController.coffee

@@ -1,3 +1,5 @@
+ProjectGetter = require "../Project/ProjectGetter"
+ProjectLocator = require "../Project/ProjectLocator"
 ProjectEntityHandler = require "../Project/ProjectEntityHandler"
 ProjectEntityUpdateHandler = require "../Project/ProjectEntityUpdateHandler"
 logger = require("logger-sharelatex")
@@ -8,21 +10,31 @@ module.exports =
 		doc_id = req.params.doc_id
 		plain = req?.query?.plain == 'true'
 		logger.log doc_id:doc_id, project_id:project_id, "receiving get document request from api (docupdater)"
-		ProjectEntityHandler.getDoc project_id, doc_id, {pathname: true}, (error, lines, rev, version, ranges, pathname) ->
-			if error?
-				logger.err err:error, doc_id:doc_id, project_id:project_id, "error finding element for getDocument"
-				return next(error)
-			if plain
-				res.type "text/plain"
-				res.send lines.join('\n')
-			else
-				res.type "json"
-				res.send JSON.stringify {
-					lines: lines
-					version: version
-					ranges: ranges
-					pathname: pathname
-				}
+		ProjectGetter.getProject project_id, rootFolder: true, overleaf: true, (error, project) ->
+			return next(error) if error?
+			return res.sendStatus(404) if !project?
+			ProjectLocator.findElement {project: project, element_id: doc_id, type: 'doc'}, (error, doc, path) ->
+				if error?
+					logger.err err:error, doc_id:doc_id, project_id:project_id, "error finding element for getDocument"
+					return next(error)
+				ProjectEntityHandler.getDoc project_id, doc_id, (error, lines, rev, version, ranges) ->
+					if error?
+						logger.err err:error, doc_id:doc_id, project_id:project_id, "error finding doc contents for getDocument"
+						return next(error)
+					if plain
+						res.type "text/plain"
+						res.send lines.join('\n')
+
+					else
+						projectHistoryId = project?.overleaf?.history?.id
+						res.type "json"
+						res.send JSON.stringify {
+							lines: lines
+							version: version
+							ranges: ranges
+							pathname: path.fileSystem
+							projectHistoryId: projectHistoryId
+						}
 
 	setDocument: (req, res, next = (error) ->) ->
 		project_id = req.params.Project_id

+ 1 - 9
services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee

@@ -6,7 +6,6 @@ DocstoreManager = require "../Docstore/DocstoreManager"
 DocumentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
 Errors = require '../Errors/Errors'
 Project = require('../../models/Project').Project
-ProjectLocator = require('./ProjectLocator')
 ProjectGetter = require "./ProjectGetter"
 TpdsUpdateSender = require('../ThirdPartyDataStore/TpdsUpdateSender')
 
@@ -105,14 +104,7 @@ module.exports = ProjectEntityHandler = self =
 			callback = options
 			options = {}
 
-		if options["pathname"]
-			delete options["pathname"]
-			ProjectLocator.findElement {project_id: project_id, element_id: doc_id, type: 'doc'}, (error, doc, path) =>
-				return callback(error) if error?
-				DocstoreManager.getDoc project_id, doc_id, options, (error, lines, rev, version, ranges) =>
-					callback(error, lines, rev, version, ranges, path.fileSystem)
-		else
-			DocstoreManager.getDoc project_id, doc_id, options, callback
+		DocstoreManager.getDoc project_id, doc_id, options, callback
 
 	_getAllFolders: (project_id,  callback) ->
 		logger.log project_id:project_id, "getting all folders for project"

+ 10 - 10
services/web/app/coffee/Features/Project/ProjectEntityMongoUpdateHandler.coffee

@@ -31,7 +31,7 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 	LOCK_NAMESPACE: LOCK_NAMESPACE
 
 	addDoc: wrapWithLock (project_id, folder_id, doc, callback = (err, result) ->) ->
-		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true}, (err, project) ->
+		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true, overleaf:true}, (err, project) ->
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add doc"
 				return callback(err)
@@ -40,7 +40,7 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 				self._putElement project, folder_id, doc, "doc", callback
 
 	addFile: wrapWithLock (project_id, folder_id, fileRef, callback = (error, result, project) ->)->
-		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true}, (err, project) ->
+		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true, overleaf:true}, (err, project) ->
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add file"
 				return callback(err)
@@ -49,7 +49,7 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 				self._putElement project, folder_id, fileRef, "file", callback
 
 	replaceFileWithNew: wrapWithLock (project_id, file_id, newFileRef, callback) ->
-		ProjectGetter.getProjectWithoutLock project_id, {rootFolder: true, name:true}, (err, project) ->
+		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true, overleaf:true}, (err, project) ->
 			return callback(err) if err?
 			ProjectLocator.findElement {project:project, element_id: file_id, type: 'file'}, (err, fileRef, path)=>
 				return callback(err) if err?
@@ -110,7 +110,7 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 				callback null, folders, lastFolder
 
 	moveEntity: wrapWithLock (project_id, entity_id, destFolderId, entityType, callback = (error) ->) ->
-		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true}, (err, project) ->
+		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true, overleaf:true}, (err, project) ->
 			return callback(err) if err?
 			ProjectLocator.findElement {project, element_id: entity_id, type: entityType}, (err, entity, entityPath)->
 				return callback(err) if err?
@@ -127,10 +127,10 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 									startPath = entityPath.fileSystem
 									endPath = result.path.fileSystem
 									changes = {oldDocs, newDocs, oldFiles, newFiles}
-									callback null, project.name, startPath, endPath, entity.rev, changes, callback
+									callback null, project, startPath, endPath, entity.rev, changes, callback
 
 	deleteEntity: wrapWithLock (project_id, entity_id, entityType, callback) ->
-		ProjectGetter.getProjectWithoutLock project_id, {name:true, rootFolder:true}, (error, project) ->
+		ProjectGetter.getProjectWithoutLock project_id, {name:true, rootFolder:true, overleaf:true}, (error, project) ->
 			return callback(error) if error?
 			ProjectLocator.findElement {project: project, element_id: entity_id, type: entityType}, (error, entity, path) ->
 				return callback(error) if error?
@@ -139,7 +139,7 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 					callback null, entity, path, project
 
 	renameEntity: wrapWithLock (project_id, entity_id, entityType, newName, callback) ->
-		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true}, (error, project)=>
+		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true, overleaf:true}, (error, project)=>
 			return callback(error) if error?
 			ProjectEntityHandler.getAllEntitiesFromProject project, (error, oldDocs, oldFiles) =>
 				return callback(error) if error?
@@ -161,10 +161,10 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 								return callback(error) if error?
 								startPath = entPath.fileSystem
 								changes = {oldDocs, newDocs, oldFiles, newFiles}
-								callback null, project.name, startPath, endPath, entity.rev, changes, callback
+								callback null, project, startPath, endPath, entity.rev, changes, callback
 
 	addFolder: wrapWithLock (project_id, parentFolder_id, folderName, callback) ->
-		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true}, (err, project) ->
+		ProjectGetter.getProjectWithoutLock project_id, {rootFolder:true, name:true, overleaf:true}, (err, project) ->
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add folder"
 				return callback(err)
@@ -325,4 +325,4 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
 					deletedAt: new Date()
 				}
 			}
-		}, {}, callback
+		}, {}, callback

+ 26 - 16
services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee

@@ -48,6 +48,7 @@ module.exports = ProjectEntityUpdateHandler = self =
 	# this doesn't need any locking because it's only called by ProjectDuplicator
 	copyFileFromExistingProjectWithProject: (project, folder_id, originalProject_id, origonalFileRef, userId, callback = (error, fileRef, folder_id) ->)->
 		project_id = project._id
+		projectHistoryId = project.overleaf?.history?.id
 		logger.log { project_id, folder_id, originalProject_id, origonalFileRef }, "copying file in s3 with project"
 		return callback(err) if err?
 		ProjectEntityMongoUpdateHandler._confirmFolder project, folder_id, (folder_id)=>
@@ -72,7 +73,7 @@ module.exports = ProjectEntityUpdateHandler = self =
 							path: result?.path?.fileSystem
 							url: fileStoreUrl
 						]
-						DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newFiles}, (error) ->
+						DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, {newFiles}, (error) ->
 							return callback(error) if error?
 							callback null, fileRef, folder_id
 
@@ -122,14 +123,15 @@ module.exports = ProjectEntityUpdateHandler = self =
 		Project.update {_id:project_id}, {$unset: {rootDoc_id: true}}, {}, callback
 
 	addDoc: wrapWithLock (project_id, folder_id, docName, docLines, userId, callback = (error, doc, folder_id) ->)=>
-		self.addDocWithoutUpdatingHistory.withoutLock project_id, folder_id, docName, docLines, userId, (error, doc, folder_id, path) ->
+		self.addDocWithoutUpdatingHistory.withoutLock project_id, folder_id, docName, docLines, userId, (error, doc, folder_id, path, project) ->
 			return callback(error) if error?
+			projectHistoryId = project.overleaf?.history?.id
 			newDocs = [
 				doc: doc
 				path: path
 				docLines: docLines.join('\n')
 			]
-			DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newDocs}, (error) ->
+			DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, {newDocs}, (error) ->
 				return callback(error) if error?
 				callback null, doc, folder_id
 
@@ -164,12 +166,13 @@ module.exports = ProjectEntityUpdateHandler = self =
 		withLock: (project_id, folder_id, fileName, fsPath, linkedFileData, userId, fileRef, fileStoreUrl, callback = (error, fileRef, folder_id) ->)->
 			ProjectEntityUpdateHandler._addFileAndSendToTpds project_id, folder_id, fileName, fileRef, (err, result, project) ->
 				return callback(err) if err?
+				projectHistoryId = project.overleaf?.history?.id
 				newFiles = [
 					file: fileRef
 					path: result?.path?.fileSystem
 					url: fileStoreUrl
 				]
-				DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newFiles}, (error) ->
+				DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, {newFiles}, (error) ->
 					return callback(error) if error?
 					callback(null, fileRef, folder_id)
 
@@ -196,9 +199,10 @@ module.exports = ProjectEntityUpdateHandler = self =
 					path: path.fileSystem
 					url: fileStoreUrl
 				]
+				projectHistoryId = project.overleaf?.history?.id
 				TpdsUpdateSender.addFile {project_id:project._id, file_id:newFileRef._id, path:path.fileSystem, rev:newFileRef.rev+1, project_name:project.name}, (err) ->
 					return callback(err) if err?
-					DocumentUpdaterHandler.updateProjectStructure project_id, userId, {oldFiles, newFiles}, callback
+					DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, {oldFiles, newFiles}, callback
 
 	addDocWithoutUpdatingHistory: wrapWithLock (project_id, folder_id, docName, docLines, userId, callback = (error, doc, folder_id) ->)=>
 		# This method should never be called directly, except when importing a project
@@ -223,7 +227,7 @@ module.exports = ProjectEntityUpdateHandler = self =
 					rev:          0
 				}, (err) ->
 					return callback(err) if err?
-					callback(null, doc, folder_id, result?.path?.fileSystem)
+					callback(null, doc, folder_id, result?.path?.fileSystem, project)
 
 	addFileWithoutUpdatingHistory: wrapWithLock
 		# This method should never be called directly, except when importing a project
@@ -354,10 +358,11 @@ module.exports = ProjectEntityUpdateHandler = self =
 			logger.err {err: "No entityType set", project_id, entity_id}
 			return callback("No entityType set")
 		entityType = entityType.toLowerCase()
-		ProjectEntityMongoUpdateHandler.moveEntity project_id, entity_id, destFolderId, entityType, (err, project_name, startPath, endPath, rev, changes) ->
+		ProjectEntityMongoUpdateHandler.moveEntity project_id, entity_id, destFolderId, entityType, (err, project, startPath, endPath, rev, changes) ->
 			return callback(err) if err?
-			TpdsUpdateSender.moveEntity { project_id, project_name, startPath, endPath, rev }
-			DocumentUpdaterHandler.updateProjectStructure project_id, userId, changes, callback
+			projectHistoryId = project.overleaf?.history?.id
+			TpdsUpdateSender.moveEntity { project_id, project_name: project.name, startPath, endPath, rev }
+			DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, changes, callback
 
 	renameEntity: wrapWithLock (project_id, entity_id, entityType, newName, userId, callback)->
 		if not SafePath.isCleanFilename newName
@@ -368,10 +373,11 @@ module.exports = ProjectEntityUpdateHandler = self =
 			return callback("No entityType set")
 		entityType = entityType.toLowerCase()
 
-		ProjectEntityMongoUpdateHandler.renameEntity project_id, entity_id, entityType, newName, (err, project_name, startPath, endPath, rev, changes) ->
+		ProjectEntityMongoUpdateHandler.renameEntity project_id, entity_id, entityType, newName, (err, project, startPath, endPath, rev, changes) ->
 			return callback(err) if err?
-			TpdsUpdateSender.moveEntity({project_id, startPath, endPath, project_name, rev})
-			DocumentUpdaterHandler.updateProjectStructure project_id, userId, changes, callback
+			projectHistoryId = project.overleaf?.history?.id
+			TpdsUpdateSender.moveEntity { project_id, project_name: project.name, startPath, endPath, rev }
+			DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, changes, callback
 
 	# This doesn't directly update project structure but we need to take the lock
 	# to prevent anything else being queued before the resync update
@@ -379,7 +385,8 @@ module.exports = ProjectEntityUpdateHandler = self =
 		ProjectGetter.getProject project_id, rootFolder: true, overleaf: true, (error, project) ->
 			return callback(error) if error?
 
-			if !project?.overleaf?.history?.id?
+			projectHistoryId = project?.overleaf?.history?.id
+			if !projectHistoryId?
 				error = new Errors.ProjectHistoryDisabledError("project history not enabled for #{project_id}")
 				return callback(error)
 
@@ -395,7 +402,8 @@ module.exports = ProjectEntityUpdateHandler = self =
 					path: file.path
 					url: FileStoreHandler._buildUrl(project_id, file.file._id)
 
-				DocumentUpdaterHandler.resyncProjectHistory project_id, docs, files, callback
+				DocumentUpdaterHandler.resyncProjectHistory project_id, projectHistoryId, docs, files, callback
+
 	_cleanUpEntity: (project, entity, entityType, path, userId, callback = (error) ->) ->
 		if(entityType.indexOf("file") != -1)
 			self._cleanUpFile project, entity, path, userId, callback
@@ -424,16 +432,18 @@ module.exports = ProjectEntityUpdateHandler = self =
 					DocstoreManager.deleteDoc project_id, doc_id, (error) ->
 						return callback(error) if error?
 						changes = oldDocs: [ {doc, path} ]
-						DocumentUpdaterHandler.updateProjectStructure project_id, userId, changes, callback
+						projectHistoryId = project.overleaf?.history?.id
+						DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, changes, callback
 
 	_cleanUpFile: (project, file, path, userId, callback = (error) ->) ->
 		ProjectEntityMongoUpdateHandler._insertDeletedFileReference project._id, file, (error) ->
 			return callback(error) if error?
 			project_id = project._id.toString()
+			projectHistoryId = project.overleaf?.history?.id
 			changes = oldFiles: [ {file, path} ]
 			# we are now keeping a copy of every file versio so we no longer delete
 			# the file from the filestore
-			DocumentUpdaterHandler.updateProjectStructure project_id, userId, changes, callback
+			DocumentUpdaterHandler.updateProjectStructure project_id, projectHistoryId, userId, changes, callback
 
 	_cleanUpFolder: (project, folder, folderPath, userId, callback = (error) ->) ->
 		jobs = []

+ 10 - 9
services/web/test/unit/coffee/DocumentUpdater/DocumentUpdaterHandlerTests.coffee

@@ -12,6 +12,7 @@ modulePath = path.join __dirname, '../../../../app/js/Features/DocumentUpdater/D
 describe 'DocumentUpdaterHandler', ->
 	beforeEach ->
 		@project_id = "project-id-923"
+		@projectHistoryId = "ol-project-id-1"
 		@doc_id = "doc-id-394"
 		@lines = ["one", "two", "three"]
 		@version = 42
@@ -409,7 +410,7 @@ describe 'DocumentUpdaterHandler', ->
 		describe "with project history disabled", ->
 			beforeEach ->
 				@settings.apis.project_history.sendProjectStructureOps = false
-				@handler.updateProjectStructure @project_id, @user_id, {}, @callback
+				@handler.updateProjectStructure @project_id, @projectHistoryId, @user_id, {}, @callback
 
 			it 'does not make a web request', ->
 				@request.called.should.equal false
@@ -445,11 +446,11 @@ describe 'DocumentUpdaterHandler', ->
 						newPathname: "/new_b"
 					]
 
-					@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
+					@handler.updateProjectStructure @project_id, @projectHistoryId, @user_id, @changes, () =>
 						@request.calledWith(
 							url: @url,
 							method: "POST"
-							json: {docUpdates, fileUpdates: [], userId: @user_id, @version}
+							json: {docUpdates, fileUpdates: [], userId: @user_id, @version, @projectHistoryId}
 						)
 						.should.equal true
 						done()
@@ -468,11 +469,11 @@ describe 'DocumentUpdaterHandler', ->
 						url: undefined
 					]
 
-					@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
+					@handler.updateProjectStructure @project_id, @projectHistoryId, @user_id, @changes, () =>
 						@request.calledWith(
 							url: @url
 							method: "POST"
-							json: {docUpdates, fileUpdates: [], userId: @user_id, @version}
+							json: {docUpdates, fileUpdates: [], userId: @user_id, @version, @projectHistoryId}
 						).should.equal true
 						done()
 
@@ -490,11 +491,11 @@ describe 'DocumentUpdaterHandler', ->
 						docLines: undefined
 					]
 
-					@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
+					@handler.updateProjectStructure @project_id, @projectHistoryId, @user_id, @changes, () =>
 						@request.calledWith(
 							url: @url
 							method: "POST"
-							json: {docUpdates: [], fileUpdates, userId: @user_id, @version}
+							json: {docUpdates: [], fileUpdates, userId: @user_id, @version, @projectHistoryId}
 						).should.equal true
 						done()
 
@@ -511,10 +512,10 @@ describe 'DocumentUpdaterHandler', ->
 						newPathname: ''
 					]
 
-					@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
+					@handler.updateProjectStructure @project_id, @projectHistoryId, @user_id, @changes, () =>
 						@request.calledWith(
 							url: @url
 							method: "POST"
-							json: {docUpdates, fileUpdates: [], userId: @user_id, @version}
+							json: {docUpdates, fileUpdates: [], userId: @user_id, @version, @projectHistoryId}
 						).should.equal true
 						done()

+ 59 - 17
services/web/test/unit/coffee/Documents/DocumentControllerTests.coffee

@@ -15,6 +15,8 @@ describe "DocumentController", ->
 			"logger-sharelatex":
 				log:->
 				err:->
+			"../Project/ProjectGetter": @ProjectGetter = {}
+			"../Project/ProjectLocator": @ProjectLocator = {}
 			"../Project/ProjectEntityHandler": @ProjectEntityHandler = {}
 			"../Project/ProjectEntityUpdateHandler": @ProjectEntityUpdateHandler = {}
 		@res = new MockResponse()
@@ -34,32 +36,76 @@ describe "DocumentController", ->
 				Project_id: @project_id
 				doc_id: @doc_id
 
-		describe "when the document exists", ->
+		describe "when the project exists without project history enabled", ->
 			beforeEach ->
-				@ProjectEntityHandler.getDoc = sinon.stub().callsArgWith(3, null, @doc_lines, @rev, @version, @ranges, @pathname)
-				@DocumentController.getDocument(@req, @res, @next)
+				@project = _id: @project_id
+				@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
 
-			it "should get the document from Mongo", ->
-				@ProjectEntityHandler.getDoc
-					.calledWith(@project_id, @doc_id, pathname: true)
-					.should.equal true
+			describe "when the document exists", ->
+				beforeEach ->
+					@doc = _id: @doc_id
+					@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @doc, fileSystem: @pathname)
+					@ProjectEntityHandler.getDoc = sinon.stub().callsArgWith(2, null, @doc_lines, @rev, @version, @ranges)
+					@DocumentController.getDocument(@req, @res, @next)
+
+				it "should get the project", ->
+					@ProjectGetter.getProject
+						.calledWith(@project_id, rootFolder: true, overleaf: true)
+						.should.equal true
+
+				it "should get the pathname of the document", ->
+					@ProjectLocator.findElement
+						.calledWith({project: @project, element_id: @doc_id, type: 'doc'})
+						.should.equal true
+
+				it "should get the document content", ->
+					@ProjectEntityHandler.getDoc
+						.calledWith(@project_id, @doc_id)
+						.should.equal true
+
+				it "should return the document data to the client as JSON", ->
+					@res.type.should.equal "json"
+					@res.body.should.equal JSON.stringify
+						lines: @doc_lines
+						version: @version
+						ranges: @ranges
+						pathname: @pathname
+
+			describe "when the document doesn't exist", ->
+				beforeEach ->
+					@ProjectLocator.findElement = sinon.stub().callsArgWith(1, new Errors.NotFoundError("not found"))
+					@DocumentController.getDocument(@req, @res, @next)
+
+				it "should call next with the NotFoundError", ->
+					@next.calledWith(new Errors.NotFoundError("not found"))
+						.should.equal true
 
-			it "should return the document data to the client as JSON", ->
+		describe "when project exists with project history enabled", ->
+			beforeEach ->
+				@doc = _id: @doc_id
+				@projectHistoryId = 1234
+				@project = _id: @project_id, overleaf: history: id: @projectHistoryId
+				@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
+				@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @doc, fileSystem: @pathname)
+				@ProjectEntityHandler.getDoc = sinon.stub().callsArgWith(2, null, @doc_lines, @rev, @version, @ranges)
+				@DocumentController.getDocument(@req, @res, @next)
+
+			it "should return the history id to the client as JSON", ->
 				@res.type.should.equal "json"
 				@res.body.should.equal JSON.stringify
 					lines: @doc_lines
 					version: @version
 					ranges: @ranges
 					pathname: @pathname
+					projectHistoryId: @projectHistoryId
 
-		describe "when the document doesn't exist", ->
+		describe "when the project does not exist", ->
 			beforeEach ->
-				@ProjectEntityHandler.getDoc = sinon.stub().callsArgWith(3, new Errors.NotFoundError("not found"), null)
+				@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, null)
 				@DocumentController.getDocument(@req, @res, @next)
 
-			it "should call next with the NotFoundError", ->
-				@next.calledWith(new Errors.NotFoundError("not found"))
-					.should.equal true
+			it "returns a 404", ->
+				@res.statusCode.should.equal 404
 
 	describe "setDocument", ->
 		beforeEach ->
@@ -94,7 +140,3 @@ describe "DocumentController", ->
 			it "should call next with the NotFoundError", ->
 				@next.calledWith(new Errors.NotFoundError("not found"))
 					.should.equal true
-
-					
-					
-

+ 7 - 30
services/web/test/unit/coffee/Project/ProjectEntityHandlerTests.coffee

@@ -241,35 +241,12 @@ describe 'ProjectEntityHandler', ->
 			@ranges = {"mock": "ranges"}
 
 			@DocstoreManager.getDoc = sinon.stub().callsArgWith(3, null, @lines, @rev, @version, @ranges)
+			@ProjectEntityHandler.getDoc project_id, doc_id, @callback
 
-		describe 'without pathname option', ->
-			beforeEach ->
-				@ProjectEntityHandler.getDoc project_id, doc_id, @callback
-
-			it "should call the docstore", ->
-				@DocstoreManager.getDoc
-					.calledWith(project_id, doc_id)
-					.should.equal true
-
-			it "should call the callback with the lines, version and rev", ->
-				@callback.calledWith(null, @lines, @rev, @version, @ranges).should.equal true
-
-		describe 'with pathname option', ->
-			beforeEach ->
-				@project = 'a project'
-				@path = mongo: "mongo.path", fileSystem: "/file/system/path"
-				@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, {}, @path)
-				@ProjectEntityHandler.getDoc project_id, doc_id, {pathname: true}, @callback
-
-			it "should call the project locator", ->
-				@ProjectLocator.findElement
-					.calledWith({project_id: project_id, element_id: doc_id, type: 'doc'})
-					.should.equal true
-
-			it "should call the docstore", ->
-				@DocstoreManager.getDoc
-					.calledWith(project_id, doc_id)
-					.should.equal true
+		it "should call the docstore", ->
+			@DocstoreManager.getDoc
+				.calledWith(project_id, doc_id)
+				.should.equal true
 
-			it "should return the pathname if option given", ->
-				@callback.calledWith(null, @lines, @rev, @version, @ranges, @path.fileSystem).should.equal true
+		it "should call the callback with the lines, version and rev", ->
+			@callback.calledWith(null, @lines, @rev, @version, @ranges).should.equal true

+ 10 - 10
services/web/test/unit/coffee/Project/ProjectEntityMongoUpdateHandlerTests.coffee

@@ -57,7 +57,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it 'gets the project', ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {rootFolder:true, name: true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it 'checks the folder exists', ->
@@ -80,7 +80,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it 'gets the project', ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {rootFolder:true, name: true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it 'checks the folder exists', ->
@@ -106,7 +106,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it 'gets the project', ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {rootFolder:true, name: true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it 'finds the existing element', ->
@@ -241,7 +241,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it 'should get the project', ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {rootFolder:true, name:true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it 'should find the doc to move', ->
@@ -267,7 +267,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 		it "calls the callback", ->
 			changes = { @oldDocs, @newDocs, @oldFiles, @newFiles }
 			@callback.calledWith(
-				null, @project.name, @path.fileSystem, @pathAfterMove.fileSystem, @doc.rev, changes
+				null, @project, @path.fileSystem, @pathAfterMove.fileSystem, @doc.rev, changes
 			).should.equal true
 
 	describe 'deleteEntity', ->
@@ -280,7 +280,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it "should get the project", ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {name:true, rootFolder:true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it "should find the element", ->
@@ -325,7 +325,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it 'should get the project', ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {rootFolder:true, name:true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it 'should find the doc', ->
@@ -349,7 +349,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 		it 'calls the callback', ->
 			changes = { @oldDocs, @newDocs, @oldFiles, @newFiles }
 			@callback.calledWith(
-				null, @project.name, '/old.tex', '/new.tex', @doc.rev, changes
+				null, @project, '/old.tex', '/new.tex', @doc.rev, changes
 			).should.equal true
 
 	describe 'addFolder', ->
@@ -363,7 +363,7 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 
 		it 'gets the project', ->
 			@ProjectGetter.getProjectWithoutLock
-				.calledWith(project_id, {rootFolder:true, name: true})
+				.calledWith(project_id, {rootFolder:true, name:true, overleaf:true})
 				.should.equal true
 
 		it 'checks the parent folder exists', ->
@@ -638,4 +638,4 @@ describe 'ProjectEntityMongoUpdateHandler', ->
 				.should.equal true
 
 		it "should call the callback", ->
-			@callback.called.should.equal true
+			@callback.called.should.equal true

+ 20 - 18
services/web/test/unit/coffee/Project/ProjectEntityUpdateHandlerTests.coffee

@@ -10,6 +10,7 @@ ObjectId = require("mongoose").Types.ObjectId
 
 describe 'ProjectEntityUpdateHandler', ->
 	project_id = '4eecb1c1bffa66588e0000a1'
+	projectHistoryId = '123456'
 	doc_id = '4eecb1c1bffa66588e0000a2'
 	file_id = "4eecaffcbffa66588e000009"
 	folder_id = "4eecaffcbffa66588e000008"
@@ -18,7 +19,12 @@ describe 'ProjectEntityUpdateHandler', ->
 	userId = 1234
 
 	beforeEach ->
-		@project = _id: project_id, name: 'project name'
+		@project =
+			_id: project_id,
+			name: 'project name'
+			overleaf:
+				history:
+					id: projectHistoryId
 		@fileUrl = 'filestore.example.com/file'
 		@FileStoreHandler =
 			uploadFileFromDisk: sinon.stub().yields(null, @fileUrl)
@@ -112,7 +118,7 @@ describe 'ProjectEntityUpdateHandler', ->
 				newFile.url == @fileUrl
 
 			@DocumentUpdaterHandler.updateProjectStructure
-				.calledWithMatch(project_id, userId, changesMatcher)
+				.calledWithMatch(project_id, projectHistoryId, userId, changesMatcher)
 				.should.equal true
 
 	describe 'updateDocLines', ->
@@ -257,7 +263,7 @@ describe 'ProjectEntityUpdateHandler', ->
 
 			@newDoc = _id: doc_id
 			@ProjectEntityUpdateHandler.addDocWithoutUpdatingHistory =
-				withoutLock: sinon.stub().yields(null, @newDoc, folder_id, @path)
+				withoutLock: sinon.stub().yields(null, @newDoc, folder_id, @path, @project)
 			@ProjectEntityUpdateHandler.addDoc project_id, folder_id, @docName, @docLines, userId, @callback
 
 		it "creates the doc without history", () ->
@@ -272,7 +278,7 @@ describe 'ProjectEntityUpdateHandler', ->
 				docLines: @docLines.join('\n')
 			]
 			@DocumentUpdaterHandler.updateProjectStructure
-				.calledWith(project_id, userId, {newDocs})
+				.calledWith(project_id, projectHistoryId, userId, {newDocs})
 				.should.equal true
 
 	describe 'addFile', ->
@@ -315,7 +321,7 @@ describe 'ProjectEntityUpdateHandler', ->
 				url: @fileUrl
 			]
 			@DocumentUpdaterHandler.updateProjectStructure
-				.calledWith(project_id, userId, {newFiles})
+				.calledWith(project_id, projectHistoryId, userId, {newFiles})
 				.should.equal true
 
 	describe 'replaceFile', ->
@@ -327,7 +333,6 @@ describe 'ProjectEntityUpdateHandler', ->
 			@newFile = _id: new_file_id, name: "dummy-upload-filename", rev: 0
 			@oldFile = _id: file_id
 			@path = "/path/to/file"
-			@project = _id: project_id, name: 'some project'
 			@ProjectEntityMongoUpdateHandler._insertDeletedFileReference = sinon.stub().yields()
 			@ProjectEntityMongoUpdateHandler.replaceFileWithNew = sinon.stub().yields(null, @oldFile, @project, fileSystem: @path)
 			@ProjectEntityUpdateHandler.replaceFile project_id, file_id, @fileSystemPath, @linkedFileData, userId, @callback
@@ -364,7 +369,7 @@ describe 'ProjectEntityUpdateHandler', ->
 				url: @newFileUrl
 			]
 			@DocumentUpdaterHandler.updateProjectStructure
-				.calledWith(project_id, userId, {oldFiles, newFiles})
+				.calledWith(project_id, projectHistoryId, userId, {oldFiles, newFiles})
 				.should.equal true
 
 	describe 'addDocWithoutUpdatingHistory', ->
@@ -704,7 +709,7 @@ describe 'ProjectEntityUpdateHandler', ->
 			@rev = 2
 			@changes = newDocs: ['old-doc'], newFiles: ['old-file']
 			@ProjectEntityMongoUpdateHandler.moveEntity = sinon.stub().yields(
-				null, @project_name, @startPath, @endPath, @rev, @changes
+				null, @project, @startPath, @endPath, @rev, @changes
 			)
 			@TpdsUpdateSender.moveEntity = sinon.stub()
 			@DocumentUpdaterHandler.updateProjectStructure = sinon.stub()
@@ -723,7 +728,7 @@ describe 'ProjectEntityUpdateHandler', ->
 
 		it 'sends the changes in project structure to the doc updater',  ->
 			@DocumentUpdaterHandler.updateProjectStructure
-				.calledWith(project_id, userId, @changes, @callback)
+				.calledWith(project_id, projectHistoryId, userId, @changes, @callback)
 				.should.equal true
 
 	describe "renameEntity", ->
@@ -735,7 +740,7 @@ describe 'ProjectEntityUpdateHandler', ->
 			@changes = newDocs: ['old-doc'], newFiles: ['old-file']
 			@newDocName = 'b.tex'
 			@ProjectEntityMongoUpdateHandler.renameEntity = sinon.stub().yields(
-				null, @project_name, @startPath, @endPath, @rev, @changes
+				null, @project, @startPath, @endPath, @rev, @changes
 			)
 			@TpdsUpdateSender.moveEntity = sinon.stub()
 			@DocumentUpdaterHandler.updateProjectStructure = sinon.stub()
@@ -754,7 +759,7 @@ describe 'ProjectEntityUpdateHandler', ->
 
 		it 'sends the changes in project structure to the doc updater',  ->
 			@DocumentUpdaterHandler.updateProjectStructure
-				.calledWith(project_id, userId, @changes, @callback)
+				.calledWith(project_id, projectHistoryId, userId, @changes, @callback)
 				.should.equal true
 
 	describe "resyncProjectHistory", ->
@@ -770,7 +775,7 @@ describe 'ProjectEntityUpdateHandler', ->
 
 		describe "a project without project-history enabled", ->
 			beforeEach ->
-				@project.ovreleaf = {}
+				@project.overleaf = {}
 				@ProjectGetter.getProject = sinon.stub().yields(null, @project)
 
 				@ProjectEntityUpdateHandler.resyncProjectHistory project_id, @callback
@@ -781,7 +786,6 @@ describe 'ProjectEntityUpdateHandler', ->
 
 		describe "a project with project-history enabled", ->
 			beforeEach ->
-				@project.overleaf = history: id: 4
 				@ProjectGetter.getProject = sinon.stub().yields(null, @project)
 				docs = [
 					doc: _id: doc_id
@@ -819,7 +823,7 @@ describe 'ProjectEntityUpdateHandler', ->
 					url: "www.filestore.test/#{project_id}/#{file_id}"
 				]
 				@DocumentUpdaterHandler.resyncProjectHistory
-					.calledWith(project_id, docs, files)
+					.calledWith(project_id, projectHistoryId, docs, files)
 					.should.equal true
 
 			it 'calls the callback', ->
@@ -853,7 +857,7 @@ describe 'ProjectEntityUpdateHandler', ->
 			it "should should send the update to the doc updater", ->
 				oldFiles = [ file: @entity, path: @path ]
 				@DocumentUpdaterHandler.updateProjectStructure
-					.calledWith(project_id, userId, {oldFiles})
+					.calledWith(project_id, projectHistoryId, userId, {oldFiles})
 					.should.equal true
 
 		describe "a doc", ->
@@ -903,8 +907,6 @@ describe 'ProjectEntityUpdateHandler', ->
 
 	describe "_cleanUpDoc", ->
 		beforeEach ->
-			@project =
-				_id: ObjectId(project_id)
 			@doc =
 				_id: ObjectId()
 				name: "test.tex"
@@ -942,7 +944,7 @@ describe 'ProjectEntityUpdateHandler', ->
 			it "should should send the update to the doc updater", ->
 				oldDocs = [ doc: @doc, path: @path ]
 				@DocumentUpdaterHandler.updateProjectStructure
-					.calledWith(project_id, userId, {oldDocs})
+					.calledWith(project_id, projectHistoryId, userId, {oldDocs})
 					.should.equal true
 
 			it "should call the callback", ->