mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Add POST end point for updating doc lines
This commit is contained in:
parent
94b25055fc
commit
2e8582874f
11 changed files with 265 additions and 40 deletions
1
services/docstore/.gitignore
vendored
1
services/docstore/.gitignore
vendored
|
@ -1,5 +1,6 @@
|
|||
node_modules
|
||||
app/js/
|
||||
test/unit/js
|
||||
test/acceptance/js
|
||||
app.js
|
||||
forever
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
Settings = require('settings-sharelatex')
|
||||
logger = require('logger-sharelatex')
|
||||
logger.initialize("docstore")
|
||||
|
||||
express = require('express')
|
||||
Settings = require "settings-sharelatex"
|
||||
logger = require "logger-sharelatex"
|
||||
express = require "express"
|
||||
bodyParser = require "body-parser"
|
||||
Errors = require "./app/js/Errors"
|
||||
HttpController = require "./app/js/HttpController"
|
||||
Errors = require "./app/js/Errors"
|
||||
|
||||
logger.initialize("docstore")
|
||||
|
||||
app = express()
|
||||
|
||||
app.get '/project/:project_id/doc/:doc_id', HttpController.getDoc
|
||||
app.get '/project/:project_id/doc/:doc_id', HttpController.getDoc
|
||||
app.post '/project/:project_id/doc/:doc_id', bodyParser.json(), HttpController.updateDoc
|
||||
|
||||
app.get '/status', (req, res)->
|
||||
res.send('docstore is alive')
|
||||
|
|
|
@ -13,7 +13,7 @@ module.exports = DocManager =
|
|||
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) ->) ->
|
||||
updateDoc: (project_id, doc_id, lines, callback = (error, modified) ->) ->
|
||||
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?
|
||||
|
@ -22,14 +22,14 @@ module.exports = DocManager =
|
|||
logger.log {
|
||||
project_id: project_id, doc_id: doc_id, rev: doc.rev
|
||||
}, "doc lines have not changed"
|
||||
return callback()
|
||||
return callback null, false
|
||||
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()
|
||||
callback null, true
|
||||
|
||||
findDocInProject: (project, doc_id, callback = (error, doc, mongoPath) ->) ->
|
||||
result = @_findDocInFolder project.rootFolder[0], doc_id, "rootFolder.0"
|
||||
|
|
10
services/docstore/app/coffee/Errors.coffee
Normal file
10
services/docstore/app/coffee/Errors.coffee
Normal file
|
@ -0,0 +1,10 @@
|
|||
NotFoundError = (message) ->
|
||||
error = new Error(message)
|
||||
error.name = "NotFoundError"
|
||||
error.__proto__ = NotFoundError.prototype
|
||||
return error
|
||||
NotFoundError.prototype.__proto__ = Error.prototype
|
||||
|
||||
module.exports = Errors =
|
||||
NotFoundError: NotFoundError
|
||||
|
|
@ -4,11 +4,30 @@ logger = require "logger-sharelatex"
|
|||
module.exports = HttpController =
|
||||
getDoc: (req, res, next = (error) ->) ->
|
||||
project_id = req.params.project_id
|
||||
doc_id = req.params.doc_id
|
||||
doc_id = req.params.doc_id
|
||||
logger.log project_id: project_id, doc_id: doc_id, "getting doc"
|
||||
DocManager.getDoc project_id, doc_id, (error, doc) ->
|
||||
return next(error) if error?
|
||||
if !doc?
|
||||
res.send 404
|
||||
else
|
||||
res.send JSON.stringify({ lines: doc.lines })
|
||||
res.json {
|
||||
lines: doc.lines
|
||||
}
|
||||
|
||||
updateDoc: (req, res, next = (error) ->) ->
|
||||
project_id = req.params.project_id
|
||||
doc_id = req.params.doc_id
|
||||
lines = req.body?.lines
|
||||
|
||||
if !lines? or lines not instanceof Array
|
||||
logger.error project_id: project_id, doc_id: doc_id, "no doc lines provided"
|
||||
res.send 400 # Bad Request
|
||||
return
|
||||
|
||||
logger.log project_id: project_id, doc_id: doc_id, "updating doc"
|
||||
DocManager.updateDoc project_id, doc_id, lines, (error, modified) ->
|
||||
return next(error) if error?
|
||||
res.json {
|
||||
modified: modified
|
||||
}
|
|
@ -8,7 +8,8 @@
|
|||
"logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#master",
|
||||
"mongojs": "0.9.11",
|
||||
"express": "~4.1.1",
|
||||
"underscore": "~1.6.0"
|
||||
"underscore": "~1.6.0",
|
||||
"body-parser": "~1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt-execute": "~0.2.1",
|
||||
|
@ -22,6 +23,7 @@
|
|||
"sinon": "~1.5.2",
|
||||
"sandboxed-module": "~0.3.0",
|
||||
"chai": "~1.9.1",
|
||||
"grunt-forever": "~0.4.4"
|
||||
"grunt-forever": "~0.4.4",
|
||||
"request": "~2.34.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
sinon = require "sinon"
|
||||
chai = require("chai")
|
||||
chai.should()
|
||||
{ObjectId} = require "mongojs"
|
||||
|
||||
DocstoreClient = require "./helpers/DocstoreClient"
|
||||
|
||||
describe "Applying updates to a doc", ->
|
||||
beforeEach (done) ->
|
||||
@project_id = ObjectId()
|
||||
@lines = ["original", "lines"]
|
||||
DocstoreClient.createDoc @project_id, @lines, (error, @doc_id) =>
|
||||
done()
|
||||
|
||||
afterEach (done) ->
|
||||
DocstoreClient.deleteProject @project_id, done
|
||||
|
||||
describe "when the doc exists", ->
|
||||
it "should get the doc lines", (done) ->
|
||||
DocstoreClient.getDoc @project_id, @doc_id, (error, res, doc) =>
|
||||
doc.lines.should.deep.equal @lines
|
||||
done()
|
||||
|
||||
describe "when the doc does not exist", ->
|
||||
it "should return a 404", (done) ->
|
||||
missing_doc_id = ObjectId()
|
||||
DocstoreClient.getDoc @project_id, missing_doc_id, (error, res, doc) ->
|
||||
res.statusCode.should.equal 404
|
||||
done()
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
sinon = require "sinon"
|
||||
chai = require("chai")
|
||||
chai.should()
|
||||
{ObjectId} = require "mongojs"
|
||||
|
||||
DocstoreClient = require "./helpers/DocstoreClient"
|
||||
|
||||
describe "Applying updates to a doc", ->
|
||||
beforeEach (done) ->
|
||||
@project_id = ObjectId()
|
||||
@originalLines = ["original", "lines"]
|
||||
@newLines = ["new", "lines"]
|
||||
DocstoreClient.createDoc @project_id, @originalLines, (error, @doc_id) =>
|
||||
done()
|
||||
|
||||
afterEach (done) ->
|
||||
DocstoreClient.deleteProject @project_id, done
|
||||
|
||||
describe "when the content has changed", ->
|
||||
beforeEach (done) ->
|
||||
DocstoreClient.updateDoc @project_id, @doc_id, @newLines, (error, res, @body) =>
|
||||
done()
|
||||
|
||||
it "should return modified = true", ->
|
||||
@body.modified.should.equal true
|
||||
|
||||
it "should update the doc in the API", (done) ->
|
||||
DocstoreClient.getDoc @project_id, @doc_id, (error, res, doc) =>
|
||||
doc.lines.should.deep.equal @newLines
|
||||
done()
|
||||
|
||||
describe "when the content has not been updated", ->
|
||||
beforeEach (done) ->
|
||||
DocstoreClient.updateDoc @project_id, @doc_id, @originalLines, (error, res, @body) =>
|
||||
done()
|
||||
|
||||
it "should return modified = false", ->
|
||||
@body.modified.should.equal false
|
||||
|
||||
it "should not update the doc in the API", (done) ->
|
||||
DocstoreClient.getDoc @project_id, @doc_id, (error, res, doc) =>
|
||||
doc.lines.should.deep.equal @originalLines
|
||||
done()
|
||||
|
||||
describe "when the doc does not exist", ->
|
||||
beforeEach (done) ->
|
||||
missing_doc_id = ObjectId()
|
||||
DocstoreClient.updateDoc @project_id, missing_doc_id, @originalLines, (error, @res, @body) =>
|
||||
done()
|
||||
|
||||
it "should return a 404", ->
|
||||
@res.statusCode.should.equal 404
|
||||
|
||||
describe "when the project does not exist", ->
|
||||
beforeEach (done) ->
|
||||
missing_project_id = ObjectId()
|
||||
DocstoreClient.updateDoc missing_project_id, @doc_id, @originalLines, (error, @res, @body) =>
|
||||
done()
|
||||
|
||||
it "should return a 404", ->
|
||||
@res.statusCode.should.equal 404
|
||||
|
||||
describe "when malformed doc lines are provided", ->
|
||||
describe "when the lines are not an array", ->
|
||||
beforeEach (done) ->
|
||||
DocstoreClient.updateDoc @project_id, @doc_id, { foo: "bar" }, (error, @res, @body) =>
|
||||
done()
|
||||
|
||||
it "should return 400", ->
|
||||
@res.statusCode.should.equal 400
|
||||
|
||||
it "should not update the doc in the API", (done) ->
|
||||
DocstoreClient.getDoc @project_id, @doc_id, (error, res, doc) =>
|
||||
doc.lines.should.deep.equal @originalLines
|
||||
done()
|
||||
|
||||
describe "when the lines are not present", ->
|
||||
beforeEach (done) ->
|
||||
DocstoreClient.updateDoc @project_id, @doc_id, null, (error, @res, @body) =>
|
||||
done()
|
||||
|
||||
it "should return 400", ->
|
||||
@res.statusCode.should.equal 400
|
||||
|
||||
it "should not update the doc in the API", (done) ->
|
||||
DocstoreClient.getDoc @project_id, @doc_id, (error, res, doc) =>
|
||||
doc.lines.should.deep.equal @originalLines
|
||||
done()
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
request = require("request").defaults(jar: false)
|
||||
{db, ObjectId} = require("../../../../app/js/mongojs")
|
||||
|
||||
module.exports = DocstoreClient =
|
||||
createDoc: (project_id, lines, callback = (error, doc_id) ->) ->
|
||||
doc_id = ObjectId()
|
||||
db.projects.insert {
|
||||
_id: project_id
|
||||
rootFolder: [{
|
||||
docs: [{
|
||||
_id: doc_id,
|
||||
lines: lines
|
||||
}]
|
||||
}]
|
||||
}, (error) ->
|
||||
return callback(error) if error?
|
||||
callback null, doc_id
|
||||
|
||||
deleteProject: (project_id, callback = (error, res, body) ->) ->
|
||||
db.projects.remove _id: project_id, callback
|
||||
|
||||
getDoc: (project_id, doc_id, callback = (error, doc) ->) ->
|
||||
request.get {
|
||||
url: "http://localhost:3016/project/#{project_id}/doc/#{doc_id}"
|
||||
json: true
|
||||
}, callback
|
||||
|
||||
updateDoc: (project_id, doc_id, lines, callback = (error, res, body) ->) ->
|
||||
request.post {
|
||||
url: "http://localhost:3016/project/#{project_id}/doc/#{doc_id}"
|
||||
json:
|
||||
lines: lines
|
||||
}, callback
|
||||
|
||||
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ describe "DocManager", ->
|
|||
.should.equal true
|
||||
|
||||
it "should return the callback", ->
|
||||
@callback.called.should.equal true
|
||||
@callback.calledWith(null, true).should.equal true
|
||||
|
||||
describe "when the doc lines have not changed", ->
|
||||
beforeEach ->
|
||||
|
@ -118,7 +118,7 @@ describe "DocManager", ->
|
|||
@MongoManager.updateDoc.called.should.equal false
|
||||
|
||||
it "should return the callback", ->
|
||||
@callback.called.should.equal true
|
||||
@callback.calledWith(null, false).should.equal true
|
||||
|
||||
describe "when the doc does not exist", ->
|
||||
beforeEach ->
|
||||
|
|
|
@ -9,8 +9,8 @@ describe "HttpController", ->
|
|||
beforeEach ->
|
||||
@HttpController = SandboxedModule.require modulePath, requires:
|
||||
"./DocManager": @DocManager = {}
|
||||
"logger-sharelatex": @logger = { log: sinon.stub() }
|
||||
@res = { send: sinon.stub() }
|
||||
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
||||
@res = { send: sinon.stub(), json: sinon.stub() }
|
||||
@req = {}
|
||||
@next = sinon.stub()
|
||||
@project_id = "mock-project-id"
|
||||
|
@ -21,33 +21,68 @@ describe "HttpController", ->
|
|||
}
|
||||
|
||||
describe "getDoc", ->
|
||||
describe "when the doc exists", ->
|
||||
beforeEach ->
|
||||
@req.params =
|
||||
project_id: @project_id
|
||||
doc_id: @doc_id
|
||||
@DocManager.getDoc = sinon.stub().callsArgWith(2, null, @doc)
|
||||
@HttpController.getDoc @req, @res, @next
|
||||
|
||||
it "should get the document", ->
|
||||
@DocManager.getDoc
|
||||
.calledWith(@project_id, @doc_id)
|
||||
.should.equal true
|
||||
|
||||
it "should return the doc as JSON", ->
|
||||
@res.json
|
||||
.calledWith(lines: @doc.lines)
|
||||
.should.equal true
|
||||
|
||||
describe "updateDoc", ->
|
||||
beforeEach ->
|
||||
@req.params =
|
||||
project_id: @project_id
|
||||
doc_id: @doc_id
|
||||
|
||||
describe "when the doc lines exist and were updated", ->
|
||||
beforeEach ->
|
||||
@req.params =
|
||||
project_id: @project_id
|
||||
doc_id: @doc_id
|
||||
@DocManager.getDoc = sinon.stub().callsArgWith(2, null, @doc)
|
||||
@HttpController.getDoc @req, @res, @next
|
||||
@req.body =
|
||||
lines: @lines = ["hello", "world"]
|
||||
@DocManager.updateDoc = sinon.stub().callsArgWith(3, null, true)
|
||||
@HttpController.updateDoc @req, @res, @next
|
||||
|
||||
it "should get the document", ->
|
||||
@DocManager.getDoc
|
||||
.calledWith(@project_id, @doc_id)
|
||||
it "should update the document", ->
|
||||
@DocManager.updateDoc
|
||||
.calledWith(@project_id, @doc_id, @lines)
|
||||
.should.equal true
|
||||
|
||||
it "should return the doc as JSON", ->
|
||||
@res.send
|
||||
.calledWith(JSON.stringify(lines: @doc.lines))
|
||||
it "should return a modified status", ->
|
||||
@res.json
|
||||
.calledWith(modified: true)
|
||||
.should.equal true
|
||||
|
||||
describe "when the doc does not exist", ->
|
||||
describe "when the doc lines exist and were not updated", ->
|
||||
beforeEach ->
|
||||
@req.params =
|
||||
project_id: @project_id
|
||||
doc_id: @doc_id
|
||||
@DocManager.getDoc = sinon.stub().callsArgWith(2, null, null)
|
||||
@HttpController.getDoc @req, @res, @next
|
||||
@req.body =
|
||||
lines: @lines = ["hello", "world"]
|
||||
@DocManager.updateDoc = sinon.stub().callsArgWith(3, null, false)
|
||||
@HttpController.updateDoc @req, @res, @next
|
||||
|
||||
it "should return a 404", ->
|
||||
@res.send
|
||||
.calledWith(404)
|
||||
it "should return a modified status", ->
|
||||
@res.json
|
||||
.calledWith(modified: false)
|
||||
.should.equal true
|
||||
|
||||
describe "when the doc lines are not provided", ->
|
||||
beforeEach ->
|
||||
@req.body = {}
|
||||
@DocManager.updateDoc = sinon.stub().callsArgWith(3, null, false)
|
||||
@HttpController.updateDoc @req, @res, @next
|
||||
|
||||
it "should not update the document", ->
|
||||
@DocManager.updateDoc.called.should.equal false
|
||||
|
||||
it "should return a 400 (bad request) response", ->
|
||||
@res.send
|
||||
.calledWith(400)
|
||||
.should.equal true
|
Loading…
Reference in a new issue