Merge pull request #26575 from overleaf/jpa-archived-state

[web] remove runtime migration for project.archived/trashed state

GitOrigin-RevId: 69064878f3dfdcde3727a4e3eb555deb75c70588
This commit is contained in:
Jakob Ackermann
2025-06-26 08:04:50 +00:00
committed by Copybot
parent 19980b41b8
commit 87de73333a
11 changed files with 94 additions and 589 deletions
@@ -2,7 +2,6 @@ const { callbackify } = require('util')
const OError = require('@overleaf/o-error')
const { Project } = require('../../models/Project')
const ProjectGetter = require('../Project/ProjectGetter')
const ProjectHelper = require('../Project/ProjectHelper')
const logger = require('@overleaf/logger')
const ContactManager = require('../Contacts/ContactManager')
const PrivilegeLevels = require('../Authorization/PrivilegeLevels')
@@ -53,55 +52,24 @@ async function fixNullCollaboratorRefs(projectId) {
async function removeUserFromProject(projectId, userId) {
try {
const project = await Project.findOne({ _id: projectId }).exec()
await fixNullCollaboratorRefs(projectId)
// Deal with the old type of boolean value for archived
// In order to clear it
if (typeof project.archived === 'boolean') {
let archived = ProjectHelper.calculateArchivedArray(
project,
userId,
'ARCHIVE'
)
archived = archived.filter(id => id.toString() !== userId.toString())
await Project.updateOne(
{ _id: projectId },
{
$set: { archived },
$pull: {
collaberator_refs: userId,
reviewer_refs: userId,
readOnly_refs: userId,
pendingEditor_refs: userId,
pendingReviewer_refs: userId,
tokenAccessReadOnly_refs: userId,
tokenAccessReadAndWrite_refs: userId,
trashed: userId,
},
}
)
} else {
await Project.updateOne(
{ _id: projectId },
{
$pull: {
collaberator_refs: userId,
readOnly_refs: userId,
reviewer_refs: userId,
pendingEditor_refs: userId,
pendingReviewer_refs: userId,
tokenAccessReadOnly_refs: userId,
tokenAccessReadAndWrite_refs: userId,
archived: userId,
trashed: userId,
},
}
)
}
await Project.updateOne(
{ _id: projectId },
{
$pull: {
collaberator_refs: userId,
readOnly_refs: userId,
reviewer_refs: userId,
pendingEditor_refs: userId,
pendingReviewer_refs: userId,
tokenAccessReadOnly_refs: userId,
tokenAccessReadAndWrite_refs: userId,
archived: userId,
trashed: userId,
},
}
)
} catch (err) {
throw OError.tag(err, 'problem removing user from project collaborators', {
projectId,
@@ -9,7 +9,6 @@ const Errors = require('../Errors/Errors')
const logger = require('@overleaf/logger')
const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
const TagsHandler = require('../Tags/TagsHandler')
const ProjectHelper = require('./ProjectHelper')
const ProjectDetailsHandler = require('./ProjectDetailsHandler')
const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler')
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
@@ -135,88 +134,37 @@ async function restoreProject(projectId) {
}
async function archiveProject(projectId, userId) {
try {
const project = await Project.findOne({ _id: projectId }).exec()
if (!project) {
throw new Errors.NotFoundError('project not found')
await Project.updateOne(
{ _id: projectId },
{
$addToSet: { archived: new ObjectId(userId) },
$pull: { trashed: new ObjectId(userId) },
}
const archived = ProjectHelper.calculateArchivedArray(
project,
userId,
'ARCHIVE'
)
await Project.updateOne(
{ _id: projectId },
{ $set: { archived }, $pull: { trashed: new ObjectId(userId) } }
)
} catch (err) {
logger.warn({ err }, 'problem archiving project')
throw err
}
)
}
async function unarchiveProject(projectId, userId) {
try {
const project = await Project.findOne({ _id: projectId }).exec()
if (!project) {
throw new Errors.NotFoundError('project not found')
}
const archived = ProjectHelper.calculateArchivedArray(
project,
userId,
'UNARCHIVE'
)
await Project.updateOne({ _id: projectId }, { $set: { archived } })
} catch (err) {
logger.warn({ err }, 'problem unarchiving project')
throw err
}
await Project.updateOne(
{ _id: projectId },
{ $pull: { archived: new ObjectId(userId) } }
)
}
async function trashProject(projectId, userId) {
try {
const project = await Project.findOne({ _id: projectId }).exec()
if (!project) {
throw new Errors.NotFoundError('project not found')
await Project.updateOne(
{ _id: projectId },
{
$addToSet: { trashed: new ObjectId(userId) },
$pull: { archived: new ObjectId(userId) },
}
const archived = ProjectHelper.calculateArchivedArray(
project,
userId,
'UNARCHIVE'
)
await Project.updateOne(
{ _id: projectId },
{
$addToSet: { trashed: new ObjectId(userId) },
$set: { archived },
}
)
} catch (err) {
logger.warn({ err }, 'problem trashing project')
throw err
}
)
}
async function untrashProject(projectId, userId) {
try {
const project = await Project.findOne({ _id: projectId }).exec()
if (!project) {
throw new Errors.NotFoundError('project not found')
}
await Project.updateOne(
{ _id: projectId },
{ $pull: { trashed: new ObjectId(userId) } }
)
} catch (err) {
logger.warn({ err }, 'problem untrashing project')
throw err
}
await Project.updateOne(
{ _id: projectId },
{ $pull: { trashed: new ObjectId(userId) } }
)
}
async function deleteProject(projectId, options = {}) {
@@ -20,7 +20,6 @@ module.exports = {
isArchived,
isTrashed,
isArchivedOrTrashed,
calculateArchivedArray,
ensureNameIsUnique,
getAllowedImagesForUser,
promises: {
@@ -63,38 +62,6 @@ function isArchivedOrTrashed(project, userId) {
return isArchived(project, userId) || isTrashed(project, userId)
}
function _allCollaborators(project) {
return _.unionWith(
[project.owner_ref],
project.collaberator_refs,
project.readOnly_refs,
project.tokenAccessReadAndWrite_refs,
project.tokenAccessReadOnly_refs,
_objectIdEquals
)
}
function calculateArchivedArray(project, userId, action) {
let archived = project.archived
userId = new ObjectId(userId)
if (archived === true) {
archived = _allCollaborators(project)
} else if (!archived) {
archived = []
}
if (action === 'ARCHIVE') {
archived = _.unionWith(archived, [userId], _objectIdEquals)
} else if (action === 'UNARCHIVE') {
archived = archived.filter(id => !_objectIdEquals(id, userId))
} else {
throw new Error('Unrecognised action')
}
return archived
}
function ensureNameIsUnique(nameList, name, suffixes, maxLength, callback) {
// create a set of all project names
if (suffixes == null) {
@@ -122,11 +89,6 @@ function ensureNameIsUnique(nameList, name, suffixes, maxLength, callback) {
}
}
function _objectIdEquals(firstVal, secondVal) {
// For use as a comparator for unionWith
return firstVal.toString() === secondVal.toString()
}
function _addSuffixToProjectName(name, suffix, maxLength) {
// append the suffix and truncate the project title if needed
if (suffix == null) {