ReferencesHandler.mjs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* eslint-disable
  2. n/handle-callback-err,
  3. max-len,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * DS103: Rewrite code to no longer use __guard__
  12. * DS207: Consider shorter variations of null checks
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  14. */
  15. import OError from '@overleaf/o-error'
  16. import logger from '@overleaf/logger'
  17. import request from 'request'
  18. import settings from '@overleaf/settings'
  19. import Features from '../../infrastructure/Features.js'
  20. import ProjectGetter from '../Project/ProjectGetter.js'
  21. import UserGetter from '../User/UserGetter.js'
  22. import DocumentUpdaterHandler from '../DocumentUpdater/DocumentUpdaterHandler.js'
  23. import _ from 'lodash'
  24. import Async from 'async'
  25. import Errors from '../Errors/Errors.js'
  26. import { promisify } from '@overleaf/promise-utils'
  27. let ReferencesHandler
  28. if (!Features.hasFeature('references')) {
  29. logger.debug('references search not enabled')
  30. }
  31. export default ReferencesHandler = {
  32. _buildDocUrl(projectId, docId) {
  33. return `${settings.apis.docstore.url}/project/${projectId}/doc/${docId}/raw`
  34. },
  35. _buildFileUrl(projectId, fileId) {
  36. return `${settings.apis.filestore.url}/project/${projectId}/file/${fileId}`
  37. },
  38. _findBibFileIds(project) {
  39. const ids = []
  40. function _process(folder) {
  41. _.forEach(folder.fileRefs || [], function (file) {
  42. if (
  43. __guard__(file != null ? file.name : undefined, x1 =>
  44. x1.match(/^.*\.bib$/)
  45. )
  46. ) {
  47. return ids.push(file._id)
  48. }
  49. })
  50. return _.forEach(folder.folders || [], folder => _process(folder))
  51. }
  52. _.forEach(project.rootFolder || [], rootFolder => _process(rootFolder))
  53. return ids
  54. },
  55. _findBibDocIds(project) {
  56. const ids = []
  57. function _process(folder) {
  58. _.forEach(folder.docs || [], function (doc) {
  59. if (
  60. __guard__(doc != null ? doc.name : undefined, x1 =>
  61. x1.match(/^.*\.bib$/)
  62. )
  63. ) {
  64. return ids.push(doc._id)
  65. }
  66. })
  67. return _.forEach(folder.folders || [], folder => _process(folder))
  68. }
  69. _.forEach(project.rootFolder || [], rootFolder => _process(rootFolder))
  70. return ids
  71. },
  72. _isFullIndex(project, callback) {
  73. if (callback == null) {
  74. callback = function () {}
  75. }
  76. return UserGetter.getUser(
  77. project.owner_ref,
  78. { features: true },
  79. function (err, owner) {
  80. if (err != null) {
  81. return callback(err)
  82. }
  83. const features = owner != null ? owner.features : undefined
  84. return callback(
  85. null,
  86. (features != null ? features.references : undefined) === true ||
  87. (features != null ? features.referencesSearch : undefined) === true
  88. )
  89. }
  90. )
  91. },
  92. indexAll(projectId, callback) {
  93. if (callback == null) {
  94. callback = function () {}
  95. }
  96. return ProjectGetter.getProject(
  97. projectId,
  98. { rootFolder: true, owner_ref: 1 },
  99. function (err, project) {
  100. if (err) {
  101. OError.tag(err, 'error finding project', {
  102. projectId,
  103. })
  104. return callback(err)
  105. }
  106. if (!project) {
  107. return callback(
  108. new Errors.NotFoundError(`project does not exist: ${projectId}`)
  109. )
  110. }
  111. logger.debug({ projectId }, 'indexing all bib files in project')
  112. const docIds = ReferencesHandler._findBibDocIds(project)
  113. const fileIds = ReferencesHandler._findBibFileIds(project)
  114. return ReferencesHandler._doIndexOperation(
  115. projectId,
  116. project,
  117. docIds,
  118. fileIds,
  119. callback
  120. )
  121. }
  122. )
  123. },
  124. _doIndexOperation(projectId, project, docIds, fileIds, callback) {
  125. if (!Features.hasFeature('references')) {
  126. return callback()
  127. }
  128. return ReferencesHandler._isFullIndex(project, function (err, isFullIndex) {
  129. if (err) {
  130. OError.tag(err, 'error checking whether to do full index', {
  131. projectId,
  132. })
  133. return callback(err)
  134. }
  135. logger.debug(
  136. { projectId, docIds },
  137. 'flushing docs to mongo before calling references service'
  138. )
  139. return Async.series(
  140. docIds.map(
  141. docId => cb =>
  142. DocumentUpdaterHandler.flushDocToMongo(projectId, docId, cb)
  143. ),
  144. function (err) {
  145. // continue
  146. if (err) {
  147. OError.tag(err, 'error flushing docs to mongo', {
  148. projectId,
  149. docIds,
  150. })
  151. return callback(err)
  152. }
  153. const bibDocUrls = docIds.map(docId =>
  154. ReferencesHandler._buildDocUrl(projectId, docId)
  155. )
  156. const bibFileUrls = fileIds.map(fileId =>
  157. ReferencesHandler._buildFileUrl(projectId, fileId)
  158. )
  159. const allUrls = bibDocUrls.concat(bibFileUrls)
  160. return request.post(
  161. {
  162. url: `${settings.apis.references.url}/project/${projectId}/index`,
  163. json: {
  164. docUrls: allUrls,
  165. fullIndex: isFullIndex,
  166. },
  167. },
  168. function (err, res, data) {
  169. if (err) {
  170. OError.tag(err, 'error communicating with references api', {
  171. projectId,
  172. })
  173. return callback(err)
  174. }
  175. if (res.statusCode >= 200 && res.statusCode < 300) {
  176. logger.debug({ projectId }, 'got keys from references api')
  177. return callback(null, data)
  178. } else {
  179. err = new Error(
  180. `references api responded with non-success code: ${res.statusCode}`
  181. )
  182. return callback(err)
  183. }
  184. }
  185. )
  186. }
  187. )
  188. })
  189. },
  190. }
  191. ReferencesHandler.promises = {
  192. indexAll: promisify(ReferencesHandler.indexAll),
  193. }
  194. function __guard__(value, transform) {
  195. return typeof value !== 'undefined' && value !== null
  196. ? transform(value)
  197. : undefined
  198. }