HistoryController.coffee 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. logger = require "logger-sharelatex"
  2. request = require "request"
  3. settings = require "settings-sharelatex"
  4. AuthenticationController = require "../Authentication/AuthenticationController"
  5. Errors = require "../Errors/Errors"
  6. HistoryManager = require "./HistoryManager"
  7. ProjectDetailsHandler = require "../Project/ProjectDetailsHandler"
  8. ProjectEntityUpdateHandler = require "../Project/ProjectEntityUpdateHandler"
  9. RestoreManager = require "./RestoreManager"
  10. module.exports = HistoryController =
  11. selectHistoryApi: (req, res, next = (error) ->) ->
  12. project_id = req.params?.Project_id
  13. # find out which type of history service this project uses
  14. ProjectDetailsHandler.getDetails project_id, (err, project) ->
  15. return next(err) if err?
  16. history = project.overleaf?.history
  17. if history?.id? and history?.display
  18. req.useProjectHistory = true
  19. else
  20. req.useProjectHistory = false
  21. next()
  22. ensureProjectHistoryEnabled: (req, res, next = (error) ->) ->
  23. if req.useProjectHistory?
  24. next()
  25. else
  26. logger.log {project_id}, "project history not enabled"
  27. res.sendStatus(404)
  28. proxyToHistoryApi: (req, res, next = (error) ->) ->
  29. user_id = AuthenticationController.getLoggedInUserId req
  30. url = HistoryController.buildHistoryServiceUrl(req.useProjectHistory) + req.url
  31. logger.log url: url, "proxying to history api"
  32. getReq = request(
  33. url: url
  34. method: req.method
  35. headers:
  36. "X-User-Id": user_id
  37. )
  38. getReq.pipe(res)
  39. getReq.on "error", (error) ->
  40. logger.error url: url, err: error, "history API error"
  41. next(error)
  42. proxyToHistoryApiAndInjectUserDetails: (req, res, next = (error) ->) ->
  43. user_id = AuthenticationController.getLoggedInUserId req
  44. url = HistoryController.buildHistoryServiceUrl(req.useProjectHistory) + req.url
  45. logger.log url: url, "proxying to history api"
  46. HistoryController._makeRequest {
  47. url: url
  48. method: req.method
  49. json: true
  50. headers:
  51. "X-User-Id": user_id
  52. }, (error, body) ->
  53. return next(error) if error?
  54. HistoryManager.injectUserDetails body, (error, data) ->
  55. return next(error) if error?
  56. res.json data
  57. buildHistoryServiceUrl: (useProjectHistory) ->
  58. # choose a history service, either document-level (trackchanges)
  59. # or project-level (project_history)
  60. if useProjectHistory
  61. return settings.apis.project_history.url
  62. else
  63. return settings.apis.trackchanges.url
  64. resyncProjectHistory: (req, res, next = (error) ->) ->
  65. project_id = req.params.Project_id
  66. ProjectEntityUpdateHandler.resyncProjectHistory project_id, (error) ->
  67. return res.sendStatus(404) if error instanceof Errors.ProjectHistoryDisabledError
  68. return next(error) if error?
  69. res.sendStatus 204
  70. restoreFileFromV2: (req, res, next) ->
  71. {project_id} = req.params
  72. {version, pathname} = req.body
  73. user_id = AuthenticationController.getLoggedInUserId req
  74. logger.log {project_id, version, pathname}, "restoring file from v2"
  75. RestoreManager.restoreFileFromV2 user_id, project_id, version, pathname, (error, entity) ->
  76. return next(error) if error?
  77. res.json {
  78. type: entity.type,
  79. id: entity._id
  80. }
  81. restoreDocFromDeletedDoc: (req, res, next) ->
  82. {project_id, doc_id} = req.params
  83. {name} = req.body
  84. user_id = AuthenticationController.getLoggedInUserId(req)
  85. if !name?
  86. return res.sendStatus 400 # Malformed request
  87. logger.log {project_id, doc_id, user_id}, "restoring doc from v1 deleted doc"
  88. RestoreManager.restoreDocFromDeletedDoc user_id, project_id, doc_id, name, (err, doc) =>
  89. return next(error) if error?
  90. res.json {
  91. doc_id: doc._id
  92. }
  93. getLabels: (req, res, next) ->
  94. project_id = req.params.Project_id
  95. user_id = AuthenticationController.getLoggedInUserId(req)
  96. HistoryController._makeRequest {
  97. method: "GET"
  98. url: "#{settings.apis.project_history.url}/project/#{project_id}/labels"
  99. json: true
  100. }, (error, labels) ->
  101. return next(error) if error?
  102. res.json labels
  103. createLabel: (req, res, next) ->
  104. project_id = req.params.Project_id
  105. {comment, version} = req.body
  106. user_id = AuthenticationController.getLoggedInUserId(req)
  107. HistoryController._makeRequest {
  108. method: "POST"
  109. url: "#{settings.apis.project_history.url}/project/#{project_id}/user/#{user_id}/labels"
  110. json: {comment, version}
  111. }, (error, label) ->
  112. return next(error) if error?
  113. res.json label
  114. deleteLabel: (req, res, next) ->
  115. project_id = req.params.Project_id
  116. label_id = req.params.label_id
  117. user_id = AuthenticationController.getLoggedInUserId(req)
  118. HistoryController._makeRequest {
  119. method: "DELETE"
  120. url: "#{settings.apis.project_history.url}/project/#{project_id}/user/#{user_id}/labels/#{label_id}"
  121. }, (error) ->
  122. return next(error) if error?
  123. res.sendStatus 204
  124. _makeRequest: (options, callback) ->
  125. request options, (error, response, body) ->
  126. return callback(error) if error?
  127. if 200 <= response.statusCode < 300
  128. callback(null, body)
  129. else
  130. error = new Error("history api responded with non-success code: #{response.statusCode}")
  131. logger.error err: error, "project-history api responded with non-success code: #{response.statusCode}"
  132. callback(error)