Modules.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. const fs = require('fs')
  2. const Path = require('path')
  3. const pug = require('pug')
  4. const async = require('async')
  5. const { promisify } = require('util')
  6. const Settings = require('@overleaf/settings')
  7. const MODULE_BASE_PATH = Path.join(__dirname, '/../../../modules')
  8. const _modules = []
  9. const _hooks = {}
  10. let _viewIncludes = {}
  11. function loadModules() {
  12. const settingsCheckModule = Path.join(
  13. MODULE_BASE_PATH,
  14. 'settings-check',
  15. 'index.js'
  16. )
  17. if (fs.existsSync(settingsCheckModule)) {
  18. require(settingsCheckModule)
  19. }
  20. for (const moduleName of Settings.moduleImportSequence || []) {
  21. const loadedModule = require(Path.join(
  22. MODULE_BASE_PATH,
  23. moduleName,
  24. 'index.js'
  25. ))
  26. loadedModule.name = moduleName
  27. _modules.push(loadedModule)
  28. }
  29. attachHooks()
  30. }
  31. function applyRouter(webRouter, privateApiRouter, publicApiRouter) {
  32. for (const module of _modules) {
  33. if (module.router && module.router.apply) {
  34. module.router.apply(webRouter, privateApiRouter, publicApiRouter)
  35. }
  36. }
  37. }
  38. function applyNonCsrfRouter(webRouter, privateApiRouter, publicApiRouter) {
  39. for (const module of _modules) {
  40. if (module.nonCsrfRouter != null) {
  41. module.nonCsrfRouter.apply(webRouter, privateApiRouter, publicApiRouter)
  42. }
  43. if (module.router && module.router.applyNonCsrfRouter) {
  44. module.router.applyNonCsrfRouter(
  45. webRouter,
  46. privateApiRouter,
  47. publicApiRouter
  48. )
  49. }
  50. }
  51. }
  52. function loadViewIncludes(app) {
  53. _viewIncludes = {}
  54. for (const module of _modules) {
  55. const object = module.viewIncludes || {}
  56. for (const view in object) {
  57. const partial = object[view]
  58. if (!_viewIncludes[view]) {
  59. _viewIncludes[view] = []
  60. }
  61. const filePath = Path.join(
  62. MODULE_BASE_PATH,
  63. module.name,
  64. 'app/views',
  65. partial + '.pug'
  66. )
  67. _viewIncludes[view].push(
  68. pug.compileFile(filePath, {
  69. doctype: 'html',
  70. compileDebug: Settings.debugPugTemplates,
  71. })
  72. )
  73. }
  74. }
  75. }
  76. function registerAppMiddleware(app) {
  77. for (const module of _modules) {
  78. if (module.appMiddleware) {
  79. module.appMiddleware(app)
  80. }
  81. }
  82. }
  83. function moduleIncludes(view, locals) {
  84. const compiledPartials = _viewIncludes[view] || []
  85. let html = ''
  86. for (const compiledPartial of compiledPartials) {
  87. html += compiledPartial(locals)
  88. }
  89. return html
  90. }
  91. function moduleIncludesAvailable(view) {
  92. return (_viewIncludes[view] || []).length > 0
  93. }
  94. function linkedFileAgentsIncludes() {
  95. const agents = {}
  96. for (const module of _modules) {
  97. for (const name in module.linkedFileAgents) {
  98. const agentFunction = module.linkedFileAgents[name]
  99. agents[name] = agentFunction()
  100. }
  101. }
  102. return agents
  103. }
  104. function attachHooks() {
  105. for (const module of _modules) {
  106. if (module.hooks != null) {
  107. for (const hook in module.hooks) {
  108. const method = module.hooks[hook]
  109. attachHook(hook, method)
  110. }
  111. }
  112. }
  113. }
  114. function attachHook(name, method) {
  115. if (_hooks[name] == null) {
  116. _hooks[name] = []
  117. }
  118. _hooks[name].push(method)
  119. }
  120. function fireHook(name, ...rest) {
  121. const adjustedLength = Math.max(rest.length, 1)
  122. const args = rest.slice(0, adjustedLength - 1)
  123. const callback = rest[adjustedLength - 1]
  124. const methods = _hooks[name] || []
  125. const callMethods = methods.map(method => cb => method(...args, cb))
  126. async.series(callMethods, function (error, results) {
  127. if (error) {
  128. return callback(error)
  129. }
  130. callback(null, results)
  131. })
  132. }
  133. module.exports = {
  134. applyNonCsrfRouter,
  135. applyRouter,
  136. linkedFileAgentsIncludes,
  137. loadViewIncludes,
  138. moduleIncludes,
  139. moduleIncludesAvailable,
  140. registerAppMiddleware,
  141. hooks: {
  142. attach: attachHook,
  143. fire: fireHook,
  144. },
  145. promises: {
  146. hooks: {
  147. fire: promisify(fireHook),
  148. },
  149. },
  150. }
  151. loadModules()