delete_dangling_comments.mjs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // @ts-check
  2. import minimist from 'minimist'
  3. import ChatApiHandler from '../app/src/Features/Chat/ChatApiHandler.js'
  4. import DocumentUpdaterHandler from '../app/src/Features/DocumentUpdater/DocumentUpdaterHandler.js'
  5. import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
  6. import HistoryManager from '../app/src/Features/History/HistoryManager.js'
  7. import { db, ObjectId } from '../app/src/infrastructure/mongodb.js'
  8. const OPTS = parseArgs()
  9. function usage() {
  10. console.error(
  11. 'Usage: node delete_dangling_comments.mjs [--commit] PROJECT_ID...'
  12. )
  13. }
  14. function parseArgs() {
  15. const args = minimist(process.argv.slice(2), {
  16. boolean: ['commit'],
  17. })
  18. if (args._.length === 0) {
  19. usage()
  20. process.exit(0)
  21. }
  22. return {
  23. projectIds: args._,
  24. commit: args.commit,
  25. }
  26. }
  27. async function processProject(projectId) {
  28. console.log(`Processing project ${projectId}...`)
  29. await DocumentUpdaterHandler.promises.flushProjectToMongoAndDelete(projectId)
  30. const docRanges = await DocstoreManager.promises.getAllRanges(projectId)
  31. const threads = await ChatApiHandler.promises.getThreads(projectId)
  32. const threadIds = new Set(Object.keys(threads))
  33. let commentsDeleted = 0
  34. for (const doc of docRanges) {
  35. const commentsDeletedInDoc = await processDoc(projectId, doc, threadIds)
  36. commentsDeleted += commentsDeletedInDoc
  37. }
  38. if (OPTS.commit) {
  39. console.log(`${commentsDeleted} comments deleted`)
  40. if (commentsDeleted > 0) {
  41. console.log(`Resyncing history for project ${projectId}`)
  42. await HistoryManager.promises.resyncProject(projectId)
  43. }
  44. }
  45. }
  46. async function processDoc(projectId, doc, threadIds) {
  47. let commentsDeleted = 0
  48. for (const comment of doc.ranges?.comments ?? []) {
  49. const threadId = comment.op.t
  50. if (!threadIds.has(threadId)) {
  51. if (OPTS.commit) {
  52. console.log(`Deleting dangling comment ${comment.op.t}...`)
  53. await deleteComment(doc._id, threadId)
  54. commentsDeleted += 1
  55. } else {
  56. console.log(`Would delete dangling comment ${comment.op.t}...`)
  57. }
  58. }
  59. }
  60. return commentsDeleted
  61. }
  62. async function deleteComment(docId, threadId) {
  63. await db.docs.updateOne(
  64. { _id: new ObjectId(docId) },
  65. {
  66. $pull: { 'ranges.comments': { 'op.t': new ObjectId(threadId) } },
  67. }
  68. )
  69. }
  70. // Main loop
  71. for (const projectId of OPTS.projectIds) {
  72. await processProject(projectId)
  73. }
  74. if (!OPTS.commit) {
  75. console.log('This was a dry run. Rerun with --commit to apply changes')
  76. }
  77. process.exit(0)