mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #7581 from overleaf/em-docstore-decaf
Decaf cleanup in docstore GitOrigin-RevId: 84553cec7f184d567dc796c4016d6a412fb8db99
This commit is contained in:
parent
e0d5cf4b42
commit
552d6d4baa
4 changed files with 643 additions and 709 deletions
|
@ -1,329 +1,296 @@
|
|||
/* eslint-disable
|
||||
camelcase,
|
||||
valid-typeof,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
let HttpController
|
||||
const DocManager = require('./DocManager')
|
||||
const logger = require('@overleaf/logger')
|
||||
const DocArchive = require('./DocArchiveManager')
|
||||
const HealthChecker = require('./HealthChecker')
|
||||
const Settings = require('@overleaf/settings')
|
||||
|
||||
module.exports = HttpController = {
|
||||
getDoc(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
function getDoc(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
const includeDeleted = req.query.include_deleted === 'true'
|
||||
logger.log({ projectId, docId }, 'getting doc')
|
||||
DocManager.getFullDoc(projectId, docId, function (error, doc) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
const { project_id } = req.params
|
||||
const { doc_id } = req.params
|
||||
const include_deleted =
|
||||
(req.query != null ? req.query.include_deleted : undefined) === 'true'
|
||||
logger.log({ project_id, doc_id }, 'getting doc')
|
||||
return DocManager.getFullDoc(project_id, doc_id, function (error, doc) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
logger.log({ doc_id, project_id }, 'got doc')
|
||||
if (doc == null) {
|
||||
return res.sendStatus(404)
|
||||
} else if (doc.deleted && !include_deleted) {
|
||||
return res.sendStatus(404)
|
||||
} else {
|
||||
return res.json(HttpController._buildDocView(doc))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
peekDoc(req, res, next) {
|
||||
const { project_id } = req.params
|
||||
const { doc_id } = req.params
|
||||
logger.log({ project_id, doc_id }, 'peeking doc')
|
||||
DocManager.peekDoc(project_id, doc_id, function (error, doc) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
if (doc == null) {
|
||||
return res.sendStatus(404)
|
||||
} else {
|
||||
res.setHeader('x-doc-status', doc.inS3 ? 'archived' : 'active')
|
||||
return res.json(HttpController._buildDocView(doc))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
isDocDeleted(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
DocManager.isDocDeleted(projectId, docId, function (error, deleted) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json({ deleted })
|
||||
})
|
||||
},
|
||||
|
||||
getRawDoc(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
logger.log({ docId, projectId }, 'got doc')
|
||||
if (doc == null) {
|
||||
res.sendStatus(404)
|
||||
} else if (doc.deleted && !includeDeleted) {
|
||||
res.sendStatus(404)
|
||||
} else {
|
||||
res.json(_buildDocView(doc))
|
||||
}
|
||||
const { project_id } = req.params
|
||||
const { doc_id } = req.params
|
||||
logger.log({ project_id, doc_id }, 'getting raw doc')
|
||||
return DocManager.getDocLines(project_id, doc_id, function (error, doc) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
if (doc == null) {
|
||||
return res.sendStatus(404)
|
||||
} else {
|
||||
res.setHeader('content-type', 'text/plain')
|
||||
return res.send(HttpController._buildRawDocView(doc))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getAllDocs(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
}
|
||||
const { project_id } = req.params
|
||||
logger.log({ project_id }, 'getting all docs')
|
||||
return DocManager.getAllNonDeletedDocs(
|
||||
project_id,
|
||||
{ lines: true, rev: true },
|
||||
function (error, docs) {
|
||||
if (docs == null) {
|
||||
docs = []
|
||||
}
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.json(HttpController._buildDocsArrayView(project_id, docs))
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
getAllDeletedDocs(req, res, next) {
|
||||
const { project_id } = req.params
|
||||
logger.log({ project_id }, 'getting all deleted docs')
|
||||
DocManager.getAllDeletedDocs(
|
||||
project_id,
|
||||
{ name: true, deletedAt: true },
|
||||
function (error, docs) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json(
|
||||
docs.map(doc => {
|
||||
return {
|
||||
_id: doc._id.toString(),
|
||||
name: doc.name,
|
||||
deletedAt: doc.deletedAt,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
getAllRanges(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
}
|
||||
const { project_id } = req.params
|
||||
logger.log({ project_id }, 'getting all ranges')
|
||||
return DocManager.getAllNonDeletedDocs(
|
||||
project_id,
|
||||
{ ranges: true },
|
||||
function (error, docs) {
|
||||
if (docs == null) {
|
||||
docs = []
|
||||
}
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.json(HttpController._buildDocsArrayView(project_id, docs))
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
updateDoc(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
}
|
||||
const { project_id } = req.params
|
||||
const { doc_id } = req.params
|
||||
const lines = req.body != null ? req.body.lines : undefined
|
||||
const version = req.body != null ? req.body.version : undefined
|
||||
const ranges = req.body != null ? req.body.ranges : undefined
|
||||
|
||||
if (lines == null || !(lines instanceof Array)) {
|
||||
logger.error({ project_id, doc_id }, 'no doc lines provided')
|
||||
res.sendStatus(400) // Bad Request
|
||||
return
|
||||
}
|
||||
|
||||
if (version == null || typeof version === !'number') {
|
||||
logger.error({ project_id, doc_id }, 'no doc version provided')
|
||||
res.sendStatus(400) // Bad Request
|
||||
return
|
||||
}
|
||||
|
||||
if (ranges == null) {
|
||||
logger.error({ project_id, doc_id }, 'no doc ranges provided')
|
||||
res.sendStatus(400) // Bad Request
|
||||
return
|
||||
}
|
||||
|
||||
const bodyLength = lines.reduce((len, line) => line.length + len, 0)
|
||||
if (bodyLength > Settings.max_doc_length) {
|
||||
logger.error(
|
||||
{ project_id, doc_id, bodyLength },
|
||||
'document body too large'
|
||||
)
|
||||
res.status(413).send('document body too large')
|
||||
return
|
||||
}
|
||||
|
||||
logger.log({ project_id, doc_id }, 'got http request to update doc')
|
||||
return DocManager.updateDoc(
|
||||
project_id,
|
||||
doc_id,
|
||||
lines,
|
||||
version,
|
||||
ranges,
|
||||
function (error, modified, rev) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.json({
|
||||
modified,
|
||||
rev,
|
||||
})
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
patchDoc(req, res, next) {
|
||||
const { project_id, doc_id } = req.params
|
||||
logger.log({ project_id, doc_id }, 'patching doc')
|
||||
|
||||
const allowedFields = ['deleted', 'deletedAt', 'name']
|
||||
const meta = {}
|
||||
Object.entries(req.body).forEach(([field, value]) => {
|
||||
if (allowedFields.includes(field)) {
|
||||
meta[field] = value
|
||||
} else {
|
||||
logger.fatal({ field }, 'joi validation for pathDoc is broken')
|
||||
}
|
||||
})
|
||||
DocManager.patchDoc(project_id, doc_id, meta, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
},
|
||||
|
||||
_buildDocView(doc) {
|
||||
const doc_view = { _id: doc._id != null ? doc._id.toString() : undefined }
|
||||
for (const attribute of ['lines', 'rev', 'version', 'ranges', 'deleted']) {
|
||||
if (doc[attribute] != null) {
|
||||
doc_view[attribute] = doc[attribute]
|
||||
}
|
||||
}
|
||||
return doc_view
|
||||
},
|
||||
|
||||
_buildRawDocView(doc) {
|
||||
return ((doc != null ? doc.lines : undefined) || []).join('\n')
|
||||
},
|
||||
|
||||
_buildDocsArrayView(project_id, docs) {
|
||||
const docViews = []
|
||||
for (const doc of Array.from(docs)) {
|
||||
if (doc != null) {
|
||||
// There can end up being null docs for some reason :( (probably a race condition)
|
||||
docViews.push(HttpController._buildDocView(doc))
|
||||
} else {
|
||||
logger.error(
|
||||
{ err: new Error('null doc'), project_id },
|
||||
'encountered null doc'
|
||||
)
|
||||
}
|
||||
}
|
||||
return docViews
|
||||
},
|
||||
|
||||
archiveAllDocs(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
}
|
||||
const { project_id } = req.params
|
||||
logger.log({ project_id }, 'archiving all docs')
|
||||
return DocArchive.archiveAllDocs(project_id, function (error) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(204)
|
||||
})
|
||||
},
|
||||
|
||||
archiveDoc(req, res, next) {
|
||||
const { project_id, doc_id } = req.params
|
||||
logger.log({ project_id, doc_id }, 'archiving a doc')
|
||||
DocArchive.archiveDocById(project_id, doc_id, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
},
|
||||
|
||||
unArchiveAllDocs(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
}
|
||||
const { project_id } = req.params
|
||||
logger.log({ project_id }, 'unarchiving all docs')
|
||||
return DocArchive.unArchiveAllDocs(project_id, function (error) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(200)
|
||||
})
|
||||
},
|
||||
|
||||
destroyAllDocs(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function () {}
|
||||
}
|
||||
const { project_id } = req.params
|
||||
logger.log({ project_id }, 'destroying all docs')
|
||||
return DocArchive.destroyAllDocs(project_id, function (error) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(204)
|
||||
})
|
||||
},
|
||||
|
||||
healthCheck(req, res) {
|
||||
return HealthChecker.check(function (err) {
|
||||
if (err != null) {
|
||||
logger.err({ err }, 'error performing health check')
|
||||
return res.sendStatus(500)
|
||||
} else {
|
||||
return res.sendStatus(200)
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function peekDoc(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
logger.log({ projectId, docId }, 'peeking doc')
|
||||
DocManager.peekDoc(projectId, docId, function (error, doc) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
if (doc == null) {
|
||||
res.sendStatus(404)
|
||||
} else {
|
||||
res.setHeader('x-doc-status', doc.inS3 ? 'archived' : 'active')
|
||||
res.json(_buildDocView(doc))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function isDocDeleted(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
DocManager.isDocDeleted(projectId, docId, function (error, deleted) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json({ deleted })
|
||||
})
|
||||
}
|
||||
|
||||
function getRawDoc(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
logger.log({ projectId, docId }, 'getting raw doc')
|
||||
DocManager.getDocLines(projectId, docId, function (error, doc) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
if (doc == null) {
|
||||
res.sendStatus(404)
|
||||
} else {
|
||||
res.setHeader('content-type', 'text/plain')
|
||||
res.send(_buildRawDocView(doc))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getAllDocs(req, res, next) {
|
||||
const { project_id: projectId } = req.params
|
||||
logger.log({ projectId }, 'getting all docs')
|
||||
DocManager.getAllNonDeletedDocs(
|
||||
projectId,
|
||||
{ lines: true, rev: true },
|
||||
function (error, docs) {
|
||||
if (docs == null) {
|
||||
docs = []
|
||||
}
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json(_buildDocsArrayView(projectId, docs))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getAllDeletedDocs(req, res, next) {
|
||||
const { project_id: projectId } = req.params
|
||||
logger.log({ projectId }, 'getting all deleted docs')
|
||||
DocManager.getAllDeletedDocs(
|
||||
projectId,
|
||||
{ name: true, deletedAt: true },
|
||||
function (error, docs) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json(
|
||||
docs.map(doc => ({
|
||||
_id: doc._id.toString(),
|
||||
name: doc.name,
|
||||
deletedAt: doc.deletedAt,
|
||||
}))
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getAllRanges(req, res, next) {
|
||||
const { project_id: projectId } = req.params
|
||||
logger.log({ projectId }, 'getting all ranges')
|
||||
DocManager.getAllNonDeletedDocs(
|
||||
projectId,
|
||||
{ ranges: true },
|
||||
function (error, docs) {
|
||||
if (docs == null) {
|
||||
docs = []
|
||||
}
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json(_buildDocsArrayView(projectId, docs))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function updateDoc(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
const lines = req.body?.lines
|
||||
const version = req.body?.version
|
||||
const ranges = req.body?.ranges
|
||||
|
||||
if (lines == null || !(lines instanceof Array)) {
|
||||
logger.error({ projectId, docId }, 'no doc lines provided')
|
||||
res.sendStatus(400) // Bad Request
|
||||
return
|
||||
}
|
||||
|
||||
if (version == null || typeof version !== 'number') {
|
||||
logger.error({ projectId, docId }, 'no doc version provided')
|
||||
res.sendStatus(400) // Bad Request
|
||||
return
|
||||
}
|
||||
|
||||
if (ranges == null) {
|
||||
logger.error({ projectId, docId }, 'no doc ranges provided')
|
||||
res.sendStatus(400) // Bad Request
|
||||
return
|
||||
}
|
||||
|
||||
const bodyLength = lines.reduce((len, line) => line.length + len, 0)
|
||||
if (bodyLength > Settings.max_doc_length) {
|
||||
logger.error({ projectId, docId, bodyLength }, 'document body too large')
|
||||
res.status(413).send('document body too large')
|
||||
return
|
||||
}
|
||||
|
||||
logger.log({ projectId, docId }, 'got http request to update doc')
|
||||
DocManager.updateDoc(
|
||||
projectId,
|
||||
docId,
|
||||
lines,
|
||||
version,
|
||||
ranges,
|
||||
function (error, modified, rev) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.json({
|
||||
modified,
|
||||
rev,
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function patchDoc(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
logger.log({ projectId, docId }, 'patching doc')
|
||||
|
||||
const allowedFields = ['deleted', 'deletedAt', 'name']
|
||||
const meta = {}
|
||||
Object.entries(req.body).forEach(([field, value]) => {
|
||||
if (allowedFields.includes(field)) {
|
||||
meta[field] = value
|
||||
} else {
|
||||
logger.fatal({ field }, 'joi validation for pathDoc is broken')
|
||||
}
|
||||
})
|
||||
DocManager.patchDoc(projectId, docId, meta, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
}
|
||||
|
||||
function _buildDocView(doc) {
|
||||
const docView = { _id: doc._id?.toString() }
|
||||
for (const attribute of ['lines', 'rev', 'version', 'ranges', 'deleted']) {
|
||||
if (doc[attribute] != null) {
|
||||
docView[attribute] = doc[attribute]
|
||||
}
|
||||
}
|
||||
return docView
|
||||
}
|
||||
|
||||
function _buildRawDocView(doc) {
|
||||
return (doc?.lines ?? []).join('\n')
|
||||
}
|
||||
|
||||
function _buildDocsArrayView(projectId, docs) {
|
||||
const docViews = []
|
||||
for (const doc of docs) {
|
||||
if (doc != null) {
|
||||
// There can end up being null docs for some reason :( (probably a race condition)
|
||||
docViews.push(_buildDocView(doc))
|
||||
} else {
|
||||
logger.error(
|
||||
{ err: new Error('null doc'), projectId },
|
||||
'encountered null doc'
|
||||
)
|
||||
}
|
||||
}
|
||||
return docViews
|
||||
}
|
||||
|
||||
function archiveAllDocs(req, res, next) {
|
||||
const { project_id: projectId } = req.params
|
||||
logger.log({ projectId }, 'archiving all docs')
|
||||
DocArchive.archiveAllDocs(projectId, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
}
|
||||
|
||||
function archiveDoc(req, res, next) {
|
||||
const { doc_id: docId, project_id: projectId } = req.params
|
||||
logger.log({ projectId, docId }, 'archiving a doc')
|
||||
DocArchive.archiveDocById(projectId, docId, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
}
|
||||
|
||||
function unArchiveAllDocs(req, res, next) {
|
||||
const { project_id: projectId } = req.params
|
||||
logger.log({ projectId }, 'unarchiving all docs')
|
||||
DocArchive.unArchiveAllDocs(projectId, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(200)
|
||||
})
|
||||
}
|
||||
|
||||
function destroyAllDocs(req, res, next) {
|
||||
const { project_id: projectId } = req.params
|
||||
logger.log({ projectId }, 'destroying all docs')
|
||||
DocArchive.destroyAllDocs(projectId, function (error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
})
|
||||
}
|
||||
|
||||
function healthCheck(req, res) {
|
||||
HealthChecker.check(function (err) {
|
||||
if (err) {
|
||||
logger.err({ err }, 'error performing health check')
|
||||
res.sendStatus(500)
|
||||
} else {
|
||||
res.sendStatus(200)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getDoc,
|
||||
peekDoc,
|
||||
isDocDeleted,
|
||||
getRawDoc,
|
||||
getAllDocs,
|
||||
getAllDeletedDocs,
|
||||
getAllRanges,
|
||||
updateDoc,
|
||||
patchDoc,
|
||||
archiveAllDocs,
|
||||
archiveDoc,
|
||||
unArchiveAllDocs,
|
||||
destroyAllDocs,
|
||||
healthCheck,
|
||||
}
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
/* eslint-disable
|
||||
camelcase,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
let MongoManager
|
||||
const { db, ObjectId } = require('./mongodb')
|
||||
const logger = require('@overleaf/logger')
|
||||
const metrics = require('@overleaf/metrics')
|
||||
|
@ -17,239 +5,243 @@ const Settings = require('@overleaf/settings')
|
|||
const Errors = require('./Errors')
|
||||
const { promisify } = require('util')
|
||||
|
||||
module.exports = MongoManager = {
|
||||
findDoc(project_id, doc_id, filter, callback) {
|
||||
if (callback == null) {
|
||||
callback = function () {}
|
||||
}
|
||||
db.docs.findOne(
|
||||
function findDoc(projectId, docId, filter, callback) {
|
||||
db.docs.findOne(
|
||||
{
|
||||
_id: ObjectId(docId.toString()),
|
||||
project_id: ObjectId(projectId.toString()),
|
||||
},
|
||||
{
|
||||
projection: filter,
|
||||
},
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
function getProjectsDeletedDocs(projectId, filter, callback) {
|
||||
db.docs
|
||||
.find(
|
||||
{
|
||||
_id: ObjectId(doc_id.toString()),
|
||||
project_id: ObjectId(project_id.toString()),
|
||||
project_id: ObjectId(projectId.toString()),
|
||||
deleted: true,
|
||||
},
|
||||
{
|
||||
projection: filter,
|
||||
},
|
||||
callback
|
||||
)
|
||||
},
|
||||
|
||||
getProjectsDeletedDocs(project_id, filter, callback) {
|
||||
db.docs
|
||||
.find(
|
||||
{
|
||||
project_id: ObjectId(project_id.toString()),
|
||||
deleted: true,
|
||||
},
|
||||
{
|
||||
projection: filter,
|
||||
sort: { deletedAt: -1 },
|
||||
limit: Settings.max_deleted_docs,
|
||||
}
|
||||
)
|
||||
.toArray(callback)
|
||||
},
|
||||
|
||||
getProjectsDocs(project_id, options, filter, callback) {
|
||||
const query = { project_id: ObjectId(project_id.toString()) }
|
||||
if (!options.include_deleted) {
|
||||
query.deleted = { $ne: true }
|
||||
}
|
||||
const queryOptions = {
|
||||
projection: filter,
|
||||
}
|
||||
if (options.limit) {
|
||||
queryOptions.limit = options.limit
|
||||
}
|
||||
db.docs.find(query, queryOptions).toArray(callback)
|
||||
},
|
||||
|
||||
getArchivedProjectDocs(project_id, maxResults, callback) {
|
||||
const query = {
|
||||
project_id: ObjectId(project_id.toString()),
|
||||
inS3: true,
|
||||
}
|
||||
db.docs
|
||||
.find(query, { projection: { _id: 1 }, limit: maxResults })
|
||||
.toArray(callback)
|
||||
},
|
||||
|
||||
getNonArchivedProjectDocs(project_id, maxResults, callback) {
|
||||
const query = {
|
||||
project_id: ObjectId(project_id.toString()),
|
||||
inS3: { $ne: true },
|
||||
}
|
||||
db.docs.find(query, { limit: maxResults }).toArray(callback)
|
||||
},
|
||||
|
||||
getNonDeletedArchivedProjectDocs(project_id, maxResults, callback) {
|
||||
const query = {
|
||||
project_id: ObjectId(project_id.toString()),
|
||||
deleted: { $ne: true },
|
||||
inS3: true,
|
||||
}
|
||||
db.docs
|
||||
.find(query, { projection: { _id: 1 }, limit: maxResults })
|
||||
.toArray(callback)
|
||||
},
|
||||
|
||||
upsertIntoDocCollection(project_id, doc_id, updates, callback) {
|
||||
const update = {
|
||||
$set: updates,
|
||||
$inc: {
|
||||
rev: 1,
|
||||
},
|
||||
$unset: {
|
||||
inS3: true,
|
||||
},
|
||||
}
|
||||
update.$set.project_id = ObjectId(project_id)
|
||||
db.docs.updateOne(
|
||||
{ _id: ObjectId(doc_id) },
|
||||
update,
|
||||
{ upsert: true },
|
||||
callback
|
||||
)
|
||||
},
|
||||
|
||||
patchDoc(project_id, doc_id, meta, callback) {
|
||||
db.docs.updateOne(
|
||||
{
|
||||
_id: ObjectId(doc_id),
|
||||
project_id: ObjectId(project_id),
|
||||
},
|
||||
{ $set: meta },
|
||||
callback
|
||||
)
|
||||
},
|
||||
|
||||
markDocAsArchived(doc_id, rev, callback) {
|
||||
const update = {
|
||||
$set: {},
|
||||
$unset: {},
|
||||
}
|
||||
update.$set.inS3 = true
|
||||
update.$unset.lines = true
|
||||
update.$unset.ranges = true
|
||||
const query = {
|
||||
_id: doc_id,
|
||||
rev,
|
||||
}
|
||||
db.docs.updateOne(query, update, callback)
|
||||
},
|
||||
|
||||
getDocVersion(doc_id, callback) {
|
||||
if (callback == null) {
|
||||
callback = function () {}
|
||||
}
|
||||
db.docOps.findOne(
|
||||
{
|
||||
doc_id: ObjectId(doc_id),
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
function (error, doc) {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
callback(null, (doc && doc.version) || 0)
|
||||
sort: { deletedAt: -1 },
|
||||
limit: Settings.max_deleted_docs,
|
||||
}
|
||||
)
|
||||
},
|
||||
.toArray(callback)
|
||||
}
|
||||
|
||||
setDocVersion(doc_id, version, callback) {
|
||||
if (callback == null) {
|
||||
callback = function () {}
|
||||
}
|
||||
db.docOps.updateOne(
|
||||
{
|
||||
doc_id: ObjectId(doc_id),
|
||||
},
|
||||
{
|
||||
$set: { version },
|
||||
},
|
||||
{
|
||||
upsert: true,
|
||||
},
|
||||
callback
|
||||
)
|
||||
},
|
||||
function getProjectsDocs(projectId, options, filter, callback) {
|
||||
const query = { project_id: ObjectId(projectId.toString()) }
|
||||
if (!options.include_deleted) {
|
||||
query.deleted = { $ne: true }
|
||||
}
|
||||
const queryOptions = {
|
||||
projection: filter,
|
||||
}
|
||||
if (options.limit) {
|
||||
queryOptions.limit = options.limit
|
||||
}
|
||||
db.docs.find(query, queryOptions).toArray(callback)
|
||||
}
|
||||
|
||||
getDocRev(doc_id, callback) {
|
||||
db.docs.findOne(
|
||||
{
|
||||
_id: ObjectId(doc_id.toString()),
|
||||
function getArchivedProjectDocs(projectId, maxResults, callback) {
|
||||
const query = {
|
||||
project_id: ObjectId(projectId.toString()),
|
||||
inS3: true,
|
||||
}
|
||||
db.docs
|
||||
.find(query, { projection: { _id: 1 }, limit: maxResults })
|
||||
.toArray(callback)
|
||||
}
|
||||
|
||||
function getNonArchivedProjectDocs(projectId, maxResults, callback) {
|
||||
const query = {
|
||||
project_id: ObjectId(projectId.toString()),
|
||||
inS3: { $ne: true },
|
||||
}
|
||||
db.docs.find(query, { limit: maxResults }).toArray(callback)
|
||||
}
|
||||
|
||||
function getNonDeletedArchivedProjectDocs(projectId, maxResults, callback) {
|
||||
const query = {
|
||||
project_id: ObjectId(projectId.toString()),
|
||||
deleted: { $ne: true },
|
||||
inS3: true,
|
||||
}
|
||||
db.docs
|
||||
.find(query, { projection: { _id: 1 }, limit: maxResults })
|
||||
.toArray(callback)
|
||||
}
|
||||
|
||||
function upsertIntoDocCollection(projectId, docId, updates, callback) {
|
||||
const update = {
|
||||
$set: updates,
|
||||
$inc: {
|
||||
rev: 1,
|
||||
},
|
||||
$unset: {
|
||||
inS3: true,
|
||||
},
|
||||
}
|
||||
update.$set.project_id = ObjectId(projectId)
|
||||
db.docs.updateOne(
|
||||
{ _id: ObjectId(docId) },
|
||||
update,
|
||||
{ upsert: true },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
function patchDoc(projectId, docId, meta, callback) {
|
||||
db.docs.updateOne(
|
||||
{
|
||||
_id: ObjectId(docId),
|
||||
project_id: ObjectId(projectId),
|
||||
},
|
||||
{ $set: meta },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
function markDocAsArchived(docId, rev, callback) {
|
||||
const update = {
|
||||
$set: {},
|
||||
$unset: {},
|
||||
}
|
||||
update.$set.inS3 = true
|
||||
update.$unset.lines = true
|
||||
update.$unset.ranges = true
|
||||
const query = {
|
||||
_id: docId,
|
||||
rev,
|
||||
}
|
||||
db.docs.updateOne(query, update, callback)
|
||||
}
|
||||
|
||||
function getDocVersion(docId, callback) {
|
||||
db.docOps.findOne(
|
||||
{
|
||||
doc_id: ObjectId(docId),
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
projection: { rev: 1 },
|
||||
},
|
||||
function (err, doc) {
|
||||
if (err != null) {
|
||||
return callback(err)
|
||||
}
|
||||
callback(null, doc && doc.rev)
|
||||
},
|
||||
function (error, doc) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
)
|
||||
},
|
||||
callback(null, (doc && doc.version) || 0)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Helper method to support optimistic locking. Call the provided method for
|
||||
// an existing doc and return the result if the rev in mongo is unchanged when
|
||||
// checked afterwards. If the rev has changed, return a DocModifiedError.
|
||||
withRevCheck(doc, method, callback) {
|
||||
method(doc._id, function (err, result) {
|
||||
function setDocVersion(docId, version, callback) {
|
||||
db.docOps.updateOne(
|
||||
{
|
||||
doc_id: ObjectId(docId),
|
||||
},
|
||||
{
|
||||
$set: { version },
|
||||
},
|
||||
{
|
||||
upsert: true,
|
||||
},
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
function getDocRev(docId, callback) {
|
||||
db.docs.findOne(
|
||||
{
|
||||
_id: ObjectId(docId.toString()),
|
||||
},
|
||||
{
|
||||
projection: { rev: 1 },
|
||||
},
|
||||
function (err, doc) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
callback(null, doc && doc.rev)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Helper method to support optimistic locking. Call the provided method for
|
||||
// an existing doc and return the result if the rev in mongo is unchanged when
|
||||
// checked afterwards. If the rev has changed, return a DocModifiedError.
|
||||
function withRevCheck(doc, method, callback) {
|
||||
method(doc._id, function (err, result) {
|
||||
if (err) return callback(err)
|
||||
getDocRev(doc._id, function (err, currentRev) {
|
||||
if (err) return callback(err)
|
||||
MongoManager.getDocRev(doc._id, function (err, currentRev) {
|
||||
if (err) return callback(err)
|
||||
if (isNaN(currentRev) || isNaN(doc.rev)) {
|
||||
return callback(
|
||||
new Errors.DocRevValueError('doc rev is NaN', {
|
||||
doc_id: doc._id,
|
||||
rev: doc.rev,
|
||||
currentRev,
|
||||
})
|
||||
)
|
||||
}
|
||||
if (doc.rev !== currentRev) {
|
||||
return callback(
|
||||
new Errors.DocModifiedError('doc rev has changed', {
|
||||
doc_id: doc._id,
|
||||
rev: doc.rev,
|
||||
currentRev,
|
||||
})
|
||||
)
|
||||
}
|
||||
return callback(null, result)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
destroyDoc(doc_id, callback) {
|
||||
db.docs.deleteOne(
|
||||
{
|
||||
_id: ObjectId(doc_id),
|
||||
},
|
||||
function (err) {
|
||||
if (err != null) {
|
||||
return callback(err)
|
||||
}
|
||||
db.docOps.deleteOne(
|
||||
{
|
||||
doc_id: ObjectId(doc_id),
|
||||
},
|
||||
callback
|
||||
if (isNaN(currentRev) || isNaN(doc.rev)) {
|
||||
return callback(
|
||||
new Errors.DocRevValueError('doc rev is NaN', {
|
||||
doc_id: doc._id,
|
||||
rev: doc.rev,
|
||||
currentRev,
|
||||
})
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
if (doc.rev !== currentRev) {
|
||||
return callback(
|
||||
new Errors.DocModifiedError('doc rev has changed', {
|
||||
doc_id: doc._id,
|
||||
rev: doc.rev,
|
||||
currentRev,
|
||||
})
|
||||
)
|
||||
}
|
||||
callback(null, result)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const methods = Object.getOwnPropertyNames(MongoManager)
|
||||
function destroyDoc(docId, callback) {
|
||||
db.docs.deleteOne(
|
||||
{
|
||||
_id: ObjectId(docId),
|
||||
},
|
||||
function (err) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
db.docOps.deleteOne(
|
||||
{
|
||||
doc_id: ObjectId(docId),
|
||||
},
|
||||
callback
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findDoc,
|
||||
getProjectsDeletedDocs,
|
||||
getProjectsDocs,
|
||||
getArchivedProjectDocs,
|
||||
getNonArchivedProjectDocs,
|
||||
getNonDeletedArchivedProjectDocs,
|
||||
upsertIntoDocCollection,
|
||||
patchDoc,
|
||||
markDocAsArchived,
|
||||
getDocVersion,
|
||||
setDocVersion,
|
||||
withRevCheck,
|
||||
destroyDoc,
|
||||
}
|
||||
|
||||
const methods = Object.getOwnPropertyNames(module.exports)
|
||||
module.exports.promises = {}
|
||||
for (const method of methods) {
|
||||
metrics.timeAsyncMethod(MongoManager, method, 'mongo.MongoManager', logger)
|
||||
metrics.timeAsyncMethod(module.exports, method, 'mongo.MongoManager', logger)
|
||||
module.exports.promises[method] = promisify(module.exports[method])
|
||||
}
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
/* eslint-disable
|
||||
no-return-assign,
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const sinon = require('sinon')
|
||||
const { assert, expect } = require('chai')
|
||||
|
@ -40,46 +29,46 @@ describe('HttpController', function () {
|
|||
this.res.status = sinon.stub().returns(this.res)
|
||||
this.req = { query: {} }
|
||||
this.next = sinon.stub()
|
||||
this.project_id = 'mock-project-id'
|
||||
this.doc_id = 'mock-doc-id'
|
||||
this.projectId = 'mock-project-id'
|
||||
this.docId = 'mock-doc-id'
|
||||
this.doc = {
|
||||
_id: this.doc_id,
|
||||
_id: this.docId,
|
||||
lines: ['mock', 'lines', ' here', '', '', ' spaces '],
|
||||
version: 42,
|
||||
rev: 5,
|
||||
}
|
||||
return (this.deletedDoc = {
|
||||
this.deletedDoc = {
|
||||
deleted: true,
|
||||
_id: this.doc_id,
|
||||
_id: this.docId,
|
||||
lines: ['mock', 'lines', ' here', '', '', ' spaces '],
|
||||
version: 42,
|
||||
rev: 5,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('getDoc', function () {
|
||||
describe('without deleted docs', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = {
|
||||
project_id: this.project_id,
|
||||
doc_id: this.doc_id,
|
||||
project_id: this.projectId,
|
||||
doc_id: this.docId,
|
||||
}
|
||||
this.DocManager.getFullDoc = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, this.doc)
|
||||
return this.HttpController.getDoc(this.req, this.res, this.next)
|
||||
this.HttpController.getDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should get the document with the version (including deleted)', function () {
|
||||
return this.DocManager.getFullDoc
|
||||
.calledWith(this.project_id, this.doc_id)
|
||||
this.DocManager.getFullDoc
|
||||
.calledWith(this.projectId, this.docId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should return the doc as JSON', function () {
|
||||
return this.res.json
|
||||
it('should return the doc as JSON', function () {
|
||||
this.res.json
|
||||
.calledWith({
|
||||
_id: this.doc_id,
|
||||
_id: this.docId,
|
||||
lines: this.doc.lines,
|
||||
rev: this.doc.rev,
|
||||
version: this.doc.version,
|
||||
|
@ -88,35 +77,35 @@ describe('HttpController', function () {
|
|||
})
|
||||
})
|
||||
|
||||
return describe('which is deleted', function () {
|
||||
describe('which is deleted', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = {
|
||||
project_id: this.project_id,
|
||||
doc_id: this.doc_id,
|
||||
project_id: this.projectId,
|
||||
doc_id: this.docId,
|
||||
}
|
||||
return (this.DocManager.getFullDoc = sinon
|
||||
this.DocManager.getFullDoc = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, this.deletedDoc))
|
||||
.callsArgWith(2, null, this.deletedDoc)
|
||||
})
|
||||
|
||||
it('should get the doc from the doc manager', function () {
|
||||
this.HttpController.getDoc(this.req, this.res, this.next)
|
||||
return this.DocManager.getFullDoc
|
||||
.calledWith(this.project_id, this.doc_id)
|
||||
this.DocManager.getFullDoc
|
||||
.calledWith(this.projectId, this.docId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should return 404 if the query string delete is not set ', function () {
|
||||
this.HttpController.getDoc(this.req, this.res, this.next)
|
||||
return this.res.sendStatus.calledWith(404).should.equal(true)
|
||||
this.res.sendStatus.calledWith(404).should.equal(true)
|
||||
})
|
||||
|
||||
return it('should return the doc as JSON if include_deleted is set to true', function () {
|
||||
it('should return the doc as JSON if include_deleted is set to true', function () {
|
||||
this.req.query.include_deleted = 'true'
|
||||
this.HttpController.getDoc(this.req, this.res, this.next)
|
||||
return this.res.json
|
||||
this.res.json
|
||||
.calledWith({
|
||||
_id: this.doc_id,
|
||||
_id: this.docId,
|
||||
lines: this.doc.lines,
|
||||
rev: this.doc.rev,
|
||||
deleted: true,
|
||||
|
@ -130,27 +119,27 @@ describe('HttpController', function () {
|
|||
describe('getRawDoc', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = {
|
||||
project_id: this.project_id,
|
||||
doc_id: this.doc_id,
|
||||
project_id: this.projectId,
|
||||
doc_id: this.docId,
|
||||
}
|
||||
this.DocManager.getDocLines = sinon.stub().callsArgWith(2, null, this.doc)
|
||||
return this.HttpController.getRawDoc(this.req, this.res, this.next)
|
||||
this.HttpController.getRawDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should get the document without the version', function () {
|
||||
return this.DocManager.getDocLines
|
||||
.calledWith(this.project_id, this.doc_id)
|
||||
this.DocManager.getDocLines
|
||||
.calledWith(this.projectId, this.docId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should set the content type header', function () {
|
||||
return this.res.setHeader
|
||||
this.res.setHeader
|
||||
.calledWith('content-type', 'text/plain')
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should send the raw version of the doc', function () {
|
||||
return assert.deepEqual(
|
||||
it('should send the raw version of the doc', function () {
|
||||
assert.deepEqual(
|
||||
this.res.send.args[0][0],
|
||||
`${this.doc.lines[0]}\n${this.doc.lines[1]}\n${this.doc.lines[2]}\n${this.doc.lines[3]}\n${this.doc.lines[4]}\n${this.doc.lines[5]}`
|
||||
)
|
||||
|
@ -160,7 +149,7 @@ describe('HttpController', function () {
|
|||
describe('getAllDocs', function () {
|
||||
describe('normally', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = { project_id: this.project_id }
|
||||
this.req.params = { project_id: this.projectId }
|
||||
this.docs = [
|
||||
{
|
||||
_id: ObjectId(),
|
||||
|
@ -176,17 +165,17 @@ describe('HttpController', function () {
|
|||
this.DocManager.getAllNonDeletedDocs = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, this.docs)
|
||||
return this.HttpController.getAllDocs(this.req, this.res, this.next)
|
||||
this.HttpController.getAllDocs(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should get all the (non-deleted) docs', function () {
|
||||
return this.DocManager.getAllNonDeletedDocs
|
||||
.calledWith(this.project_id, { lines: true, rev: true })
|
||||
this.DocManager.getAllNonDeletedDocs
|
||||
.calledWith(this.projectId, { lines: true, rev: true })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should return the doc as JSON', function () {
|
||||
return this.res.json
|
||||
it('should return the doc as JSON', function () {
|
||||
this.res.json
|
||||
.calledWith([
|
||||
{
|
||||
_id: this.docs[0]._id.toString(),
|
||||
|
@ -203,9 +192,9 @@ describe('HttpController', function () {
|
|||
})
|
||||
})
|
||||
|
||||
return describe('with a null doc', function () {
|
||||
describe('with a null doc', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = { project_id: this.project_id }
|
||||
this.req.params = { project_id: this.projectId }
|
||||
this.docs = [
|
||||
{
|
||||
_id: ObjectId(),
|
||||
|
@ -222,11 +211,11 @@ describe('HttpController', function () {
|
|||
this.DocManager.getAllNonDeletedDocs = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, this.docs)
|
||||
return this.HttpController.getAllDocs(this.req, this.res, this.next)
|
||||
this.HttpController.getAllDocs(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should return the non null docs as JSON', function () {
|
||||
return this.res.json
|
||||
this.res.json
|
||||
.calledWith([
|
||||
{
|
||||
_id: this.docs[0]._id.toString(),
|
||||
|
@ -242,12 +231,12 @@ describe('HttpController', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should log out an error', function () {
|
||||
return this.logger.error
|
||||
it('should log out an error', function () {
|
||||
this.logger.error
|
||||
.calledWith(
|
||||
{
|
||||
err: sinon.match.has('message', 'null doc'),
|
||||
project_id: this.project_id,
|
||||
projectId: this.projectId,
|
||||
},
|
||||
'encountered null doc'
|
||||
)
|
||||
|
@ -257,9 +246,9 @@ describe('HttpController', function () {
|
|||
})
|
||||
|
||||
describe('getAllRanges', function () {
|
||||
return describe('normally', function () {
|
||||
describe('normally', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = { project_id: this.project_id }
|
||||
this.req.params = { project_id: this.projectId }
|
||||
this.docs = [
|
||||
{
|
||||
_id: ObjectId(),
|
||||
|
@ -273,17 +262,17 @@ describe('HttpController', function () {
|
|||
this.DocManager.getAllNonDeletedDocs = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, this.docs)
|
||||
return this.HttpController.getAllRanges(this.req, this.res, this.next)
|
||||
this.HttpController.getAllRanges(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should get all the (non-deleted) doc ranges', function () {
|
||||
return this.DocManager.getAllNonDeletedDocs
|
||||
.calledWith(this.project_id, { ranges: true })
|
||||
this.DocManager.getAllNonDeletedDocs
|
||||
.calledWith(this.projectId, { ranges: true })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should return the doc as JSON', function () {
|
||||
return this.res.json
|
||||
it('should return the doc as JSON', function () {
|
||||
this.res.json
|
||||
.calledWith([
|
||||
{
|
||||
_id: this.docs[0]._id.toString(),
|
||||
|
@ -301,10 +290,10 @@ describe('HttpController', function () {
|
|||
|
||||
describe('updateDoc', function () {
|
||||
beforeEach(function () {
|
||||
return (this.req.params = {
|
||||
project_id: this.project_id,
|
||||
doc_id: this.doc_id,
|
||||
})
|
||||
this.req.params = {
|
||||
project_id: this.projectId,
|
||||
doc_id: this.docId,
|
||||
}
|
||||
})
|
||||
|
||||
describe('when the doc lines exist and were updated', function () {
|
||||
|
@ -317,14 +306,14 @@ describe('HttpController', function () {
|
|||
this.DocManager.updateDoc = sinon
|
||||
.stub()
|
||||
.yields(null, true, (this.rev = 5))
|
||||
return this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should update the document', function () {
|
||||
return this.DocManager.updateDoc
|
||||
this.DocManager.updateDoc
|
||||
.calledWith(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.projectId,
|
||||
this.docId,
|
||||
this.lines,
|
||||
this.version,
|
||||
this.ranges
|
||||
|
@ -332,8 +321,8 @@ describe('HttpController', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should return a modified status', function () {
|
||||
return this.res.json
|
||||
it('should return a modified status', function () {
|
||||
this.res.json
|
||||
.calledWith({ modified: true, rev: this.rev })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
@ -349,11 +338,11 @@ describe('HttpController', function () {
|
|||
this.DocManager.updateDoc = sinon
|
||||
.stub()
|
||||
.yields(null, false, (this.rev = 5))
|
||||
return this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
return it('should return a modified status', function () {
|
||||
return this.res.json
|
||||
it('should return a modified status', function () {
|
||||
this.res.json
|
||||
.calledWith({ modified: false, rev: this.rev })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
@ -363,15 +352,15 @@ describe('HttpController', function () {
|
|||
beforeEach(function () {
|
||||
this.req.body = { version: 42, ranges: {} }
|
||||
this.DocManager.updateDoc = sinon.stub().yields(null, false)
|
||||
return this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should not update the document', function () {
|
||||
return this.DocManager.updateDoc.called.should.equal(false)
|
||||
this.DocManager.updateDoc.called.should.equal(false)
|
||||
})
|
||||
|
||||
return it('should return a 400 (bad request) response', function () {
|
||||
return this.res.sendStatus.calledWith(400).should.equal(true)
|
||||
it('should return a 400 (bad request) response', function () {
|
||||
this.res.sendStatus.calledWith(400).should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -379,15 +368,15 @@ describe('HttpController', function () {
|
|||
beforeEach(function () {
|
||||
this.req.body = { version: 42, lines: ['hello world'] }
|
||||
this.DocManager.updateDoc = sinon.stub().yields(null, false)
|
||||
return this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should not update the document', function () {
|
||||
return this.DocManager.updateDoc.called.should.equal(false)
|
||||
this.DocManager.updateDoc.called.should.equal(false)
|
||||
})
|
||||
|
||||
return it('should return a 400 (bad request) response', function () {
|
||||
return this.res.sendStatus.calledWith(400).should.equal(true)
|
||||
it('should return a 400 (bad request) response', function () {
|
||||
this.res.sendStatus.calledWith(400).should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -395,34 +384,34 @@ describe('HttpController', function () {
|
|||
beforeEach(function () {
|
||||
this.req.body = { lines: ['foo'], version: 42 }
|
||||
this.DocManager.updateDoc = sinon.stub().yields(null, false)
|
||||
return this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should not update the document', function () {
|
||||
return this.DocManager.updateDoc.called.should.equal(false)
|
||||
this.DocManager.updateDoc.called.should.equal(false)
|
||||
})
|
||||
|
||||
return it('should return a 400 (bad request) response', function () {
|
||||
return this.res.sendStatus.calledWith(400).should.equal(true)
|
||||
it('should return a 400 (bad request) response', function () {
|
||||
this.res.sendStatus.calledWith(400).should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
return describe('when the doc body is too large', function () {
|
||||
describe('when the doc body is too large', function () {
|
||||
beforeEach(function () {
|
||||
this.req.body = {
|
||||
lines: (this.lines = Array(2049).fill('a'.repeat(1024))),
|
||||
version: (this.version = 42),
|
||||
ranges: (this.ranges = { changes: 'mock' }),
|
||||
}
|
||||
return this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
this.HttpController.updateDoc(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should return a 413 (too large) response', function () {
|
||||
return sinon.assert.calledWith(this.res.status, 413)
|
||||
sinon.assert.calledWith(this.res.status, 413)
|
||||
})
|
||||
|
||||
return it('should report that the document body is too large', function () {
|
||||
return sinon.assert.calledWith(this.res.send, 'document body too large')
|
||||
it('should report that the document body is too large', function () {
|
||||
sinon.assert.calledWith(this.res.send, 'document body too large')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -430,8 +419,8 @@ describe('HttpController', function () {
|
|||
describe('patchDoc', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = {
|
||||
project_id: this.project_id,
|
||||
doc_id: this.doc_id,
|
||||
project_id: this.projectId,
|
||||
doc_id: this.docId,
|
||||
}
|
||||
this.req.body = { name: 'foo.tex' }
|
||||
this.DocManager.patchDoc = sinon.stub().yields(null)
|
||||
|
@ -440,8 +429,8 @@ describe('HttpController', function () {
|
|||
|
||||
it('should delete the document', function () {
|
||||
expect(this.DocManager.patchDoc).to.have.been.calledWith(
|
||||
this.project_id,
|
||||
this.doc_id
|
||||
this.projectId,
|
||||
this.docId
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -466,8 +455,8 @@ describe('HttpController', function () {
|
|||
|
||||
it('should not pass the invalid field along', function () {
|
||||
expect(this.DocManager.patchDoc).to.have.been.calledWith(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.projectId,
|
||||
this.docId,
|
||||
{}
|
||||
)
|
||||
})
|
||||
|
@ -476,38 +465,38 @@ describe('HttpController', function () {
|
|||
|
||||
describe('archiveAllDocs', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = { project_id: this.project_id }
|
||||
this.req.params = { project_id: this.projectId }
|
||||
this.DocArchiveManager.archiveAllDocs = sinon.stub().callsArg(1)
|
||||
return this.HttpController.archiveAllDocs(this.req, this.res, this.next)
|
||||
this.HttpController.archiveAllDocs(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should archive the project', function () {
|
||||
return this.DocArchiveManager.archiveAllDocs
|
||||
.calledWith(this.project_id)
|
||||
this.DocArchiveManager.archiveAllDocs
|
||||
.calledWith(this.projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should return a 204 (No Content)', function () {
|
||||
return this.res.sendStatus.calledWith(204).should.equal(true)
|
||||
it('should return a 204 (No Content)', function () {
|
||||
this.res.sendStatus.calledWith(204).should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
return describe('destroyAllDocs', function () {
|
||||
describe('destroyAllDocs', function () {
|
||||
beforeEach(function () {
|
||||
this.req.params = { project_id: this.project_id }
|
||||
this.req.params = { project_id: this.projectId }
|
||||
this.DocArchiveManager.destroyAllDocs = sinon.stub().callsArg(1)
|
||||
return this.HttpController.destroyAllDocs(this.req, this.res, this.next)
|
||||
this.HttpController.destroyAllDocs(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should destroy the docs', function () {
|
||||
return sinon.assert.calledWith(
|
||||
sinon.assert.calledWith(
|
||||
this.DocArchiveManager.destroyAllDocs,
|
||||
this.project_id
|
||||
this.projectId
|
||||
)
|
||||
})
|
||||
|
||||
return it('should return 204', function () {
|
||||
return sinon.assert.calledWith(this.res.sendStatus, 204)
|
||||
it('should return 204', function () {
|
||||
sinon.assert.calledWith(this.res.sendStatus, 204)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,13 +1,3 @@
|
|||
/* eslint-disable
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = require('path').join(
|
||||
|
@ -34,7 +24,7 @@ describe('MongoManager', function () {
|
|||
this.project_id = ObjectId().toString()
|
||||
this.doc_id = ObjectId().toString()
|
||||
this.callback = sinon.stub()
|
||||
return (this.stubbedErr = new Error('hello world'))
|
||||
this.stubbedErr = new Error('hello world')
|
||||
})
|
||||
|
||||
describe('findDoc', function () {
|
||||
|
@ -42,7 +32,7 @@ describe('MongoManager', function () {
|
|||
this.doc = { name: 'mock-doc' }
|
||||
this.db.docs.findOne = sinon.stub().callsArgWith(2, null, this.doc)
|
||||
this.filter = { lines: true }
|
||||
return this.MongoManager.findDoc(
|
||||
this.MongoManager.findDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.filter,
|
||||
|
@ -64,8 +54,8 @@ describe('MongoManager', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should call the callback with the doc', function () {
|
||||
return this.callback.calledWith(null, this.doc).should.equal(true)
|
||||
it('should call the callback with the doc', function () {
|
||||
this.callback.calledWith(null, this.doc).should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -112,7 +102,7 @@ describe('MongoManager', function () {
|
|||
|
||||
describe('with included_deleted = false', function () {
|
||||
beforeEach(function () {
|
||||
return this.MongoManager.getProjectsDocs(
|
||||
this.MongoManager.getProjectsDocs(
|
||||
this.project_id,
|
||||
{ include_deleted: false },
|
||||
this.filter,
|
||||
|
@ -121,7 +111,7 @@ describe('MongoManager', function () {
|
|||
})
|
||||
|
||||
it('should find the non-deleted docs via the project_id', function () {
|
||||
return this.db.docs.find
|
||||
this.db.docs.find
|
||||
.calledWith(
|
||||
{
|
||||
project_id: ObjectId(this.project_id),
|
||||
|
@ -134,16 +124,16 @@ describe('MongoManager', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should call the callback with the docs', function () {
|
||||
return this.callback
|
||||
it('should call the callback with the docs', function () {
|
||||
this.callback
|
||||
.calledWith(null, [this.doc, this.doc3, this.doc4])
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
return describe('with included_deleted = true', function () {
|
||||
describe('with included_deleted = true', function () {
|
||||
beforeEach(function () {
|
||||
return this.MongoManager.getProjectsDocs(
|
||||
this.MongoManager.getProjectsDocs(
|
||||
this.project_id,
|
||||
{ include_deleted: true },
|
||||
this.filter,
|
||||
|
@ -152,7 +142,7 @@ describe('MongoManager', function () {
|
|||
})
|
||||
|
||||
it('should find all via the project_id', function () {
|
||||
return this.db.docs.find
|
||||
this.db.docs.find
|
||||
.calledWith(
|
||||
{
|
||||
project_id: ObjectId(this.project_id),
|
||||
|
@ -164,8 +154,8 @@ describe('MongoManager', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should call the callback with the docs', function () {
|
||||
return this.callback
|
||||
it('should call the callback with the docs', function () {
|
||||
this.callback
|
||||
.calledWith(null, [this.doc, this.doc3, this.doc4])
|
||||
.should.equal(true)
|
||||
})
|
||||
|
@ -218,11 +208,11 @@ describe('MongoManager', function () {
|
|||
describe('upsertIntoDocCollection', function () {
|
||||
beforeEach(function () {
|
||||
this.db.docs.updateOne = sinon.stub().callsArgWith(3, this.stubbedErr)
|
||||
return (this.oldRev = 77)
|
||||
this.oldRev = 77
|
||||
})
|
||||
|
||||
it('should upsert the document', function (done) {
|
||||
return this.MongoManager.upsertIntoDocCollection(
|
||||
this.MongoManager.upsertIntoDocCollection(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
{ lines: this.lines },
|
||||
|
@ -233,19 +223,19 @@ describe('MongoManager', function () {
|
|||
assert.equal(args[1].$set.lines, this.lines)
|
||||
assert.equal(args[1].$inc.rev, 1)
|
||||
assert.deepEqual(args[1].$set.project_id, ObjectId(this.project_id))
|
||||
return done()
|
||||
done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
return it('should return the error', function (done) {
|
||||
return this.MongoManager.upsertIntoDocCollection(
|
||||
it('should return the error', function (done) {
|
||||
this.MongoManager.upsertIntoDocCollection(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
{ lines: this.lines },
|
||||
err => {
|
||||
err.should.equal(this.stubbedErr)
|
||||
return done()
|
||||
done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -255,17 +245,17 @@ describe('MongoManager', function () {
|
|||
beforeEach(function (done) {
|
||||
this.db.docs.deleteOne = sinon.stub().yields()
|
||||
this.db.docOps.deleteOne = sinon.stub().yields()
|
||||
return this.MongoManager.destroyDoc('123456789012', done)
|
||||
this.MongoManager.destroyDoc('123456789012', done)
|
||||
})
|
||||
|
||||
it('should destroy the doc', function () {
|
||||
return sinon.assert.calledWith(this.db.docs.deleteOne, {
|
||||
sinon.assert.calledWith(this.db.docs.deleteOne, {
|
||||
_id: ObjectId('123456789012'),
|
||||
})
|
||||
})
|
||||
|
||||
return it('should destroy the docOps', function () {
|
||||
return sinon.assert.calledWith(this.db.docOps.deleteOne, {
|
||||
it('should destroy the docOps', function () {
|
||||
sinon.assert.calledWith(this.db.docOps.deleteOne, {
|
||||
doc_id: ObjectId('123456789012'),
|
||||
})
|
||||
})
|
||||
|
@ -276,11 +266,11 @@ describe('MongoManager', function () {
|
|||
beforeEach(function () {
|
||||
this.doc = { version: (this.version = 42) }
|
||||
this.db.docOps.findOne = sinon.stub().callsArgWith(2, null, this.doc)
|
||||
return this.MongoManager.getDocVersion(this.doc_id, this.callback)
|
||||
this.MongoManager.getDocVersion(this.doc_id, this.callback)
|
||||
})
|
||||
|
||||
it('should look for the doc in the database', function () {
|
||||
return this.db.docOps.findOne
|
||||
this.db.docOps.findOne
|
||||
.calledWith(
|
||||
{ doc_id: ObjectId(this.doc_id) },
|
||||
{
|
||||
|
@ -290,19 +280,19 @@ describe('MongoManager', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should call the callback with the version', function () {
|
||||
return this.callback.calledWith(null, this.version).should.equal(true)
|
||||
it('should call the callback with the version', function () {
|
||||
this.callback.calledWith(null, this.version).should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
return describe("when the doc doesn't exist", function () {
|
||||
describe("when the doc doesn't exist", function () {
|
||||
beforeEach(function () {
|
||||
this.db.docOps.findOne = sinon.stub().callsArgWith(2, null, null)
|
||||
return this.MongoManager.getDocVersion(this.doc_id, this.callback)
|
||||
this.MongoManager.getDocVersion(this.doc_id, this.callback)
|
||||
})
|
||||
|
||||
return it('should call the callback with 0', function () {
|
||||
return this.callback.calledWith(null, 0).should.equal(true)
|
||||
it('should call the callback with 0', function () {
|
||||
this.callback.calledWith(null, 0).should.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -311,15 +301,11 @@ describe('MongoManager', function () {
|
|||
beforeEach(function () {
|
||||
this.version = 42
|
||||
this.db.docOps.updateOne = sinon.stub().callsArg(3)
|
||||
return this.MongoManager.setDocVersion(
|
||||
this.doc_id,
|
||||
this.version,
|
||||
this.callback
|
||||
)
|
||||
this.MongoManager.setDocVersion(this.doc_id, this.version, this.callback)
|
||||
})
|
||||
|
||||
it('should update the doc version', function () {
|
||||
return this.db.docOps.updateOne
|
||||
this.db.docOps.updateOne
|
||||
.calledWith(
|
||||
{
|
||||
doc_id: ObjectId(this.doc_id),
|
||||
|
@ -336,8 +322,8 @@ describe('MongoManager', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
return it('should call the callback', function () {
|
||||
return this.callback.called.should.equal(true)
|
||||
it('should call the callback', function () {
|
||||
this.callback.called.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue