diff --git a/server-ce/hotfix/3.3.2/Dockerfile b/server-ce/hotfix/3.3.2/Dockerfile new file mode 100644 index 0000000000..6cfe14fc8d --- /dev/null +++ b/server-ce/hotfix/3.3.2/Dockerfile @@ -0,0 +1,5 @@ +FROM sharelatex/sharelatex:3.3.0 + +# Patch: add migration for convert_archived_state script +COPY pr_10442.patch . +RUN patch -p0 < pr_10442.patch diff --git a/server-ce/hotfix/3.3.2/pr_10442.patch b/server-ce/hotfix/3.3.2/pr_10442.patch new file mode 100644 index 0000000000..6f5353da33 --- /dev/null +++ b/server-ce/hotfix/3.3.2/pr_10442.patch @@ -0,0 +1,132 @@ +--- services/web/scripts/convert_archived_state.js ++++ services/web/scripts/convert_archived_state.js +@@ -6,62 +6,77 @@ + const { promiseMapWithLimit } = require('../app/src/util/promises') + + // $ node scripts/convert_archived_state.js FIRST,SECOND +-const STAGE = process.argv.pop() + +-async function main() { +- if (STAGE.includes('FIRST')) { +- await batchedUpdate( +- 'projects', +- { archived: false }, +- { +- $set: { archived: [] }, +- } +- ) ++async function main(STAGE) { ++ for (const FIELD of ['archived', 'trashed']) { ++ if (STAGE.includes('FIRST')) { ++ await batchedUpdate( ++ 'projects', ++ { [FIELD]: false }, ++ { ++ $set: { [FIELD]: [] }, ++ } ++ ) + +- console.error('Done, with first part') +- } ++ console.error('Done, with first part for field:', FIELD) ++ } + +- if (STAGE.includes('SECOND')) { +- await batchedUpdate('projects', { archived: true }, performUpdate, { +- _id: 1, +- owner_ref: 1, +- collaberator_refs: 1, +- readOnly_refs: 1, +- tokenAccessReadAndWrite_refs: 1, +- tokenAccessReadOnly_refs: 1, +- }) ++ if (STAGE.includes('SECOND')) { ++ await batchedUpdate( ++ 'projects', ++ { [FIELD]: true }, ++ async function performUpdate(collection, nextBatch) { ++ await promiseMapWithLimit( ++ WRITE_CONCURRENCY, ++ nextBatch, ++ async project => { ++ try { ++ await upgradeFieldToArray({ collection, project, FIELD }) ++ } catch (err) { ++ console.error(project._id, err) ++ throw err ++ } ++ } ++ ) ++ }, ++ { ++ _id: 1, ++ owner_ref: 1, ++ collaberator_refs: 1, ++ readOnly_refs: 1, ++ tokenAccessReadAndWrite_refs: 1, ++ tokenAccessReadOnly_refs: 1, ++ } ++ ) + +- console.error('Done, with second part') ++ console.error('Done, with second part for field:', FIELD) ++ } + } + } + +-main() +- .then(() => { +- process.exit(0) +- }) +- .catch(error => { +- console.error({ error }) +- process.exit(1) +- }) +- +-async function performUpdate(collection, nextBatch) { +- await promiseMapWithLimit(WRITE_CONCURRENCY, nextBatch, project => +- setArchived(collection, project) +- ) ++module.exports = main ++ ++if (require.main === module) { ++ main(process.argv.pop()) ++ .then(() => { ++ process.exit(0) ++ }) ++ .catch(error => { ++ console.error({ error }) ++ process.exit(1) ++ }) + } + +-async function setArchived(collection, project) { +- const archived = calculateArchivedArray(project) +- ++async function upgradeFieldToArray({ collection, project, FIELD }) { + return collection.updateOne( + { _id: project._id }, + { +- $set: { archived }, ++ $set: { [FIELD]: getAllUserIds(project) }, + } + ) + } + +-function calculateArchivedArray(project) { ++function getAllUserIds(project) { + return _.unionWith( + [project.owner_ref], + project.collaberator_refs, +--- /dev/null ++++ services/web/migrations/20221111111111_ce_sp_convert_archived_state.js +@@ -0,0 +1,9 @@ ++const runScript = require('../scripts/convert_archived_state') ++ ++exports.tags = ['server-ce', 'server-pro'] ++ ++exports.migrate = async () => { ++ await runScript('FIRST,SECOND') ++} ++ ++exports.rollback = async () => {}