Files
overleaf-cep/services/web/scripts/delete_dangling_comments.mjs
Anna Claire Fields 6113c6c291 Enable TS noImplicitAny in web (#31636)
GitOrigin-RevId: 18881694770f2476c475f8fef4c6a2678a2a12fe
2026-03-27 09:05:30 +00:00

98 lines
2.6 KiB
JavaScript

// @ts-check
import minimist from 'minimist'
import ChatApiHandler from '../app/src/Features/Chat/ChatApiHandler.mjs'
import DocumentUpdaterHandler from '../app/src/Features/DocumentUpdater/DocumentUpdaterHandler.mjs'
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.mjs'
import HistoryManager from '../app/src/Features/History/HistoryManager.mjs'
import { db, ObjectId } from '../app/src/infrastructure/mongodb.mjs'
const OPTS = parseArgs()
function usage() {
console.error(
'Usage: node delete_dangling_comments.mjs [--commit] PROJECT_ID...'
)
}
function parseArgs() {
const args = minimist(process.argv.slice(2), {
boolean: ['commit'],
})
if (args._.length === 0) {
usage()
process.exit(0)
}
return {
projectIds: args._,
commit: args.commit,
}
}
/**
* @param {any} projectId
*/
async function processProject(projectId) {
console.log(`Processing project ${projectId}...`)
await DocumentUpdaterHandler.promises.flushProjectToMongoAndDelete(projectId)
const docRanges = await DocstoreManager.promises.getAllRanges(projectId)
const threads = await ChatApiHandler.promises.getThreads(projectId)
const threadIds = new Set(Object.keys(threads))
let commentsDeleted = 0
for (const doc of docRanges) {
const commentsDeletedInDoc = await processDoc(projectId, doc, threadIds)
commentsDeleted += commentsDeletedInDoc
}
if (OPTS.commit) {
console.log(`${commentsDeleted} comments deleted`)
if (commentsDeleted > 0) {
console.log(`Resyncing history for project ${projectId}`)
await HistoryManager.promises.resyncProject(projectId)
}
}
}
/**
* @param {any} projectId
* @param {any} doc
* @param {any} threadIds
*/
async function processDoc(projectId, doc, threadIds) {
let commentsDeleted = 0
for (const comment of doc.ranges?.comments ?? []) {
const threadId = comment.op.t
if (!threadIds.has(threadId)) {
if (OPTS.commit) {
console.log(`Deleting dangling comment ${comment.op.t}...`)
await deleteComment(doc._id, threadId)
commentsDeleted += 1
} else {
console.log(`Would delete dangling comment ${comment.op.t}...`)
}
}
}
return commentsDeleted
}
/**
* @param {any} docId
* @param {any} threadId
*/
async function deleteComment(docId, threadId) {
await db.docs.updateOne(
{ _id: new ObjectId(docId) },
{
$pull: { 'ranges.comments': { 'op.t': new ObjectId(threadId) } },
}
)
}
// Main loop
for (const projectId of OPTS.projectIds) {
await processProject(projectId)
}
if (!OPTS.commit) {
console.log('This was a dry run. Rerun with --commit to apply changes')
}
process.exit(0)