ProjectFileAgent.coffee 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. V1ProjectNotFoundError: V1ProjectNotFoundError
  49. _v1ProjectNotFoundMessage: "Sorry, the source project is not yet imported to Overleaf v2. Please import it to Overleaf v2 to refresh this file"
  50. sanitizeData: (data) ->
  51. return _.pick(
  52. data,
  53. 'source_project_id',
  54. 'v1_source_doc_id',
  55. 'source_entity_path'
  56. )
  57. _validate: (data) ->
  58. return (
  59. (data.source_project_id? || data.v1_source_doc_id?) &&
  60. data.source_entity_path?
  61. )
  62. canCreate: (data) ->
  63. # Don't allow creation of linked-files with v1 doc ids
  64. !data.v1_source_doc_id?
  65. _getSourceProject: (data, callback=(err, project)->) ->
  66. projection = {_id: 1, name: 1}
  67. if data.v1_source_doc_id?
  68. Project.findOne {'overleaf.id': data.v1_source_doc_id}, projection, (err, project) ->
  69. return callback(err) if err?
  70. if !project?
  71. return callback(new V1ProjectNotFoundError())
  72. callback(null, project)
  73. else if data.source_project_id?
  74. ProjectGetter.getProject data.source_project_id, projection, (err, project) ->
  75. return callback(err) if err?
  76. if !project?
  77. return callback(new ProjectNotFoundError())
  78. callback(null, project)
  79. else
  80. callback(new BadDataError('neither v1 nor v2 id present'))
  81. decorateLinkedFileData: (data, callback = (err, newData) ->) ->
  82. callback = _.once(callback)
  83. @_getSourceProject data, (err, project) ->
  84. return callback(err) if err?
  85. callback(err, _.extend(data, {source_project_display_name: project.name}))
  86. checkAuth: (project_id, data, current_user_id, callback = (error, allowed)->) ->
  87. callback = _.once(callback)
  88. if !ProjectFileAgent._validate(data)
  89. return callback(new BadDataError())
  90. @_getSourceProject data, (err, project) ->
  91. return callback(err) if err?
  92. AuthorizationManager.canUserReadProject current_user_id, project._id, null, (err, canRead) ->
  93. return callback(err) if err?
  94. callback(null, canRead)
  95. writeIncomingFileToDisk:
  96. (project_id, data, current_user_id, callback = (error, fsPath) ->) ->
  97. callback = _.once(callback)
  98. if !ProjectFileAgent._validate(data)
  99. return callback(new BadDataError())
  100. { source_entity_path } = data
  101. @_getSourceProject data, (err, project) ->
  102. return callback(err) if err?
  103. source_project_id = project._id
  104. ProjectLocator.findElementByPath {
  105. project_id: source_project_id,
  106. path: source_entity_path
  107. }, (err, entity, type) ->
  108. if err?
  109. if err.toString().match(/^not found.*/)
  110. err = new SourceFileNotFoundError()
  111. return callback(err)
  112. ProjectFileAgent._writeEntityToDisk source_project_id, entity._id, type, callback
  113. _writeEntityToDisk: (project_id, entity_id, type, callback=(err, location)->) ->
  114. callback = _.once(callback)
  115. if type == 'doc'
  116. DocstoreManager.getDoc project_id, entity_id, (err, lines) ->
  117. return callback(err) if err?
  118. FileWriter.writeLinesToDisk entity_id, lines, callback
  119. else if type == 'file'
  120. FileStoreHandler.getFileStream project_id, entity_id, null, (err, fileStream) ->
  121. return callback(err) if err?
  122. FileWriter.writeStreamToDisk entity_id, fileStream, callback
  123. else
  124. callback(new BadEntityTypeError())
  125. handleError: (error, req, res, next) ->
  126. if error instanceof AccessDeniedError
  127. res.status(403).send("You do not have access to this project")
  128. else if error instanceof BadDataError
  129. res.status(400).send("The submitted data is not valid")
  130. else if error instanceof BadEntityTypeError
  131. res.status(400).send("The file is the wrong type")
  132. else if error instanceof SourceFileNotFoundError
  133. res.status(404).send("Source file not found")
  134. else if error instanceof ProjectNotFoundError
  135. res.status(404).send("Project not found")
  136. else if error instanceof V1ProjectNotFoundError
  137. res.status(409).send(ProjectFileAgent._v1ProjectNotFoundMessage)
  138. else
  139. next(error)
  140. next()