ProjectFileAgent.mjs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* eslint-disable
  2. n/handle-callback-err,
  3. max-len,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS102: Remove unnecessary code created because of implicit returns
  10. * DS207: Consider shorter variations of null checks
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. import AuthorizationManager from '../Authorization/AuthorizationManager.mjs'
  14. import ProjectLocator from '../Project/ProjectLocator.mjs'
  15. import DocstoreManager from '../Docstore/DocstoreManager.mjs'
  16. import DocumentUpdaterHandler from '../DocumentUpdater/DocumentUpdaterHandler.mjs'
  17. import _ from 'lodash'
  18. import LinkedFilesHandler from './LinkedFilesHandler.mjs'
  19. import LinkedFilesErrors from './LinkedFilesErrors.mjs'
  20. import { promisify } from '@overleaf/promise-utils'
  21. import HistoryManager from '../History/HistoryManager.mjs'
  22. import Errors from '../Errors/Errors.js'
  23. const {
  24. BadDataError,
  25. AccessDeniedError,
  26. BadEntityTypeError,
  27. SourceFileNotFoundError,
  28. } = LinkedFilesErrors
  29. let ProjectFileAgent
  30. export default ProjectFileAgent = {
  31. createLinkedFile(
  32. projectId,
  33. linkedFileData,
  34. name,
  35. parentFolderId,
  36. userId,
  37. callback
  38. ) {
  39. if (!ProjectFileAgent._canCreate(linkedFileData)) {
  40. return callback(new AccessDeniedError())
  41. }
  42. return ProjectFileAgent._go(
  43. projectId,
  44. linkedFileData,
  45. name,
  46. parentFolderId,
  47. userId,
  48. callback
  49. )
  50. },
  51. refreshLinkedFile(
  52. projectId,
  53. linkedFileData,
  54. name,
  55. parentFolderId,
  56. userId,
  57. callback
  58. ) {
  59. return ProjectFileAgent._go(
  60. projectId,
  61. linkedFileData,
  62. name,
  63. parentFolderId,
  64. userId,
  65. callback
  66. )
  67. },
  68. _prepare(projectId, linkedFileData, userId, callback) {
  69. if (callback == null) {
  70. callback = function () {}
  71. }
  72. return ProjectFileAgent._checkAuth(
  73. projectId,
  74. linkedFileData,
  75. userId,
  76. (err, allowed) => {
  77. if (err != null) {
  78. return callback(err)
  79. }
  80. if (!allowed) {
  81. return callback(new AccessDeniedError())
  82. }
  83. if (!ProjectFileAgent._validate(linkedFileData)) {
  84. return callback(new BadDataError())
  85. }
  86. return callback(null, linkedFileData)
  87. }
  88. )
  89. },
  90. _go(projectId, linkedFileData, name, parentFolderId, userId, callback) {
  91. linkedFileData = ProjectFileAgent._sanitizeData(linkedFileData)
  92. return ProjectFileAgent._prepare(
  93. projectId,
  94. linkedFileData,
  95. userId,
  96. (err, linkedFileData) => {
  97. if (err != null) {
  98. return callback(err)
  99. }
  100. if (!ProjectFileAgent._validate(linkedFileData)) {
  101. return callback(new BadDataError())
  102. }
  103. return ProjectFileAgent._getEntity(
  104. linkedFileData,
  105. userId,
  106. (err, sourceProject, entity, type) => {
  107. if (err != null) {
  108. return callback(err)
  109. }
  110. if (type === 'doc') {
  111. return DocstoreManager.getDoc(
  112. sourceProject._id,
  113. entity._id,
  114. function (err, lines) {
  115. if (err != null) {
  116. return callback(err)
  117. }
  118. return LinkedFilesHandler.importContent(
  119. projectId,
  120. lines.join('\n'),
  121. linkedFileData,
  122. name,
  123. parentFolderId,
  124. userId,
  125. function (err, file) {
  126. if (err != null) {
  127. return callback(err)
  128. }
  129. return callback(null, file._id)
  130. }
  131. )
  132. }
  133. ) // Created
  134. } else if (type === 'file') {
  135. return HistoryManager.requestBlob(
  136. sourceProject.overleaf.history.id,
  137. entity.hash,
  138. 'GET',
  139. function (err, result) {
  140. if (err != null) {
  141. return callback(err)
  142. }
  143. return LinkedFilesHandler.importFromStream(
  144. projectId,
  145. result.stream,
  146. linkedFileData,
  147. name,
  148. parentFolderId,
  149. userId,
  150. function (err, file) {
  151. if (err != null) {
  152. return callback(err)
  153. }
  154. return callback(null, file._id)
  155. }
  156. )
  157. }
  158. ) // Created
  159. } else {
  160. return callback(new BadEntityTypeError())
  161. }
  162. }
  163. )
  164. }
  165. )
  166. },
  167. _getEntity(linkedFileData, currentUserId, callback) {
  168. if (callback == null) {
  169. callback = function () {}
  170. }
  171. callback = _.once(callback)
  172. const { source_entity_path: sourceEntityPath } = linkedFileData
  173. return ProjectFileAgent._getSourceProject(
  174. linkedFileData,
  175. function (err, project) {
  176. if (err != null) {
  177. return callback(err)
  178. }
  179. const sourceProjectId = project._id
  180. return DocumentUpdaterHandler.flushProjectToMongo(
  181. sourceProjectId,
  182. function (err) {
  183. if (err != null) {
  184. return callback(err)
  185. }
  186. return ProjectLocator.findElementByPath(
  187. {
  188. project_id: sourceProjectId,
  189. path: sourceEntityPath,
  190. exactCaseMatch: true,
  191. },
  192. function (err, entity, type) {
  193. if (err != null) {
  194. if (err instanceof Errors.NotFoundError) {
  195. err = new SourceFileNotFoundError()
  196. }
  197. return callback(err)
  198. }
  199. return callback(null, project, entity, type)
  200. }
  201. )
  202. }
  203. )
  204. }
  205. )
  206. },
  207. _sanitizeData(data) {
  208. return _.pick(
  209. data,
  210. 'provider',
  211. 'source_project_id',
  212. 'v1_source_doc_id',
  213. 'source_entity_path',
  214. 'importedAt'
  215. )
  216. },
  217. _validate(data) {
  218. return (
  219. (data.source_project_id != null || data.v1_source_doc_id != null) &&
  220. data.source_entity_path != null
  221. )
  222. },
  223. _canCreate(data) {
  224. // Don't allow creation of linked-files with v1 doc ids
  225. return data.v1_source_doc_id == null
  226. },
  227. _getSourceProject: LinkedFilesHandler.getSourceProject,
  228. _checkAuth(projectId, data, currentUserId, callback) {
  229. if (callback == null) {
  230. callback = function () {}
  231. }
  232. callback = _.once(callback)
  233. if (!ProjectFileAgent._validate(data)) {
  234. return callback(new BadDataError())
  235. }
  236. return ProjectFileAgent._getSourceProject(data, function (err, project) {
  237. if (err != null) {
  238. return callback(err)
  239. }
  240. return AuthorizationManager.canUserReadProject(
  241. currentUserId,
  242. project._id,
  243. null,
  244. function (err, canRead) {
  245. if (err != null) {
  246. return callback(err)
  247. }
  248. return callback(null, canRead)
  249. }
  250. )
  251. })
  252. },
  253. }
  254. ProjectFileAgent.promises = {
  255. createLinkedFile: promisify(ProjectFileAgent.createLinkedFile),
  256. refreshLinkedFile: promisify(ProjectFileAgent.refreshLinkedFile),
  257. }