Merge pull request #3014 from overleaf/ns-delete-project-history-cleanup

Decaf cleanup HistoryController

GitOrigin-RevId: e5df4cde30d8b9e65062e1484699326e96c4eb92
This commit is contained in:
Jakob Ackermann 2020-11-30 13:02:12 +00:00 committed by Copybot
parent 1fe7eaab90
commit 3ce57ed442
2 changed files with 102 additions and 150 deletions

View file

@ -1,22 +1,5 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
no-undef,
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
* DS103: Rewrite code to no longer use __guard__
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let HistoryController let HistoryController
const OError = require('@overleaf/o-error') const OError = require('@overleaf/o-error')
const _ = require('lodash')
const async = require('async') const async = require('async')
const logger = require('logger-sharelatex') const logger = require('logger-sharelatex')
const request = require('request') const request = require('request')
@ -32,45 +15,32 @@ const { pipeline } = require('stream')
module.exports = HistoryController = { module.exports = HistoryController = {
selectHistoryApi(req, res, next) { selectHistoryApi(req, res, next) {
if (next == null) { const { Project_id: projectId } = req.params
next = function(error) {}
}
const project_id = req.params != null ? req.params.Project_id : undefined
// find out which type of history service this project uses // find out which type of history service this project uses
return ProjectDetailsHandler.getDetails(project_id, function(err, project) { ProjectDetailsHandler.getDetails(projectId, function(err, project) {
if (err != null) { if (err) {
return next(err) return next(err)
} }
const history = const history = project.overleaf && project.overleaf.history
project.overleaf != null ? project.overleaf.history : undefined if (history && history.id && history.display) {
if (
(history != null ? history.id : undefined) != null &&
(history != null ? history.display : undefined)
) {
req.useProjectHistory = true req.useProjectHistory = true
} else { } else {
req.useProjectHistory = false req.useProjectHistory = false
} }
return next() next()
}) })
}, },
ensureProjectHistoryEnabled(req, res, next) { ensureProjectHistoryEnabled(req, res, next) {
if (next == null) { if (req.useProjectHistory) {
next = function(error) {} next()
}
if (req.useProjectHistory != null) {
return next()
} else { } else {
return res.sendStatus(404) res.sendStatus(404)
} }
}, },
proxyToHistoryApi(req, res, next) { proxyToHistoryApi(req, res, next) {
if (next == null) { const userId = AuthenticationController.getLoggedInUserId(req)
next = function(error) {}
}
const user_id = AuthenticationController.getLoggedInUserId(req)
const url = const url =
HistoryController.buildHistoryServiceUrl(req.useProjectHistory) + req.url HistoryController.buildHistoryServiceUrl(req.useProjectHistory) + req.url
@ -78,41 +48,38 @@ module.exports = HistoryController = {
url, url,
method: req.method, method: req.method,
headers: { headers: {
'X-User-Id': user_id 'X-User-Id': userId
} }
}) })
getReq.pipe(res) getReq.pipe(res)
return getReq.on('error', function(error) { getReq.on('error', function(err) {
logger.warn({ url, err: error }, 'history API error') logger.warn({ url, err }, 'history API error')
return next(error) next(err)
}) })
}, },
proxyToHistoryApiAndInjectUserDetails(req, res, next) { proxyToHistoryApiAndInjectUserDetails(req, res, next) {
if (next == null) { const userId = AuthenticationController.getLoggedInUserId(req)
next = function(error) {}
}
const user_id = AuthenticationController.getLoggedInUserId(req)
const url = const url =
HistoryController.buildHistoryServiceUrl(req.useProjectHistory) + req.url HistoryController.buildHistoryServiceUrl(req.useProjectHistory) + req.url
return HistoryController._makeRequest( HistoryController._makeRequest(
{ {
url, url,
method: req.method, method: req.method,
json: true, json: true,
headers: { headers: {
'X-User-Id': user_id 'X-User-Id': userId
} }
}, },
function(error, body) { function(err, body) {
if (error != null) { if (err) {
return next(error) return next(err)
} }
return HistoryManager.injectUserDetails(body, function(error, data) { HistoryManager.injectUserDetails(body, function(err, data) {
if (error != null) { if (err) {
return next(error) return next(err)
} }
return res.json(data) res.json(data)
}) })
} }
) )
@ -129,37 +96,32 @@ module.exports = HistoryController = {
}, },
resyncProjectHistory(req, res, next) { resyncProjectHistory(req, res, next) {
if (next == null) { const projectId = req.params.Project_id
next = function(error) {} ProjectEntityUpdateHandler.resyncProjectHistory(projectId, function(err) {
} if (err instanceof Errors.ProjectHistoryDisabledError) {
const project_id = req.params.Project_id
return ProjectEntityUpdateHandler.resyncProjectHistory(project_id, function(
error
) {
if (error instanceof Errors.ProjectHistoryDisabledError) {
return res.sendStatus(404) return res.sendStatus(404)
} }
if (error != null) { if (err) {
return next(error) return next(err)
} }
return res.sendStatus(204) res.sendStatus(204)
}) })
}, },
restoreFileFromV2(req, res, next) { restoreFileFromV2(req, res, next) {
const { project_id } = req.params const { project_id: projectId } = req.params
const { version, pathname } = req.body const { version, pathname } = req.body
const user_id = AuthenticationController.getLoggedInUserId(req) const userId = AuthenticationController.getLoggedInUserId(req)
return RestoreManager.restoreFileFromV2( RestoreManager.restoreFileFromV2(
user_id, userId,
project_id, projectId,
version, version,
pathname, pathname,
function(error, entity) { function(err, entity) {
if (error != null) { if (err) {
return next(error) return next(err)
} }
return res.json({ res.json({
type: entity.type, type: entity.type,
id: entity._id id: entity._id
}) })
@ -168,19 +130,19 @@ module.exports = HistoryController = {
}, },
restoreDocFromDeletedDoc(req, res, next) { restoreDocFromDeletedDoc(req, res, next) {
const { project_id, doc_id } = req.params const { project_id: projectId, doc_id: docId } = req.params
const { name } = req.body const { name } = req.body
const user_id = AuthenticationController.getLoggedInUserId(req) const userId = AuthenticationController.getLoggedInUserId(req)
if (name == null) { if (name == null) {
return res.sendStatus(400) // Malformed request return res.sendStatus(400) // Malformed request
} }
return RestoreManager.restoreDocFromDeletedDoc( RestoreManager.restoreDocFromDeletedDoc(
user_id, userId,
project_id, projectId,
doc_id, docId,
name, name,
(error, doc) => { (err, doc) => {
if (error != null) return next(error) if (err) return next(err)
res.json({ res.json({
doc_id: doc._id doc_id: doc._id
}) })
@ -189,51 +151,48 @@ module.exports = HistoryController = {
}, },
getLabels(req, res, next) { getLabels(req, res, next) {
const project_id = req.params.Project_id const projectId = req.params.Project_id
const user_id = AuthenticationController.getLoggedInUserId(req) HistoryController._makeRequest(
return HistoryController._makeRequest(
{ {
method: 'GET', method: 'GET',
url: `${ url: `${settings.apis.project_history.url}/project/${projectId}/labels`,
settings.apis.project_history.url
}/project/${project_id}/labels`,
json: true json: true
}, },
function(error, labels) { function(err, labels) {
if (error != null) { if (err) {
return next(error) return next(err)
} }
HistoryController._enrichLabels(labels, (err, labels) => { HistoryController._enrichLabels(labels, (err, labels) => {
if (err) { if (err) {
return next(err) return next(err)
} }
return res.json(labels) res.json(labels)
}) })
} }
) )
}, },
createLabel(req, res, next) { createLabel(req, res, next) {
const project_id = req.params.Project_id const projectId = req.params.Project_id
const { comment, version } = req.body const { comment, version } = req.body
const user_id = AuthenticationController.getLoggedInUserId(req) const userId = AuthenticationController.getLoggedInUserId(req)
return HistoryController._makeRequest( HistoryController._makeRequest(
{ {
method: 'POST', method: 'POST',
url: `${ url: `${
settings.apis.project_history.url settings.apis.project_history.url
}/project/${project_id}/user/${user_id}/labels`, }/project/${projectId}/user/${userId}/labels`,
json: { comment, version } json: { comment, version }
}, },
function(error, label) { function(err, label) {
if (error != null) { if (err) {
return next(error) return next(err)
} }
HistoryController._enrichLabel(label, (err, label) => { HistoryController._enrichLabel(label, (err, label) => {
if (err) { if (err) {
return next(err) return next(err)
} }
return res.json(label) res.json(label)
}) })
} }
) )
@ -293,7 +252,7 @@ module.exports = HistoryController = {
if (user == null) { if (user == null) {
return 'Anonymous' return 'Anonymous'
} }
if (user.name != null) { if (user.name) {
return user.name return user.name
} }
let name = [user.first_name, user.last_name] let name = [user.first_name, user.last_name]
@ -303,67 +262,66 @@ module.exports = HistoryController = {
if (name === '') { if (name === '') {
name = user.email.split('@')[0] name = user.email.split('@')[0]
} }
if (name == null || name === '') { if (!name) {
return '?' return '?'
} }
return name return name
}, },
deleteLabel(req, res, next) { deleteLabel(req, res, next) {
const project_id = req.params.Project_id const { Project_id: projectId, label_id: labelId } = req.params
const { label_id } = req.params const userId = AuthenticationController.getLoggedInUserId(req)
const user_id = AuthenticationController.getLoggedInUserId(req) HistoryController._makeRequest(
return HistoryController._makeRequest(
{ {
method: 'DELETE', method: 'DELETE',
url: `${ url: `${
settings.apis.project_history.url settings.apis.project_history.url
}/project/${project_id}/user/${user_id}/labels/${label_id}` }/project/${projectId}/user/${userId}/labels/${labelId}`
}, },
function(error) { function(err) {
if (error != null) { if (err) {
return next(error) return next(err)
} }
return res.sendStatus(204) res.sendStatus(204)
} }
) )
}, },
_makeRequest(options, callback) { _makeRequest(options, callback) {
return request(options, function(error, response, body) { return request(options, function(err, response, body) {
if (error != null) { if (err) {
return callback(error) return callback(err)
} }
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
return callback(null, body) callback(null, body)
} else { } else {
error = new Error( err = new Error(
`history api responded with non-success code: ${response.statusCode}` `history api responded with non-success code: ${response.statusCode}`
) )
return callback(error) callback(err)
} }
}) })
}, },
downloadZipOfVersion(req, res, next) { downloadZipOfVersion(req, res, next) {
const { project_id, version } = req.params const { project_id: projectId, version } = req.params
return ProjectDetailsHandler.getDetails(project_id, function(err, project) { ProjectDetailsHandler.getDetails(projectId, function(err, project) {
if (err != null) { if (err) {
return next(err) return next(err)
} }
const v1_id = __guard__( const v1Id =
project.overleaf != null ? project.overleaf.history : undefined, project.overleaf &&
x => x.id project.overleaf.history &&
) project.overleaf.history.id
if (v1_id == null) { if (v1Id == null) {
logger.err( logger.error(
{ project_id, version }, { projectId, version },
'got request for zip version of non-v1 history project' 'got request for zip version of non-v1 history project'
) )
return res.sendStatus(402) return res.sendStatus(402)
} }
return HistoryController._pipeHistoryZipToResponse( HistoryController._pipeHistoryZipToResponse(
v1_id, v1Id,
version, version,
`${project.name} (Version ${version})`, `${project.name} (Version ${version})`,
req, req,
@ -373,7 +331,7 @@ module.exports = HistoryController = {
}) })
}, },
_pipeHistoryZipToResponse(v1_project_id, version, name, req, res, next) { _pipeHistoryZipToResponse(v1ProjectId, version, name, req, res, next) {
if (req.aborted) { if (req.aborted) {
// client has disconnected -- skip project history api call and download // client has disconnected -- skip project history api call and download
return return
@ -382,7 +340,7 @@ module.exports = HistoryController = {
res.setTimeout(6 * 60 * 1000) res.setTimeout(6 * 60 * 1000)
const url = `${ const url = `${
settings.apis.v1_history.url settings.apis.v1_history.url
}/projects/${v1_project_id}/version/${version}/zip` }/projects/${v1ProjectId}/version/${version}/zip`
const options = { const options = {
auth: { auth: {
user: settings.apis.v1_history.user, user: settings.apis.v1_history.user,
@ -392,10 +350,10 @@ module.exports = HistoryController = {
method: 'post', method: 'post',
url url
} }
return request(options, function(err, response, body) { request(options, function(err, response, body) {
if (err) { if (err) {
OError.tag(err, 'history API error', { OError.tag(err, 'history API error', {
v1_project_id, v1ProjectId,
version version
}) })
return next(err) return next(err)
@ -407,7 +365,7 @@ module.exports = HistoryController = {
let retryAttempt = 0 let retryAttempt = 0
let retryDelay = 2000 let retryDelay = 2000
// retry for about 6 minutes starting with short delay // retry for about 6 minutes starting with short delay
return async.retry( async.retry(
40, 40,
callback => callback =>
setTimeout(function() { setTimeout(function() {
@ -448,39 +406,33 @@ module.exports = HistoryController = {
pipeline(response, res, err => { pipeline(response, res, err => {
if (err) { if (err) {
logger.warn( logger.warn(
{ err, v1_project_id, version, retryAttempt }, { err, v1ProjectId, version, retryAttempt },
'history s3 proxying error' 'history s3 proxying error'
) )
} }
}) })
callback() callback()
}) })
return getReq.on('error', function(err) { getReq.on('error', function(err) {
logger.warn( logger.warn(
{ err, v1_project_id, version, retryAttempt }, { err, v1ProjectId, version, retryAttempt },
'history s3 download error' 'history s3 download error'
) )
cleanupAbortTrigger() cleanupAbortTrigger()
return callback(err) callback(err)
}) })
}, retryDelay), }, retryDelay),
function(err) { function(err) {
if (err) { if (err) {
OError.tag(err, 'history s3 download failed', { OError.tag(err, 'history s3 download failed', {
v1_project_id, v1ProjectId,
version, version,
retryAttempt retryAttempt
}) })
return next(err) next(err)
} }
} }
) )
}) })
} }
} }
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}

View file

@ -59,7 +59,7 @@ describe('HistoryController', function() {
describe('selectHistoryApi', function() { describe('selectHistoryApi', function() {
beforeEach(function() { beforeEach(function() {
this.req = { url: '/mock/url', method: 'POST' } this.req = { url: '/mock/url', method: 'POST', params: {} }
this.res = 'mock-res' this.res = 'mock-res'
return (this.next = sinon.stub()) return (this.next = sinon.stub())
}) })