ProjectFileAgent.coffee 5.6 KB

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