overleaf/services/web/scripts/history/unset_allow_downgrade.js
Eric Mc Sween cff54eae78 Merge pull request #12575 from overleaf/em-fix-chunk-replace-transaction
Fix history chunk replacement transaction

GitOrigin-RevId: fc0fa8f4a55ae5f402ba87db5e4ac2856fe6627b
2023-04-19 08:03:10 +00:00

133 lines
3.7 KiB
JavaScript

const { promisify } = require('util')
const { ObjectId } = require('mongodb')
const {
db,
waitForDb,
READ_PREFERENCE_SECONDARY,
} = require('../../app/src/infrastructure/mongodb')
const sleep = promisify(setTimeout)
const _ = require('lodash')
const NOW_IN_S = Date.now() / 1000
const ONE_WEEK_IN_S = 60 * 60 * 24 * 7
const TEN_SECONDS = 10 * 1000
function getSecondsFromObjectId(id) {
return id.getTimestamp().getTime() / 1000
}
async function main(options) {
if (!options) {
options = {}
}
_.defaults(options, {
projectId: process.env.PROJECT_ID,
dryRun: process.env.DRY_RUN !== 'false',
verboseLogging: process.env.VERBOSE_LOGGING === 'true',
firstProjectId: process.env.FIRST_PROJECT_ID
? ObjectId(process.env.FIRST_PROJECT_ID)
: ObjectId('4b3d3b3d0000000000000000'), // timestamped to 2010-01-01T00:01:01.000Z
incrementByS: parseInt(process.env.INCREMENT_BY_S, 10) || ONE_WEEK_IN_S,
batchSize: parseInt(process.env.BATCH_SIZE, 10) || 1000,
stopAtS: parseInt(process.env.STOP_AT_S, 10) || NOW_IN_S,
letUserDoubleCheckInputsFor:
parseInt(process.env.LET_USER_DOUBLE_CHECK_INPUTS_FOR, 10) || TEN_SECONDS,
})
if (options.projectId) {
await waitForDb()
const { modifiedCount } = await db.projects.updateOne(
{
_id: ObjectId(options.projectId),
'overleaf.history.allowDowngrade': true,
},
{ $unset: { 'overleaf.history.allowDowngrade': 1 } }
)
console.log(`modifiedCount: ${modifiedCount}`)
process.exit(0)
}
await letUserDoubleCheckInputs(options)
await waitForDb()
let startId = options.firstProjectId
let totalProcessed = 0
while (getSecondsFromObjectId(startId) <= options.stopAtS) {
let batchProcessed = 0
const end = getSecondsFromObjectId(startId) + options.incrementByS
let endId = ObjectId.createFromTime(end)
const query = {
_id: {
// include edge
$gte: startId,
// exclude edge
$lt: endId,
},
'overleaf.history.allowDowngrade': true,
}
const projects = await db.projects
.find(query, { readPreference: READ_PREFERENCE_SECONDARY })
.project({ _id: 1 })
.limit(options.batchSize)
.toArray()
if (projects.length) {
const projectIds = projects.map(project => project._id)
if (options.verboseLogging) {
console.log(
`Processing projects with ids: ${JSON.stringify(projectIds)}`
)
} else {
console.log(`Processing ${projects.length} projects`)
}
if (!options.dryRun) {
await db.projects.updateMany(
{ _id: { $in: projectIds } },
{ $unset: { 'overleaf.history.allowDowngrade': 1 } }
)
} else {
console.log(
`skipping update of ${projectIds.length} projects in dry-run mode`
)
}
totalProcessed += projectIds.length
batchProcessed += projectIds.length
if (projects.length === options.batchSize) {
endId = projects[projects.length - 1]._id
}
}
console.error(
`Processed ${batchProcessed} from ${startId} until ${endId} (${totalProcessed} processed in total)`
)
startId = endId
}
}
async function letUserDoubleCheckInputs(options) {
console.error('Options:', JSON.stringify(options, null, 2))
console.error(
'Waiting for you to double check inputs for',
options.letUserDoubleCheckInputsFor,
'ms'
)
await sleep(options.letUserDoubleCheckInputsFor)
}
module.exports = main
if (require.main === module) {
main()
.then(() => {
console.error('Done.')
process.exit(0)
})
.catch(error => {
console.error({ error })
process.exit(1)
})
}