HistoryController.coffee 5.4 KB

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