From 94b25055fcf705dcbcb8f629f1406d87b8ab0a5b Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 28 Apr 2014 17:43:19 +0100 Subject: [PATCH] Add in DocManager.updateDoc method --- services/docstore/.gitignore | 1 + services/docstore/app.coffee | 6 +- .../docstore/app/coffee/DocManager.coffee | 30 +++++- .../docstore/app/coffee/MongoManager.coffee | 11 ++- services/docstore/package.json | 3 +- .../test/unit/coffee/DocManagerTests.coffee | 93 ++++++++++++++++++- .../test/unit/coffee/MongoManagerTests.coffee | 25 +++++ 7 files changed, 158 insertions(+), 11 deletions(-) diff --git a/services/docstore/.gitignore b/services/docstore/.gitignore index 6617e40b2a..fadf405279 100644 --- a/services/docstore/.gitignore +++ b/services/docstore/.gitignore @@ -2,3 +2,4 @@ node_modules app/js/ test/unit/js app.js +forever diff --git a/services/docstore/app.coffee b/services/docstore/app.coffee index b3932ffd46..b61287fec6 100644 --- a/services/docstore/app.coffee +++ b/services/docstore/app.coffee @@ -4,6 +4,7 @@ logger.initialize("docstore") express = require('express') HttpController = require "./app/js/HttpController" +Errors = require "./app/js/Errors" app = express() @@ -14,7 +15,10 @@ app.get '/status', (req, res)-> app.use (error, req, res, next) -> logger.error err: error, "request errored" - res.send(500, "Oops, something went wrong") + if error instanceof Errors.NotFoundError + res.send 404 + else + res.send(500, "Oops, something went wrong") port = Settings.internal.docstore.port host = Settings.internal.docstore.host diff --git a/services/docstore/app/coffee/DocManager.coffee b/services/docstore/app/coffee/DocManager.coffee index 201868f882..047d32f552 100644 --- a/services/docstore/app/coffee/DocManager.coffee +++ b/services/docstore/app/coffee/DocManager.coffee @@ -1,13 +1,35 @@ MongoManager = require "./MongoManager" +Errors = require "./Errors" +logger = require "logger-sharelatex" +_ = require "underscore" module.exports = DocManager = - getDoc: (project_id, doc_id, callback = (error, doc) ->) -> + getDoc: (project_id, doc_id, callback = (error, doc, mongoPath) ->) -> MongoManager.findProject project_id, (error, project) -> return callback(error) if error? - return callback null, null if !project? - DocManager.findDocInProject project, doc_id, (error, doc) -> + return callback new Errors.NotFoundError("No such project: #{project_id}") if !project? + DocManager.findDocInProject project, doc_id, (error, doc, mongoPath) -> return callback(error) if error? - return callback null, doc + return callback new Errors.NotFoundError("No such doc: #{project_id}") if !doc? + return callback null, doc, mongoPath + + updateDoc: (project_id, doc_id, lines, callback = (error) ->) -> + DocManager.getDoc project_id, doc_id, (error, doc, mongoPath) -> + return callback(error) if error? + return callback new Errors.NotFoundError("No such project/doc: #{project_id}/#{doc_id}") if !doc? + + if _.isEqual(doc.lines, lines) + logger.log { + project_id: project_id, doc_id: doc_id, rev: doc.rev + }, "doc lines have not changed" + return callback() + else + logger.log { + project_id: project_id, doc_id: doc_id, oldDocLines: doc.lines, newDocLines: lines, rev: doc.rev + }, "updating doc lines" + MongoManager.updateDoc project_id, mongoPath, lines, (error) -> + return callback(error) if error? + callback() findDocInProject: (project, doc_id, callback = (error, doc, mongoPath) ->) -> result = @_findDocInFolder project.rootFolder[0], doc_id, "rootFolder.0" diff --git a/services/docstore/app/coffee/MongoManager.coffee b/services/docstore/app/coffee/MongoManager.coffee index a3f97f73b1..422e678255 100644 --- a/services/docstore/app/coffee/MongoManager.coffee +++ b/services/docstore/app/coffee/MongoManager.coffee @@ -3,4 +3,13 @@ module.exports = MongoManager = findProject: (project_id, callback = (error, project) ->) -> db.projects.find _id: ObjectId(project_id.toString()), {}, (error, projects = []) -> - callback error, projects[0] \ No newline at end of file + callback error, projects[0] + + updateDoc: (project_id, docPath, lines, callback = (error) ->) -> + update = + $set: {} + $inc: {} + update.$set["#{docPath}.lines"] = lines + update.$inc["#{docPath}.rev"] = 1 + + db.projects.update _id: ObjectId(project_id), update, callback \ No newline at end of file diff --git a/services/docstore/package.json b/services/docstore/package.json index 02466a9fd7..94335c97f4 100644 --- a/services/docstore/package.json +++ b/services/docstore/package.json @@ -7,7 +7,8 @@ "settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#master", "logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#master", "mongojs": "0.9.11", - "express": "~4.1.1" + "express": "~4.1.1", + "underscore": "~1.6.0" }, "devDependencies": { "grunt-execute": "~0.2.1", diff --git a/services/docstore/test/unit/coffee/DocManagerTests.coffee b/services/docstore/test/unit/coffee/DocManagerTests.coffee index 7afc546964..525bf7cb7e 100644 --- a/services/docstore/test/unit/coffee/DocManagerTests.coffee +++ b/services/docstore/test/unit/coffee/DocManagerTests.coffee @@ -5,11 +5,13 @@ chai.should() expect = chai.expect modulePath = require('path').join __dirname, '../../../app/js/DocManager' ObjectId = require("mongojs").ObjectId +Errors = require "../../../app/js/Errors" describe "DocManager", -> beforeEach -> @DocManager = SandboxedModule.require modulePath, requires: "./MongoManager": @MongoManager = {} + "logger-sharelatex": @logger = {log: sinon.stub()} @doc_id = ObjectId().toString() @project_id = ObjectId().toString() @callback = sinon.stub() @@ -19,8 +21,9 @@ describe "DocManager", -> beforeEach -> @project = { name: "mock-project" } @doc = { _id: @doc_id, lines: ["mock-lines"] } + @mongoPath = "mock.mongo.path" @MongoManager.findProject = sinon.stub().callsArgWith(1, null, @project) - @DocManager.findDocInProject = sinon.stub().callsArgWith(2, null, @doc) + @DocManager.findDocInProject = sinon.stub().callsArgWith(2, null, @doc, @mongoPath) @DocManager.getDoc @project_id, @doc_id, @callback it "should get the project from the database", -> @@ -34,7 +37,7 @@ describe "DocManager", -> .should.equal true it "should return the doc", -> - @callback.calledWith(null, @doc).should.equal true + @callback.calledWith(null, @doc, @mongoPath).should.equal true describe "when the project does not exist", -> beforeEach -> @@ -45,8 +48,90 @@ describe "DocManager", -> it "should not try to find the doc in the project", -> @DocManager.findDocInProject.called.should.equal false - it "should return null", -> - @callback.calledWith(null, null).should.equal true + it "should return a NotFoundError", -> + @callback + .calledWith(new Errors.NotFoundError("No such project: #{@project_id}")) + .should.equal true + + describe "when the doc does not exist", -> + beforeEach -> + @project = { name: "mock-project" } + @MongoManager.findProject = sinon.stub().callsArgWith(1, null, @project) + @DocManager.findDocInProject = sinon.stub().callsArgWith(2, null, null, null) + @DocManager.getDoc @project_id, @doc_id, @callback + + it "should try to find the doc in the project", -> + @DocManager.findDocInProject + .calledWith(@project, @doc_id) + .should.equal true + + it "should return a NotFoundError", -> + @callback + .calledWith(new Errors.NotFoundError("No such doc: #{@doc_id}")) + .should.equal true + + describe "updateDoc", -> + beforeEach -> + @oldDocLines = ["old", "doc", "lines"] + @newDocLines = ["new", "doc", "lines"] + @doc = { _id: @doc_id, lines: @oldDocLines, rev: 42 } + @mongoPath = "mock.mongo.path" + + @MongoManager.updateDoc = sinon.stub().callsArg(3) + + describe "when the doc lines have changed", -> + beforeEach -> + @DocManager.getDoc = sinon.stub().callsArgWith(2, null, @doc, @mongoPath) + @DocManager.updateDoc @project_id, @doc_id, @newDocLines, @callback + + it "should get the existing doc", -> + @DocManager.getDoc + .calledWith(@project_id, @doc_id) + .should.equal true + + it "should update the doc with the new doc lines", -> + @MongoManager.updateDoc + .calledWith(@project_id, @mongoPath, @newDocLines) + .should.equal true + + it "should log out the old and new doc lines", -> + @logger.log + .calledWith( + project_id: @project_id + doc_id: @doc_id + oldDocLines: @oldDocLines + newDocLines: @newDocLines + rev: @doc.rev + "updating doc lines" + ) + .should.equal true + + it "should return the callback", -> + @callback.called.should.equal true + + describe "when the doc lines have not changed", -> + beforeEach -> + @DocManager.getDoc = sinon.stub().callsArgWith(2, null, @doc, @mongoPath) + @DocManager.updateDoc @project_id, @doc_id, @oldDocLines.slice(), @callback + + it "should not update the doc", -> + @MongoManager.updateDoc.called.should.equal false + + it "should return the callback", -> + @callback.called.should.equal true + + describe "when the doc does not exist", -> + beforeEach -> + @DocManager.getDoc = sinon.stub().callsArgWith(2, null, null, null) + @DocManager.updateDoc @project_id, @doc_id, @newDocLines, @callback + + it "should not try to update the doc", -> + @MongoManager.updateDoc.called.should.equal false + + it "should return a NotFoundError", -> + @callback + .calledWith(new Errors.NotFoundError("No such project/doc: #{@project_id}/#{@doc_id}")) + .should.equal true describe "findDocInProject", -> it "should find the doc when it is in the root folder", (done) -> diff --git a/services/docstore/test/unit/coffee/MongoManagerTests.coffee b/services/docstore/test/unit/coffee/MongoManagerTests.coffee index b3706004f1..61c0b45de6 100644 --- a/services/docstore/test/unit/coffee/MongoManagerTests.coffee +++ b/services/docstore/test/unit/coffee/MongoManagerTests.coffee @@ -25,3 +25,28 @@ describe "MongoManager", -> _id: ObjectId(@project_id) }, {}) .should.equal true + + it "should call the callback with the project", -> + @callback.calledWith(null, @project).should.equal true + + describe "updateDoc", -> + beforeEach -> + @lines = ["mock-lines"] + @docPath = "rootFolder.0.folders.1.docs.0" + @db.projects.update = sinon.stub().callsArg(2) + @MongoManager.updateDoc @project_id, @docPath, @lines, @callback + + it "should update the doc lines and increment the TPDS rev", -> + @db.projects.update + .calledWith({ + _id: ObjectId(@project_id) + }, { + $set: + "rootFolder.0.folders.1.docs.0.lines": @lines + $inc: + "rootFolder.0.folders.1.docs.0.rev": 1 + }) + .should.equal true + + it "should call the callback with the project", -> + @callback.called.should.equal true