ProjectFileAgent.coffee 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. FileWriter = require('../../infrastructure/FileWriter')
  2. AuthorizationManager = require('../Authorization/AuthorizationManager')
  3. ProjectLocator = require('../Project/ProjectLocator')
  4. ProjectGetter = require('../Project/ProjectGetter')
  5. Project = require("../../models/Project").Project
  6. DocstoreManager = require('../Docstore/DocstoreManager')
  7. FileStoreHandler = require('../FileStore/FileStoreHandler')
  8. FileWriter = require('../../infrastructure/FileWriter')
  9. _ = require "underscore"
  10. Settings = require 'settings-sharelatex'
  11. AccessDeniedError = (message) ->
  12. error = new Error(message)
  13. error.name = 'AccessDenied'
  14. error.__proto__ = AccessDeniedError.prototype
  15. return error
  16. AccessDeniedError.prototype.__proto__ = Error.prototype
  17. BadEntityTypeError = (message) ->
  18. error = new Error(message)
  19. error.name = 'BadEntityType'
  20. error.__proto__ = BadEntityTypeError.prototype
  21. return error
  22. BadEntityTypeError.prototype.__proto__ = Error.prototype
  23. BadDataError = (message) ->
  24. error = new Error(message)
  25. error.name = 'BadData'
  26. error.__proto__ = BadDataError.prototype
  27. return error
  28. BadDataError.prototype.__proto__ = Error.prototype
  29. ProjectNotFoundError = (message) ->
  30. error = new Error(message)
  31. error.name = 'ProjectNotFound'
  32. error.__proto__ = ProjectNotFoundError.prototype
  33. return error
  34. ProjectNotFoundError.prototype.__proto__ = Error.prototype
  35. V1ProjectNotFoundError = (message) ->
  36. error = new Error(message)
  37. error.name = 'V1ProjectNotFound'
  38. error.__proto__ = V1ProjectNotFoundError.prototype
  39. return error
  40. V1ProjectNotFoundError.prototype.__proto__ = Error.prototype
  41. SourceFileNotFoundError = (message) ->
  42. error = new Error(message)
  43. error.name = 'SourceFileNotFound'
  44. error.__proto__ = SourceFileNotFoundError.prototype
  45. return error
  46. SourceFileNotFoundError.prototype.__proto__ = Error.prototype
  47. module.exports = ProjectFileAgent =
  48. sanitizeData: (data) ->
  49. return _.pick(
  50. data,
  51. 'source_project_id',
  52. 'v1_source_doc_id',
  53. 'source_entity_path'
  54. )
  55. _validate: (data) ->
  56. return (
  57. (data.source_project_id? || data.v1_source_doc_id?) &&
  58. data.source_entity_path?
  59. )
  60. canCreate: (data) ->
  61. # Don't allow creation of linked-files with v1 doc ids
  62. !data.v1_source_doc_id?
  63. _getSourceProject: (data, callback=(err, project)->) ->
  64. projection = {_id: 1, name: 1}
  65. if data.v1_source_doc_id?
  66. Project.findOne {'overleaf.id': data.v1_source_doc_id}, projection, (err, project) ->
  67. return callback(err) if err?
  68. if !project?
  69. return callback(new V1ProjectNotFoundError())
  70. callback(null, project)
  71. else if data.source_project_id?
  72. ProjectGetter.getProject data.source_project_id, projection, (err, project) ->
  73. return callback(err) if err?
  74. if !project?
  75. return callback(new ProjectNotFoundError())
  76. callback(null, project)
  77. else
  78. callback(new BadDataError('neither v1 nor v2 id present'))
  79. decorateLinkedFileData: (data, callback = (err, newData) ->) ->
  80. callback = _.once(callback)
  81. @_getSourceProject data, (err, project) ->
  82. return callback(err) if err?
  83. callback(err, _.extend(data, {source_project_display_name: project.name}))
  84. checkAuth: (project_id, data, current_user_id, callback = (error, allowed)->) ->
  85. callback = _.once(callback)
  86. if !ProjectFileAgent._validate(data)
  87. return callback(new BadDataError())
  88. @_getSourceProject data, (err, project) ->
  89. return callback(err) if err?
  90. AuthorizationManager.canUserReadProject current_user_id, project._id, null, (err, canRead) ->
  91. return callback(err) if err?
  92. callback(null, canRead)
  93. writeIncomingFileToDisk:
  94. (project_id, data, current_user_id, callback = (error, fsPath) ->) ->
  95. callback = _.once(callback)
  96. if !ProjectFileAgent._validate(data)
  97. return callback(new BadDataError())
  98. { source_entity_path } = data
  99. @_getSourceProject data, (err, project) ->
  100. return callback(err) if err?
  101. source_project_id = project._id
  102. ProjectLocator.findElementByPath {
  103. project_id: source_project_id,
  104. path: source_entity_path
  105. }, (err, entity, type) ->
  106. if err?
  107. if err.toString().match(/^not found.*/)
  108. err = new SourceFileNotFoundError()
  109. return callback(err)
  110. ProjectFileAgent._writeEntityToDisk source_project_id, entity._id, type, callback
  111. _writeEntityToDisk: (project_id, entity_id, type, callback=(err, location)->) ->
  112. callback = _.once(callback)
  113. if type == 'doc'
  114. DocstoreManager.getDoc project_id, entity_id, (err, lines) ->
  115. return callback(err) if err?
  116. FileWriter.writeLinesToDisk entity_id, lines, callback
  117. else if type == 'file'
  118. FileStoreHandler.getFileStream project_id, entity_id, null, (err, fileStream) ->
  119. return callback(err) if err?
  120. FileWriter.writeStreamToDisk entity_id, fileStream, callback
  121. else
  122. callback(new BadEntityTypeError())
  123. handleError: (error, req, res, next) ->
  124. if error instanceof AccessDeniedError
  125. res.status(403).send("You do not have access to this project")
  126. else if error instanceof BadDataError
  127. res.status(400).send("The submitted data is not valid")
  128. else if error instanceof BadEntityTypeError
  129. res.status(400).send("The file is the wrong type")
  130. else if error instanceof SourceFileNotFoundError
  131. res.status(404).send("Source file not found")
  132. else if error instanceof ProjectNotFoundError
  133. res.status(404).send("Project not found")
  134. else if error instanceof V1ProjectNotFoundError
  135. res.status(409).send("Sorry, the source project is not yet imported to Overleaf v2. Please import it to Overleaf v2 to refresh this file")
  136. else
  137. next(error)
  138. next()