ProjectHistoryHandler.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. const { Project } = require('../../models/Project')
  2. const ProjectDetailsHandler = require('./ProjectDetailsHandler')
  3. const HistoryManager = require('../History/HistoryManager')
  4. const ProjectEntityUpdateHandler = require('./ProjectEntityUpdateHandler')
  5. const { promisifyAll } = require('../../util/promises')
  6. const ProjectHistoryHandler = {
  7. setHistoryId(projectId, historyId, callback) {
  8. // reject invalid history ids
  9. if (historyId == null) {
  10. return callback(new Error('missing history id'))
  11. }
  12. // use $exists:false to prevent overwriting any existing history id, atomically
  13. Project.updateOne(
  14. { _id: projectId, 'overleaf.history.id': { $exists: false } },
  15. { 'overleaf.history.id': historyId },
  16. function (err, result) {
  17. if (err) {
  18. return callback(err)
  19. }
  20. if (result.n === 0) {
  21. return callback(new Error('history exists'))
  22. }
  23. callback()
  24. }
  25. )
  26. },
  27. getHistoryId(projectId, callback) {
  28. ProjectDetailsHandler.getDetails(projectId, function (err, project) {
  29. if (err) {
  30. return callback(err)
  31. } // n.b. getDetails returns an error if the project doesn't exist
  32. callback(null, project?.overleaf?.history?.id)
  33. })
  34. },
  35. unsetHistory(projectId, callback) {
  36. Project.updateOne(
  37. { _id: projectId },
  38. { $unset: { 'overleaf.history': true } },
  39. callback
  40. )
  41. },
  42. upgradeHistory(projectId, allowDowngrade, callback) {
  43. // project must have an overleaf.history.id before allowing display of new history
  44. Project.updateOne(
  45. { _id: projectId, 'overleaf.history.id': { $exists: true } },
  46. {
  47. 'overleaf.history.display': true,
  48. 'overleaf.history.upgradedAt': new Date(),
  49. 'overleaf.history.allowDowngrade': allowDowngrade,
  50. },
  51. function (err, result) {
  52. if (err) {
  53. return callback(err)
  54. }
  55. // return an error if overleaf.history.id wasn't present
  56. if (result.n === 0) {
  57. return callback(new Error('history not upgraded'))
  58. }
  59. callback()
  60. }
  61. )
  62. },
  63. downgradeHistory(projectId, callback) {
  64. Project.updateOne(
  65. { _id: projectId, 'overleaf.history.upgradedAt': { $exists: true } },
  66. {
  67. 'overleaf.history.display': false,
  68. $unset: { 'overleaf.history.upgradedAt': 1 },
  69. },
  70. function (err, result) {
  71. if (err) {
  72. return callback(err)
  73. }
  74. if (result.n === 0) {
  75. return callback(new Error('history not downgraded'))
  76. }
  77. callback()
  78. }
  79. )
  80. },
  81. setMigrationArchiveFlag(projectId, callback) {
  82. Project.updateOne(
  83. { _id: projectId, version: { $exists: true } },
  84. {
  85. 'overleaf.history.zipFileArchivedInProject': true,
  86. },
  87. function (err, result) {
  88. if (err) {
  89. return callback(err)
  90. }
  91. if (result.n === 0) {
  92. return callback(new Error('migration flag not set'))
  93. }
  94. callback()
  95. }
  96. )
  97. },
  98. ensureHistoryExistsForProject(projectId, callback) {
  99. // We can only set a history id for a project that doesn't have one. The
  100. // history id is cached in the project history service, and changing an
  101. // existing value corrupts the history, leaving it in an irrecoverable
  102. // state. Setting a history id when one wasn't present before is ok,
  103. // because undefined history ids aren't cached.
  104. ProjectHistoryHandler.getHistoryId(projectId, function (err, historyId) {
  105. if (err) {
  106. return callback(err)
  107. }
  108. if (historyId != null) {
  109. return callback()
  110. } // history already exists, success
  111. HistoryManager.initializeProject(projectId, function (err, historyId) {
  112. if (err) {
  113. return callback(err)
  114. }
  115. if (historyId == null) {
  116. return callback(new Error('failed to initialize history id'))
  117. }
  118. ProjectHistoryHandler.setHistoryId(
  119. projectId,
  120. historyId,
  121. function (err) {
  122. if (err) {
  123. return callback(err)
  124. }
  125. ProjectEntityUpdateHandler.resyncProjectHistory(
  126. projectId,
  127. function (err) {
  128. if (err) {
  129. return callback(err)
  130. }
  131. HistoryManager.flushProject(projectId, callback)
  132. }
  133. )
  134. }
  135. )
  136. })
  137. })
  138. },
  139. }
  140. ProjectHistoryHandler.promises = promisifyAll(ProjectHistoryHandler)
  141. module.exports = ProjectHistoryHandler