ReferencesHandler.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* eslint-disable
  2. node/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. let ReferencesHandler
  16. const OError = require('@overleaf/o-error')
  17. const logger = require('logger-sharelatex')
  18. const request = require('request')
  19. const settings = require('@overleaf/settings')
  20. const Features = require('../../infrastructure/Features')
  21. const ProjectGetter = require('../Project/ProjectGetter')
  22. const UserGetter = require('../User/UserGetter')
  23. const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
  24. const _ = require('underscore')
  25. const Async = require('async')
  26. const oneMinInMs = 60 * 1000
  27. const fiveMinsInMs = oneMinInMs * 5
  28. if (!Features.hasFeature('references')) {
  29. logger.log('references search not enabled')
  30. }
  31. module.exports = 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. var _process = function (folder) {
  41. _.each(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 _.each(folder.folders || [], folder => _process(folder))
  51. }
  52. _.each(project.rootFolder || [], rootFolder => _process(rootFolder))
  53. return ids
  54. },
  55. _findBibDocIds(project) {
  56. const ids = []
  57. var _process = function (folder) {
  58. _.each(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 _.each(folder.folders || [], folder => _process(folder))
  68. }
  69. _.each(project.rootFolder || [], rootFolder => _process(rootFolder))
  70. return ids
  71. },
  72. _isFullIndex(project, callback) {
  73. if (callback == null) {
  74. callback = function (err, result) {}
  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 (err, data) {}
  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. logger.log({ projectId }, 'indexing all bib files in project')
  107. const docIds = ReferencesHandler._findBibDocIds(project)
  108. const fileIds = ReferencesHandler._findBibFileIds(project)
  109. return ReferencesHandler._doIndexOperation(
  110. projectId,
  111. project,
  112. docIds,
  113. fileIds,
  114. callback
  115. )
  116. }
  117. )
  118. },
  119. index(projectId, docIds, callback) {
  120. if (callback == null) {
  121. callback = function (err, data) {}
  122. }
  123. return ProjectGetter.getProject(
  124. projectId,
  125. { rootFolder: true, owner_ref: 1 },
  126. function (err, project) {
  127. if (err) {
  128. OError.tag(err, 'error finding project', {
  129. projectId,
  130. })
  131. return callback(err)
  132. }
  133. return ReferencesHandler._doIndexOperation(
  134. projectId,
  135. project,
  136. docIds,
  137. [],
  138. callback
  139. )
  140. }
  141. )
  142. },
  143. _doIndexOperation(projectId, project, docIds, fileIds, callback) {
  144. if (!Features.hasFeature('references')) {
  145. return callback()
  146. }
  147. return ReferencesHandler._isFullIndex(project, function (err, isFullIndex) {
  148. if (err) {
  149. OError.tag(err, 'error checking whether to do full index', {
  150. projectId,
  151. })
  152. return callback(err)
  153. }
  154. logger.log(
  155. { projectId, docIds },
  156. 'flushing docs to mongo before calling references service'
  157. )
  158. return Async.series(
  159. docIds.map(docId => cb =>
  160. DocumentUpdaterHandler.flushDocToMongo(projectId, docId, cb)
  161. ),
  162. function (err) {
  163. // continue
  164. if (err) {
  165. OError.tag(err, 'error flushing docs to mongo', {
  166. projectId,
  167. docIds,
  168. })
  169. return callback(err)
  170. }
  171. const bibDocUrls = docIds.map(docId =>
  172. ReferencesHandler._buildDocUrl(projectId, docId)
  173. )
  174. const bibFileUrls = fileIds.map(fileId =>
  175. ReferencesHandler._buildFileUrl(projectId, fileId)
  176. )
  177. const allUrls = bibDocUrls.concat(bibFileUrls)
  178. return request.post(
  179. {
  180. url: `${settings.apis.references.url}/project/${projectId}/index`,
  181. json: {
  182. docUrls: allUrls,
  183. fullIndex: isFullIndex,
  184. },
  185. },
  186. function (err, res, data) {
  187. if (err) {
  188. OError.tag(err, 'error communicating with references api', {
  189. projectId,
  190. })
  191. return callback(err)
  192. }
  193. if (res.statusCode >= 200 && res.statusCode < 300) {
  194. logger.log({ projectId }, 'got keys from references api')
  195. return callback(null, data)
  196. } else {
  197. err = new Error(
  198. `references api responded with non-success code: ${res.statusCode}`
  199. )
  200. return callback(err)
  201. }
  202. }
  203. )
  204. }
  205. )
  206. })
  207. },
  208. }
  209. function __guard__(value, transform) {
  210. return typeof value !== 'undefined' && value !== null
  211. ? transform(value)
  212. : undefined
  213. }