Router.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import OError from '@overleaf/o-error'
  2. import * as HttpController from './HttpController.js'
  3. import { Joi, validate } from './Validation.js'
  4. export function initialize(app) {
  5. app.use(
  6. validate({
  7. params: Joi.object({
  8. project_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  9. user_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  10. label_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  11. version: Joi.number().integer(),
  12. }),
  13. })
  14. )
  15. // use an extended timeout on all endpoints, to allow for long requests to history-v1
  16. app.use(longerTimeout)
  17. app.post('/project', HttpController.initializeProject)
  18. app.delete('/project/:project_id', HttpController.deleteProject)
  19. app.get(
  20. '/project/:project_id/diff',
  21. validate({
  22. query: {
  23. pathname: Joi.string().required(),
  24. from: Joi.number().integer().required(),
  25. to: Joi.number().integer().required(),
  26. },
  27. }),
  28. HttpController.getDiff
  29. )
  30. app.get(
  31. '/project/:project_id/filetree/diff',
  32. validate({
  33. query: {
  34. from: Joi.number().integer().required(),
  35. to: Joi.number().integer().required(),
  36. },
  37. }),
  38. HttpController.getFileTreeDiff
  39. )
  40. app.get(
  41. '/project/:project_id/updates',
  42. validate({
  43. query: {
  44. before: Joi.number().integer(),
  45. min_count: Joi.number().integer(),
  46. },
  47. }),
  48. HttpController.getUpdates
  49. )
  50. app.get('/project/:project_id/version', HttpController.latestVersion)
  51. app.post(
  52. '/project/:project_id/flush',
  53. validate({
  54. query: {
  55. debug: Joi.boolean().default(false),
  56. bisect: Joi.boolean().default(false),
  57. },
  58. }),
  59. HttpController.flushProject
  60. )
  61. app.post(
  62. '/project/:project_id/resync',
  63. validate({
  64. query: {
  65. force: Joi.boolean().default(false),
  66. },
  67. body: {
  68. force: Joi.boolean().default(false),
  69. origin: Joi.object({
  70. kind: Joi.string().required(),
  71. }),
  72. historyRangesMigration: Joi.string()
  73. .optional()
  74. .valid('forwards', 'backwards'),
  75. },
  76. }),
  77. HttpController.resyncProject
  78. )
  79. app.get(
  80. '/project/:project_id/dump',
  81. validate({
  82. query: {
  83. count: Joi.number().integer(),
  84. },
  85. }),
  86. HttpController.dumpProject
  87. )
  88. app.get('/project/:project_id/labels', HttpController.getLabels)
  89. app.post(
  90. '/project/:project_id/user/:user_id/labels',
  91. validate({
  92. body: {
  93. version: Joi.number().integer().required(),
  94. comment: Joi.string().required(),
  95. created_at: Joi.string(),
  96. validate_exists: Joi.boolean().default(true),
  97. },
  98. }),
  99. HttpController.createLabel
  100. )
  101. app.delete(
  102. '/project/:project_id/user/:user_id/labels/:label_id',
  103. validate({
  104. params: Joi.object({
  105. project_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  106. user_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  107. label_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  108. }),
  109. }),
  110. HttpController.deleteLabelForUser
  111. )
  112. app.delete(
  113. '/project/:project_id/labels/:label_id',
  114. validate({
  115. params: Joi.object({
  116. project_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  117. label_id: Joi.string().regex(/^[0-9a-f]{24}$/),
  118. }),
  119. }),
  120. HttpController.deleteLabel
  121. )
  122. app.post(
  123. '/user/:from_user/labels/transfer/:to_user',
  124. HttpController.transferLabels
  125. )
  126. app.get(
  127. '/project/:project_id/version/:version/:pathname',
  128. HttpController.getFileSnapshot
  129. )
  130. app.get(
  131. '/project/:project_id/ranges/version/:version/:pathname',
  132. HttpController.getRangesSnapshot
  133. )
  134. app.get(
  135. '/project/:project_id/version/:version',
  136. HttpController.getProjectSnapshot
  137. )
  138. app.get(
  139. '/project/:project_id/paths/version/:version',
  140. HttpController.getPathsAtVersion
  141. )
  142. app.post(
  143. '/project/:project_id/force',
  144. validate({
  145. query: {
  146. clear: Joi.boolean().default(false),
  147. },
  148. }),
  149. HttpController.forceDebugProject
  150. )
  151. app.get('/project/:project_id/blob/:hash', HttpController.getProjectBlob)
  152. app.get('/status/failures', HttpController.getFailures)
  153. app.get('/status/queue', HttpController.getQueueCounts)
  154. app.post(
  155. '/retry/failures',
  156. validate({
  157. query: {
  158. failureType: Joi.string().valid('soft', 'hard'),
  159. // bail out after this time limit
  160. timeout: Joi.number().integer().default(300),
  161. // maximum number of projects to check
  162. limit: Joi.number().integer().default(100),
  163. callbackUrl: Joi.string(),
  164. },
  165. }),
  166. HttpController.retryFailures
  167. )
  168. app.post(
  169. '/flush/old',
  170. validate({
  171. query: {
  172. // flush projects with queued ops older than this
  173. maxAge: Joi.number()
  174. .integer()
  175. .default(6 * 3600),
  176. // pause this amount of time between checking queues
  177. queueDelay: Joi.number().integer().default(100),
  178. // maximum number of queues to check
  179. limit: Joi.number().integer().default(1000),
  180. // maximum amount of time allowed
  181. timeout: Joi.number()
  182. .integer()
  183. .default(60 * 1000),
  184. // whether to run in the background
  185. background: Joi.boolean().falsy('0').truthy('1').default(false),
  186. },
  187. }),
  188. HttpController.flushOld
  189. )
  190. app.get('/status', (req, res, next) => res.send('project-history is up'))
  191. app.get('/oops', function (req, res, next) {
  192. throw new OError('dummy test error')
  193. })
  194. app.get('/check_lock', HttpController.checkLock)
  195. app.get('/health_check', HttpController.healthCheck)
  196. }
  197. function longerTimeout(req, res, next) {
  198. res.setTimeout(6 * 60 * 1000)
  199. next()
  200. }