Merge pull request #24790 from overleaf/ls-use-script-runner

Update some scripts to use Script Runner

GitOrigin-RevId: aaa11f94dcfd328c158bb02d1b9fb2adfb1bb146
This commit is contained in:
Liangjun Song
2025-05-22 11:51:53 +01:00
committed by Copybot
parent a2cf685a84
commit 385523bcdc
62 changed files with 225 additions and 112 deletions

View File

@@ -35,6 +35,7 @@ let BATCHED_UPDATE_RUNNING = false
* @property {string} [BATCH_RANGE_START]
* @property {string} [BATCH_SIZE]
* @property {string} [VERBOSE_LOGGING]
* @property {(progress: string) => Promise<void>} [trackProgress]
*/
/**
@@ -210,7 +211,7 @@ async function batchedUpdate(
update,
projection,
findOptions,
batchedUpdateOptions
batchedUpdateOptions = {}
) {
// only a single batchedUpdate can run at a time due to global variables
if (BATCHED_UPDATE_RUNNING) {
@@ -226,6 +227,8 @@ async function batchedUpdate(
return 0
}
refreshGlobalOptionsForBatchedUpdate(batchedUpdateOptions)
const { trackProgress = async progress => console.warn(progress) } =
batchedUpdateOptions
findOptions = findOptions || {}
findOptions.readPreference = READ_PREFERENCE_SECONDARY
@@ -255,9 +258,10 @@ async function batchedUpdate(
nextBatch.map(entry => entry._id)
)}`
)
} else {
console.error(`Running update on batch ending ${renderObjectId(end)}`)
}
await trackProgress(
`Running update on batch ending ${renderObjectId(end)}`
)
if (typeof update === 'function') {
await update(nextBatch)
@@ -265,7 +269,7 @@ async function batchedUpdate(
await performUpdate(collection, nextBatch, update)
}
}
console.error(`Completed batch ending ${renderObjectId(end)}`)
await trackProgress(`Completed batch ending ${renderObjectId(end)}`)
start = end
}
return updated

View File

@@ -4,6 +4,7 @@ import { parse } from 'csv'
import Stream from 'node:stream/promises'
import { ObjectId } from '../app/src/infrastructure/mongodb.js'
import { Subscription } from '../app/src/models/Subscription.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
function usage() {
console.log(
@@ -76,20 +77,22 @@ const stats = {
},
}
function showStats() {
console.log('Stats:')
console.log(` Total rows: ${stats.totalRows}`)
console.log(` Processed rows: ${stats.processedRows}`)
console.log(` Skipped (no subscription ID): ${stats.subscriptionIDMissing}`)
console.log(` Used V1 ID: ${stats.usedV1ID}`)
console.log(` Used Salesforce ID: ${stats.usedSalesforceID}`)
if (commit) {
console.log('Database operations:')
console.log(` Errors: ${stats.db.errors}`)
console.log(` Matched: ${stats.db.matched}`)
console.log(` Updated: ${stats.db.updated}`)
console.log(` Update attempted: ${stats.db.updateAttempted}`)
}
function generateStats() {
return `Stats:
Total rows: ${stats.totalRows}
Processed rows: ${stats.processedRows}
Skipped (no subscription ID): ${stats.subscriptionIDMissing}
Used V1 ID: ${stats.usedV1ID}
Used Salesforce ID: ${stats.usedSalesforceID}${
commit
? `
Database operations:
Errors: ${stats.db.errors}
Matched: ${stats.db.matched}
Updated: ${stats.db.updated}
Update attempted: ${stats.db.updateAttempted}`
: ''
}`
}
function pickRelevantColumns(row) {
@@ -161,7 +164,7 @@ async function processRows(rows) {
}
}
async function main() {
async function main(trackProgress) {
await Stream.pipeline(
fs.createReadStream(filename),
parse({
@@ -191,6 +194,7 @@ async function main() {
}),
processRows
)
await trackProgress(generateStats())
}
if (!commit) {
@@ -199,6 +203,5 @@ if (!commit) {
console.log('Committing changes to the database')
}
await main()
showStats()
await scriptRunner(main)
process.exit()

View File

@@ -9,6 +9,7 @@ import minimist from 'minimist'
import UserGetter from '../app/src/Features/User/UserGetter.js'
import { db } from '../app/src/infrastructure/mongodb.js'
import _ from 'lodash'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const argv = minimist(process.argv.slice(2), {
string: ['domain', 'output'],
@@ -86,7 +87,7 @@ async function getUsersByHostnameWithSubdomain(domain, projection) {
}
try {
await main()
await scriptRunner(main)
console.log('Done')
process.exit(0)
} catch (error) {

View File

@@ -19,6 +19,7 @@ import AccountMappingHelper from '../../app/src/Features/Analytics/AccountMappin
import { registerAccountMapping } from '../../app/src/Features/Analytics/AnalyticsManager.js'
import { triggerGracefulShutdown } from '../../app/src/infrastructure/GracefulShutdown.js'
import Validation from '../../app/src/infrastructure/Validation.js'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const paramsSchema = Validation.Joi.object({
endDate: Validation.Joi.string().isoDate(),
@@ -59,7 +60,7 @@ function registerMapping(subscription) {
}
}
async function main() {
async function main(trackProgress) {
const additionalBatchedUpdateOptions = {}
if (endDate) {
@@ -83,6 +84,7 @@ async function main() {
{
verboseLogging: verbose,
...additionalBatchedUpdateOptions,
trackProgress,
}
)
@@ -109,7 +111,7 @@ if (error) {
triggerGracefulShutdown(done => done(1))
} else {
logger.info({ verbose, commit, endDate }, commit ? 'COMMITTING' : 'DRY RUN')
await main()
await scriptRunner(main)
triggerGracefulShutdown({
close(done) {

View File

@@ -5,6 +5,7 @@ import { DeletedSubscription } from '../../app/src/models/DeletedSubscription.js
import minimist from 'minimist'
import _ from 'lodash'
import mongodb from 'mongodb-legacy'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
@@ -272,7 +273,7 @@ const setup = () => {
setup()
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -3,10 +3,11 @@ import { promiseMapWithLimit, promisify } from '@overleaf/promise-utils'
import { db } from '../app/src/infrastructure/mongodb.js'
import { fileURLToPath } from 'node:url'
import _ from 'lodash'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const sleep = promisify(setTimeout)
async function main(options) {
async function main(options, trackProgress) {
if (!options) {
options = {}
}
@@ -28,7 +29,9 @@ async function main(options) {
async projects => {
await processBatch(projects, options)
},
{ _id: 1, deletedDocs: 1 }
{ _id: 1, deletedDocs: 1 },
undefined,
{ trackProgress }
)
}
@@ -83,7 +86,9 @@ export default main
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(
async trackProgress => await main(undefined, trackProgress)
)
process.exit(0)
} catch (error) {
console.error({ error })

View File

@@ -7,6 +7,7 @@ import {
import _ from 'lodash'
import LRUCache from 'lru-cache'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
const sleep = promisify(setTimeout)
@@ -151,7 +152,7 @@ export default main
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(async () => await main())
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -3,6 +3,7 @@ import {
READ_PREFERENCE_SECONDARY,
} from '../app/src/infrastructure/mongodb.js'
import UserSessionsManager from '../app/src/Features/User/UserSessionsManager.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const COMMIT = process.argv.includes('--commit')
const KEEP_SESSIONS = process.argv.includes('--keep-sessions')
@@ -84,7 +85,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,6 +1,7 @@
import NotificationsBuilder from '../app/src/Features/Notifications/NotificationsBuilder.js'
import { db } from '../app/src/infrastructure/mongodb.js'
import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const DRY_RUN = !process.argv.includes('--dry-run=false')
@@ -55,14 +56,23 @@ async function processBatch(groupSubscriptionsBatch) {
}
}
async function main() {
await batchedUpdate(db.subscriptions, { groupPlan: true }, processBatch, {
member_ids: 1,
})
async function main(trackProgress) {
await batchedUpdate(
db.subscriptions,
{ groupPlan: true },
processBatch,
{
member_ids: 1,
},
undefined,
{
trackProgress,
}
)
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -9,6 +9,7 @@ import {
} from '../app/src/infrastructure/mongodb.js'
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
import { NotFoundError } from '../app/src/Features/Errors/Errors.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const OPTS = parseArgs()
@@ -213,7 +214,7 @@ function docsHaveTrackedChanges(docs) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (err) {
console.error(err)

View File

@@ -1,5 +1,6 @@
import InstitutionsManager from '../app/src/Features/Institutions/InstitutionsManager.js'
import { ensureRunningOnMongoSecondaryWithTimeout } from './helpers/env_variable_helper.mjs'
import { scriptRunner } from './lib/ScriptRunner.mjs'
ensureRunningOnMongoSecondaryWithTimeout(300000)
@@ -18,7 +19,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -3,6 +3,7 @@ import {
READ_PREFERENCE_SECONDARY,
} from '../app/src/infrastructure/mongodb.js'
import UserSessionsManager from '../app/src/Features/User/UserSessionsManager.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const COMMIT = process.argv.includes('--commit')
const LOG_SESSIONS = !process.argv.includes('--log-sessions=false')
@@ -58,7 +59,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,6 +1,7 @@
import { promisify } from 'node:util'
import InstitutionsManager from '../app/src/Features/Institutions/InstitutionsManager.js'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const sleep = promisify(setTimeout)
async function main() {
@@ -39,7 +40,7 @@ async function main() {
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
console.log('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,4 +1,5 @@
import ProjectDetailsHandler from '../app/src/Features/Project/ProjectDetailsHandler.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const projectId = process.argv[2]
if (!/^(?=[a-f\d]{24}$)(\d+[a-f]|[a-f]+\d)/.test(projectId)) {
@@ -21,7 +22,7 @@ function main() {
}
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -1,6 +1,7 @@
import { promisify, promiseMapWithLimit } from '@overleaf/promise-utils'
import UserSessionsRedis from '../app/src/Features/User/UserSessionsRedis.js'
import minimist from 'minimist'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const rClient = UserSessionsRedis.client()
@@ -76,7 +77,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -2,6 +2,7 @@ import minimist from 'minimist'
import { ObjectId } from '../app/src/infrastructure/mongodb.js'
import ProjectEntityUpdateHandler from '../app/src/Features/Project/ProjectEntityUpdateHandler.js'
import Errors from '../app/src/Features/Errors/Errors.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
async function main() {
const argv = minimist(process.argv.slice(2))
@@ -35,7 +36,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.log('Done.')
process.exit(0)
} catch (error) {

View File

@@ -5,6 +5,7 @@ import {
import _ from 'lodash'
import { formatTokenUsageStats } from '@overleaf/access-token-encryptor/scripts/helpers/format-usage-stats.js'
import { ensureMongoTimeout } from './helpers/env_variable_helper.mjs'
import { scriptRunner } from './lib/ScriptRunner.mjs'
if (!process.env.MONGO_SOCKET_TIMEOUT) {
const TEN_MINUTES = 1000 * 60 * 10
@@ -65,7 +66,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -3,6 +3,7 @@ import {
READ_PREFERENCE_SECONDARY,
} from '../app/src/infrastructure/mongodb.js'
import { extname } from 'node:path'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const FILE_TYPES = [
'.jpg',
@@ -71,7 +72,7 @@ function countFiles(folder, result) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -10,6 +10,7 @@ import Errors from '../app/src/Features/Errors/Errors.js'
import FileStoreHandler from '../app/src/Features/FileStore/FileStoreHandler.js'
import ProjectEntityMongoUpdateHandler from '../app/src/Features/Project/ProjectEntityMongoUpdateHandler.js'
import { iterablePaths } from '../app/src/Features/Project/IterablePath.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
@@ -123,7 +124,7 @@ async function deleteFile(projectId, fileId) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error({ error })

View File

@@ -3,6 +3,7 @@ import ChatApiHandler from '../app/src/Features/Chat/ChatApiHandler.js'
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
import DocumentUpdaterHandler from '../app/src/Features/DocumentUpdater/DocumentUpdaterHandler.js'
import { promiseMapWithLimit } from '@overleaf/promise-utils'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY, 10) || 10
@@ -43,7 +44,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.log('Done.')
process.exit(0)
} catch (error) {

View File

@@ -8,6 +8,7 @@ import {
} from '../app/src/infrastructure/mongodb.js'
import { promiseMapWithLimit } from '@overleaf/promise-utils'
import DeleteOrphanedDataHelper from './delete_orphaned_data_helper.mjs'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
const sleep = promisify(setTimeout)
@@ -170,7 +171,7 @@ async function letUserDoubleCheckInputs() {
}
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -3,6 +3,7 @@ import Settings from '@overleaf/settings'
import AdminController from '../app/src/Features/ServerAdmin/AdminController.js'
import minimist from 'minimist'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const args = minimist(process.argv.slice(2), {
string: ['confirm-site-url', 'delay-in-seconds'],
@@ -60,7 +61,7 @@ async function main() {
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -9,6 +9,7 @@ import ProjectDeleter from '../app/src/Features/Project/ProjectDeleter.js'
import SplitTestManager from '../app/src/Features/SplitTests/SplitTestManager.js'
import UserDeleter from '../app/src/Features/User/UserDeleter.js'
import UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const MONOREPO = Path.dirname(
Path.dirname(Path.dirname(Path.dirname(fileURLToPath(import.meta.url))))
@@ -158,7 +159,7 @@ async function main() {
await provisionSplitTests()
}
await main()
await scriptRunner(main)
await GracefulShutdown.gracefulShutdown(
{
close(cb) {

View File

@@ -1,6 +1,7 @@
// @ts-check
import { db, ObjectId } from '../app/src/infrastructure/mongodb.js'
import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
/**
* @typedef {Object} Doc
@@ -30,7 +31,12 @@ import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
* @property {Array<Folder>} rootFolder
*/
async function main() {
/**
* @param {(progress: string) => Promise<void>} trackProgress
* @returns {Promise<void>}
* @async
*/
async function main(trackProgress) {
let projectsProcessed = 0
await batchedUpdate(
db.projects,
@@ -59,7 +65,9 @@ async function main() {
}
}
},
{ _id: 1, rootFolder: 1 }
{ _id: 1, rootFolder: 1 },
undefined,
{ trackProgress }
)
}
@@ -161,7 +169,7 @@ function* findBadPaths(folder) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,5 +1,6 @@
import { db } from '../app/src/infrastructure/mongodb.js'
import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const DRY_RUN = process.env.DRY_RUN !== 'false'
@@ -44,7 +45,7 @@ async function processBatch(subscriptions) {
}
}
async function main() {
async function main(trackProgress) {
const projection = {
_id: 1,
teamInvites: 1,
@@ -54,11 +55,18 @@ async function main() {
$exists: true,
},
}
await batchedUpdate(db.subscriptions, query, processBatch, projection)
await batchedUpdate(
db.subscriptions,
query,
processBatch,
projection,
undefined,
{ trackProgress }
)
}
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -15,6 +15,7 @@ import minimist from 'minimist'
import readline from 'node:readline'
import fs from 'node:fs'
import logger from '@overleaf/logger'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
const lastUpdated = new Date()
@@ -287,7 +288,7 @@ function findUniqueName(existingFilenames) {
try {
try {
await main()
await scriptRunner(main)
} finally {
logStats()
}

View File

@@ -8,6 +8,7 @@ import ProjectEntityMongoUpdateHandler from '../app/src/Features/Project/Project
import ProjectLocator from '../app/src/Features/Project/ProjectLocator.js'
import RedisWrapper from '@overleaf/redis-wrapper'
import Settings from '@overleaf/settings'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const opts = parseArgs()
const redis = RedisWrapper.createClient(Settings.redis.web)
@@ -155,7 +156,7 @@ async function deleteDocFromRedis(projectId, docId) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,6 +1,7 @@
import mongodb from 'mongodb-legacy'
import { db } from '../app/src/infrastructure/mongodb.js'
import DocumentUpdaterHandler from '../app/src/Features/DocumentUpdater/DocumentUpdaterHandler.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
const PROJECT_ID = process.env.PROJECT_ID
@@ -67,7 +68,7 @@ function getDocument() {
}
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,5 +1,6 @@
import { db } from '../../app/src/infrastructure/mongodb.js'
import { ensureMongoTimeout } from '../helpers/env_variable_helper.mjs'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
// Ensure default mongo query timeout has been increased 1h
if (!process.env.MONGO_SOCKET_TIMEOUT) {
ensureMongoTimeout(360000)
@@ -66,7 +67,7 @@ async function gracefullyDropCollection(collection) {
}
try {
await main()
await scriptRunner(main)
} catch (err) {
console.error(err)
process.exit(1)

View File

@@ -1,5 +1,6 @@
import HistoryRangesSupportMigration from '../../app/src/Features/History/HistoryRangesSupportMigration.mjs'
import minimist from 'minimist'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
async function main() {
const {
@@ -111,7 +112,7 @@ function arrayOpt(value) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,6 +1,7 @@
import checkSanitizeOptions from './checkSanitizeOptions.mjs'
import Scrape from './scrape.mjs'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from '../../lib/ScriptRunner.mjs'
const { getAllPagesAndCache, scrapeAndCachePage } = Scrape
@@ -32,7 +33,7 @@ async function main() {
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,23 +1,28 @@
import { ScriptLog } from '../../app/src/models/ScriptLog.mjs'
import Settings from '@overleaf/settings'
const UNKNOWN = 'unknown'
async function beforeScriptExecution(canonicalName, vars, scriptPath) {
let log = new ScriptLog({
canonicalName,
filePathAtVersion: scriptPath,
podName: process.env.OL_POD_NAME,
username: process.env.OL_USERNAME,
imageVersion: process.env.OL_IMAGE_VERSION,
podName: process.env.OL_POD_NAME ?? UNKNOWN,
username: process.env.OL_USERNAME ?? UNKNOWN,
imageVersion: process.env.OL_IMAGE_VERSION ?? UNKNOWN,
vars,
})
log = await log.save()
console.log(
'\n==================================' +
'\n✨ Your script is running!' +
'\n📊 Track progress at:' +
`\n${Settings.adminUrl}/admin/script-log/${log._id}` +
'\n==================================\n'
)
// Print Script Log link if ran by a user
if (process.env.OL_USERNAME) {
console.log(
'\n==================================' +
'\n✨ Your script is running!' +
'\n📊 Track progress at:' +
`\n${Settings.adminUrl}/admin/script-log/${log._id}` +
'\n==================================\n'
)
}
return log._id
}

View File

@@ -2,6 +2,7 @@ import { db } from '../app/src/infrastructure/mongodb.js'
import minimist from 'minimist'
import UserGetter from '../app/src/Features/User/UserGetter.js'
import fs from 'node:fs'
import { scriptRunner } from './lib/ScriptRunner.mjs'
function usage() {
console.log(
@@ -112,7 +113,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -10,6 +10,7 @@ import { db, ObjectId } from '../app/src/infrastructure/mongodb.js'
import SubscriptionUpdater from '../app/src/Features/Subscription/SubscriptionUpdater.js'
import minimist from 'minimist'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const argv = minimist(process.argv.slice(2), {
string: ['target', 'source'],
boolean: ['commit'],
@@ -93,7 +94,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.error('Done.')
process.exit(0)
} catch (error) {

View File

@@ -3,10 +3,11 @@ import { promiseMapWithLimit, promisify } from '@overleaf/promise-utils'
import { db, ObjectId } from '../app/src/infrastructure/mongodb.js'
import _ from 'lodash'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const sleep = promisify(setTimeout)
async function main(options) {
async function main(options, trackProgress) {
if (!options) {
options = {}
}
@@ -54,7 +55,9 @@ async function main(options) {
async users => {
await processUsersBatch(users, options)
},
{ _id: 1, auditLog: 1 }
{ _id: 1, auditLog: 1 },
undefined,
{ trackProgress }
)
}
@@ -67,7 +70,9 @@ async function main(options) {
async projects => {
await processProjectsBatch(projects, options)
},
{ _id: 1, auditLog: 1 }
{ _id: 1, auditLog: 1 },
undefined,
{ trackProgress }
)
}
}
@@ -152,7 +157,9 @@ export default main
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(
async trackProgress => await main(undefined, trackProgress)
)
console.log('Done.')
process.exit(0)
} catch (error) {

View File

@@ -3,6 +3,7 @@ import {
READ_PREFERENCE_SECONDARY,
} from '../../app/src/infrastructure/mongodb.js'
import { hashSecret } from '../../modules/oauth2-server/app/src/SecretsHelper.js'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
async function main() {
console.log('Hashing client secrets...')
@@ -35,7 +36,7 @@ async function hashSecrets(collection, field) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,6 +1,7 @@
import minimist from 'minimist'
import { db } from '../../app/src/infrastructure/mongodb.js'
import { hashSecret } from '../../modules/oauth2-server/app/src/SecretsHelper.js'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
async function main() {
const opts = parseArgs()
@@ -88,7 +89,7 @@ Options:
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -2,6 +2,7 @@ import minimist from 'minimist'
import mongodb from 'mongodb-legacy'
import { db } from '../../app/src/infrastructure/mongodb.js'
import { hashSecret } from '../../modules/oauth2-server/app/src/SecretsHelper.js'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
@@ -142,7 +143,7 @@ function toArray(value) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -3,6 +3,7 @@ import {
db,
READ_PREFERENCE_SECONDARY,
} from '../../app/src/infrastructure/mongodb.js'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
async function main() {
const opts = parseArgs()
@@ -113,7 +114,7 @@ Options:
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -8,6 +8,7 @@ import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEnti
import RedisWrapper from '@overleaf/redis-wrapper'
import Settings from '@overleaf/settings'
import logger from '@overleaf/logger'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const opts = parseArgs()
const redis = RedisWrapper.createClient(Settings.redis.web)
@@ -173,7 +174,7 @@ async function deleteDocFromRedis(projectId, docId) {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -4,6 +4,7 @@ import * as csv from 'csv'
import minimist from 'minimist'
import recurly from 'recurly'
import Settings from '@overleaf/settings'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const recurlyClient = new recurly.Client(Settings.apis.recurly.apiKey)
@@ -223,7 +224,7 @@ class ReportError extends Error {
}
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -2,6 +2,7 @@ import RecurlyWrapper from '../../app/src/Features/Subscription/RecurlyWrapper.j
import minimist from 'minimist'
import logger from '@overleaf/logger'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const waitMs =
fileURLToPath(import.meta.url) === process.argv[1]
@@ -119,7 +120,7 @@ const main = async () => {
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
logger.info('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,6 +1,7 @@
// @ts-check
import settings from '@overleaf/settings'
import recurly from 'recurly'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const ADD_ON_CODE = process.argv[2]
@@ -54,4 +55,4 @@ async function getPlan(planCode) {
return await recurlyClient.getPlan(`code-${planCode}`)
}
await main()
await scriptRunner(main)

View File

@@ -5,6 +5,7 @@ import { setTimeout } from 'node:timers/promises'
import minimist from 'minimist'
import * as csv from 'csv'
import Stream from 'node:stream/promises'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const recurlyApiKey = Settings.apis.recurly.apiKey
if (!recurlyApiKey) {
@@ -95,7 +96,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -7,6 +7,7 @@
import recurly from 'recurly'
import Settings from '@overleaf/settings'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const recurlySettings = Settings.apis.recurly
const recurlyApiKey = recurlySettings ? recurlySettings.apiKey : undefined
@@ -39,7 +40,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error({ error })

View File

@@ -4,6 +4,7 @@ import fs from 'node:fs'
import minimist from 'minimist'
import * as csv from 'csv'
import { setTimeout } from 'node:timers/promises'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const recurlyApiKey = Settings.apis.recurly.apiKey
if (!recurlyApiKey) {
@@ -95,7 +96,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,5 +1,6 @@
import minimist from 'minimist'
import InstitutionsManager from '../app/src/Features/Institutions/InstitutionsManager.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const institutionId = parseInt(process.argv[2])
if (isNaN(institutionId)) throw new Error('No institution id')
@@ -31,7 +32,7 @@ function main() {
}
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -3,6 +3,7 @@ import {
READ_PREFERENCE_SECONDARY,
} from '../app/src/infrastructure/mongodb.js'
import parseArgs from 'minimist'
import { scriptRunner } from './lib/ScriptRunner.mjs'
async function _removeFeatureFromAllUsers(feature, commit) {
let removals = 0
@@ -44,7 +45,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.log('Done')
process.exit(0)
} catch (error) {

View File

@@ -1,6 +1,7 @@
import { OauthApplication } from '../app/src/models/OauthApplication.js'
import parseArgs from 'minimist'
import OError from '@overleaf/o-error'
import { scriptRunner } from './lib/ScriptRunner.mjs'
async function _removeOauthApplication(appId) {
if (!appId) {
@@ -24,7 +25,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.log('Done')
process.exit(0)
} catch (error) {

View File

@@ -8,6 +8,7 @@ import fs from 'node:fs/promises'
import * as csv from 'csv'
import { promisify } from 'node:util'
import _ from 'lodash'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const CSV_FILENAME = '/tmp/remove_unconfirmed_emails.csv'
/**
@@ -38,7 +39,7 @@ const { generate, consume, commit, help } = minimist(process.argv.slice(2), {
default: { generate: false, consume: false, commit: false },
})
async function generateCsvFile() {
async function generateCsvFile(trackProgress) {
console.time('generate_csv')
let processedUsersCount = 0
@@ -92,7 +93,9 @@ async function generateCsvFile() {
totalEmailsToRemove += unconfirmedSecondaries.length
}
},
{ _id: 1, signUpDate: 1, emails: 1, email: 1 }
{ _id: 1, signUpDate: 1, emails: 1, email: 1 },
undefined,
{ trackProgress }
)
const csvContent = await stringifyAsync(records)
@@ -226,7 +229,7 @@ async function consumeCsvFile() {
console.log()
}
async function main() {
async function main(trackProgress) {
if (help) {
return usage()
}
@@ -247,14 +250,14 @@ async function main() {
}
if (generate) {
await generateCsvFile()
await generateCsvFile(trackProgress)
} else if (consume) {
await consumeCsvFile()
}
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,6 +1,7 @@
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.js'
import ProjectEntityHandler from '../app/src/Features/Project/ProjectEntityHandler.js'
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const ARGV = process.argv.slice(2)
const DEVELOPER_USER_ID = ARGV.shift()
@@ -35,7 +36,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,5 +1,6 @@
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.js'
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const ARGV = process.argv.slice(2)
const DEVELOPER_USER_ID = ARGV.shift()
@@ -24,7 +25,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,6 +1,7 @@
import Settings from '@overleaf/settings'
import mongodb from 'mongodb-legacy'
import { Project } from '../app/src/models/Project.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
@@ -61,7 +62,7 @@ async function updateImage(image, projectIds) {
}
try {
await main()
await scriptRunner(main)
process.exit()
} catch (error) {
console.error(error)

View File

@@ -1,5 +1,6 @@
import minimist from 'minimist'
import ProjectDeleter from '../app/src/Features/Project/ProjectDeleter.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
async function main() {
const argv = minimist(process.argv.slice(2))
@@ -14,7 +15,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.log('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,5 +1,6 @@
import SAMLUserIdMigrationHandler from '../modules/saas-authentication/app/src/SAML/SAMLUserIdMigrationHandler.mjs'
import { ensureRunningOnMongoSecondaryWithTimeout } from './helpers/env_variable_helper.mjs'
import { scriptRunner } from './lib/ScriptRunner.mjs'
ensureRunningOnMongoSecondaryWithTimeout(300000)
@@ -10,7 +11,7 @@ const emitUsers = process.argv.includes('--emit-users')
console.log('Checking SSO user ID migration for institution:', institutionId)
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -1,5 +1,6 @@
import SAMLUserIdMigrationHandler from '../modules/saas-authentication/app/src/SAML/SAMLUserIdMigrationHandler.mjs'
import { ensureMongoTimeout } from './helpers/env_variable_helper.mjs'
import { scriptRunner } from './lib/ScriptRunner.mjs'
ensureMongoTimeout(300000)
@@ -30,7 +31,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
} catch (error) {
console.error(error)
process.exit(1)

View File

@@ -1,5 +1,6 @@
import minimist from 'minimist'
import ProjectDeleter from '../app/src/Features/Project/ProjectDeleter.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
async function main() {
const argv = minimist(process.argv.slice(2))
@@ -14,7 +15,7 @@ async function main() {
}
try {
await main()
await scriptRunner(main)
console.log('Done.')
process.exit(0)
} catch (error) {

View File

@@ -1,6 +1,7 @@
import minimist from 'minimist'
import ThirdPartyIdentityManager from '../app/src/Features/User/ThirdPartyIdentityManager.js'
import UserGetter from '../app/src/Features/User/UserGetter.js'
import { scriptRunner } from './lib/ScriptRunner.mjs'
/**
* This script is used to remove a linked third party identity from a user account.
@@ -79,7 +80,7 @@ async function main() {
setup()
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error(error)

View File

@@ -1,7 +1,8 @@
import { db } from '../../app/src/infrastructure/mongodb.js'
import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
async function main() {
async function main(trackProgress) {
// update all applicable user models
await batchedUpdate(
db.users,
@@ -12,7 +13,10 @@ async function main() {
$set: {
'aiErrorAssistant.enabled': false,
},
}
},
undefined,
undefined,
{ trackProgress }
)
console.log('completed syncing writefull state with error assist')
}
@@ -20,7 +24,7 @@ async function main() {
export default main
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error({ error })

View File

@@ -3,6 +3,7 @@ import mongodb from 'mongodb-legacy'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
import { chunkArray } from '../helpers/chunkArray.mjs'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
@@ -37,7 +38,7 @@ export default main
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error({ error })

View File

@@ -2,6 +2,7 @@ import { db } from '../../app/src/infrastructure/mongodb.js'
import mongodb from 'mongodb-legacy'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
@@ -36,7 +37,7 @@ export default main
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error({ error })

View File

@@ -4,10 +4,11 @@ import mongodb from 'mongodb-legacy'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
import { chunkArray } from '../helpers/chunkArray.mjs'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
const { ObjectId } = mongodb
async function main() {
async function main(trackProgress) {
// search for file of users who already explicitly opted out first
const optOutPath = process.argv[2]
const optedOutFile = fs.readFileSync(optOutPath, 'utf8')
@@ -20,7 +21,10 @@ async function main() {
await batchedUpdate(
db.users,
{ 'writefull.enabled': false }, // and is false
{ $set: { 'writefull.enabled': null } }
{ $set: { 'writefull.enabled': null } },
undefined,
undefined,
{ trackProgress }
)
const chunks = chunkArray(optedOutList)
@@ -41,7 +45,7 @@ export default main
if (fileURLToPath(import.meta.url) === process.argv[1]) {
try {
await main()
await scriptRunner(main)
process.exit(0)
} catch (error) {
console.error({ error })