diff --git a/services/web/scripts/convert_track_changes_to_explicit_format.mjs b/services/web/scripts/convert_track_changes_to_explicit_format.mjs new file mode 100644 index 0000000000..182ebdafa7 --- /dev/null +++ b/services/web/scripts/convert_track_changes_to_explicit_format.mjs @@ -0,0 +1,88 @@ +// @ts-check +import { db } from '../app/src/infrastructure/mongodb.js' +import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js' +import { scriptRunner } from './lib/ScriptRunner.mjs' +import CollaboratorsHandler from '../app/src/Features/Collaborators/CollaboratorsHandler.js' + +const DRY_RUN = !process.argv.includes('--dry-run=false') +const DEBUG = process.argv.includes('--debug=true') + +// Deployment procedure: +// Run it locally (not dry run) +// Run it on staging (dry run then real and then real). Maybe leave it a few days but might not get good feedback +// Run on prod on a small number of projects to start with, then on all projects (using BATCH_RANGE_START and BATCH_RANGE_END env vars) +// Are there race conditions here? If someone is editing in parallel. Is it worth doing atomic queries? + +/** + * @typedef {Object} Project + * @property {any} _id + * @property {Object} track_changes + */ + +/** + * @param {(progress: string) => Promise} trackProgress + * @returns {Promise} + * @async + */ +async function main(trackProgress) { + let projectsProcessed = 0 + await batchedUpdate( + db.projects, + {}, + /** + * @param {Array} projects + * @return {Promise} + */ + async function projects(projects) { + for (const project of projects) { + projectsProcessed += 1 + if (projectsProcessed % 100000 === 0) { + console.log(projectsProcessed, 'projects processed') + } + await processProject(project) + } + }, + { _id: 1, track_changes: 1 }, + undefined, + { trackProgress } + ) +} + +async function processProject(project) { + if (DEBUG) { + console.log( + `Processing project ${project._id} with track_changes: ${JSON.stringify( + project.track_changes + )}` + ) + } + + const newTrackChangesState = + await CollaboratorsHandler.promises.convertTrackChangesToExplicitFormat( + project._id, + project.track_changes + ) + + if (DEBUG) { + console.log( + `Processed project ${project._id} to have new track_changes: ${JSON.stringify( + newTrackChangesState + )}` + ) + } + + if (!DRY_RUN) { + await db.projects.updateOne( + { _id: project._id }, + { $set: { track_changes: newTrackChangesState } } + ) + } +} + +try { + await scriptRunner(main) + process.exit(0) +} catch (error) { + console.error(error) + process.exit(1) +}