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
@@ -120,7 +120,7 @@ describe('ConvertArchivedState', function () {
beforeEach(function (done) {
exec(
'CONNECT_DELAY=1 node scripts/convert_archived_state.mjs FIRST,SECOND',
'east migrate --tag server-ce --force 20221111111111_ce_sp_convert_archived_state',
error => {
if (error) {
return done(error)
@@ -125,25 +125,6 @@ describe('Project CRUD', function () {
expectObjectIdArrayEqual(trashedProject.archived, [])
})
})
describe('with a legacy boolean state', function () {
it('should mark the project as not archived for the user', async function () {
await Project.updateOne(
{ _id: this.projectId },
{ $set: { archived: true } }
).exec()
const { response } = await this.user.doRequest(
'POST',
`/project/${this.projectId}/trash`
)
expect(response.statusCode).to.equal(200)
const trashedProject = await Project.findById(this.projectId).exec()
expectObjectIdArrayEqual(trashedProject.archived, [])
})
})
})
describe('when untrashing a project', function () {
@@ -24,16 +24,6 @@ describe('CollaboratorsHandler', function () {
name: 'Foo',
}
this.archivedProject = {
_id: new ObjectId(),
archived: [new ObjectId(this.userId)],
}
this.oldArchivedProject = {
_id: new ObjectId(),
archived: true,
}
this.UserGetter = {
promises: {
getUser: sinon.stub().resolves(null),
@@ -59,9 +49,6 @@ describe('CollaboratorsHandler', function () {
},
}
this.ProjectHelper = {
calculateArchivedArray: sinon.stub(),
}
this.CollaboratorsGetter = {
promises: {
dangerouslyGetAllProjectsUserIsMemberOf: sinon.stub(),
@@ -77,7 +64,6 @@ describe('CollaboratorsHandler', function () {
'../ThirdPartyDataStore/TpdsProjectFlusher': this.TpdsProjectFlusher,
'../ThirdPartyDataStore/TpdsUpdateSender': this.TpdsUpdateSender,
'../Project/ProjectGetter': this.ProjectGetter,
'../Project/ProjectHelper': this.ProjectHelper,
'../Editor/EditorRealTimeController': this.EditorRealTimeController,
'./CollaboratorsGetter': this.CollaboratorsGetter,
},
@@ -130,15 +116,6 @@ describe('CollaboratorsHandler', function () {
describe('removeUserFromProject', function () {
describe('a non-archived project', function () {
beforeEach(function () {
this.ProjectMock.expects('findOne')
.withArgs({
_id: this.project._id,
})
.chain('exec')
.resolves(this.project)
})
it('should remove the user from mongo', async function () {
this.expectNullReferenceCleanup(this.project._id)
this.ProjectMock.expects('updateOne')
@@ -168,89 +145,6 @@ describe('CollaboratorsHandler', function () {
)
})
})
describe('an archived project, archived with a boolean value', function () {
beforeEach(function () {
const archived = [new ObjectId(this.userId)]
this.ProjectHelper.calculateArchivedArray.returns(archived)
this.ProjectMock.expects('findOne')
.withArgs({
_id: this.oldArchivedProject._id,
})
.chain('exec')
.resolves(this.oldArchivedProject)
})
it('should remove the user from mongo', async function () {
this.expectNullReferenceCleanup(this.oldArchivedProject._id)
this.ProjectMock.expects('updateOne')
.withArgs(
{
_id: this.oldArchivedProject._id,
},
{
$set: {
archived: [],
},
$pull: {
collaberator_refs: this.userId,
reviewer_refs: this.userId,
readOnly_refs: this.userId,
pendingEditor_refs: this.userId,
pendingReviewer_refs: this.userId,
tokenAccessReadOnly_refs: this.userId,
tokenAccessReadAndWrite_refs: this.userId,
trashed: this.userId,
},
}
)
.resolves()
await this.CollaboratorsHandler.promises.removeUserFromProject(
this.oldArchivedProject._id,
this.userId
)
})
})
describe('an archived project, archived with an array value', function () {
beforeEach(function () {
this.ProjectMock.expects('findOne')
.withArgs({
_id: this.archivedProject._id,
})
.chain('exec')
.resolves(this.archivedProject)
})
it('should remove the user from mongo', async function () {
this.expectNullReferenceCleanup(this.archivedProject._id)
this.ProjectMock.expects('updateOne')
.withArgs(
{
_id: this.archivedProject._id,
},
{
$pull: {
collaberator_refs: this.userId,
reviewer_refs: this.userId,
readOnly_refs: this.userId,
pendingEditor_refs: this.userId,
pendingReviewer_refs: this.userId,
tokenAccessReadOnly_refs: this.userId,
tokenAccessReadAndWrite_refs: this.userId,
archived: this.userId,
trashed: this.userId,
},
}
)
.resolves()
await this.CollaboratorsHandler.promises.removeUserFromProject(
this.archivedProject._id,
this.userId
)
})
})
})
describe('addUserIdToProject', function () {
@@ -539,13 +433,6 @@ describe('CollaboratorsHandler', function () {
'token-read-only-1',
]
for (const projectId of expectedProjects) {
this.ProjectMock.expects('findOne')
.withArgs({
_id: projectId,
})
.chain('exec')
.resolves({ _id: projectId })
this.expectNullReferenceCleanup(projectId)
this.ProjectMock.expects('updateOne')
.withArgs(
@@ -95,10 +95,6 @@ describe('ProjectDeleter', function () {
},
}
this.ProjectHelper = {
calculateArchivedArray: sinon.stub(),
}
this.db = {
projects: {
insertOne: sinon.stub().resolves(),
@@ -143,7 +139,6 @@ describe('ProjectDeleter', function () {
'../../infrastructure/Features': this.Features,
'../Editor/EditorRealTimeController': this.EditorRealTimeController,
'../../models/Project': { Project },
'./ProjectHelper': this.ProjectHelper,
'../../models/DeletedProject': { DeletedProject },
'../DocumentUpdater/DocumentUpdaterHandler':
this.DocumentUpdaterHandler,
@@ -559,19 +554,11 @@ describe('ProjectDeleter', function () {
describe('archiveProject', function () {
beforeEach(function () {
const archived = [new ObjectId(this.user._id)]
this.ProjectHelper.calculateArchivedArray.returns(archived)
this.ProjectMock.expects('findOne')
.withArgs({ _id: this.project._id })
.chain('exec')
.resolves(this.project)
this.ProjectMock.expects('updateOne')
.withArgs(
{ _id: this.project._id },
{
$set: { archived },
$addToSet: { archived: new ObjectId(this.user._id) },
$pull: { trashed: new ObjectId(this.user._id) },
}
)
@@ -585,32 +572,15 @@ describe('ProjectDeleter', function () {
)
this.ProjectMock.verify()
})
it('calculates the archived array', async function () {
await this.ProjectDeleter.promises.archiveProject(
this.project._id,
this.user._id
)
expect(this.ProjectHelper.calculateArchivedArray).to.have.been.calledWith(
this.project,
this.user._id,
'ARCHIVE'
)
})
})
describe('unarchiveProject', function () {
beforeEach(function () {
const archived = [new ObjectId(this.user._id)]
this.ProjectHelper.calculateArchivedArray.returns(archived)
this.ProjectMock.expects('findOne')
.withArgs({ _id: this.project._id })
.chain('exec')
.resolves(this.project)
this.ProjectMock.expects('updateOne')
.withArgs({ _id: this.project._id }, { $set: { archived } })
.withArgs(
{ _id: this.project._id },
{ $pull: { archived: new ObjectId(this.user._id) } }
)
.resolves()
})
@@ -621,36 +591,16 @@ describe('ProjectDeleter', function () {
)
this.ProjectMock.verify()
})
it('calculates the archived array', async function () {
await this.ProjectDeleter.promises.unarchiveProject(
this.project._id,
this.user._id
)
expect(this.ProjectHelper.calculateArchivedArray).to.have.been.calledWith(
this.project,
this.user._id,
'UNARCHIVE'
)
})
})
describe('trashProject', function () {
beforeEach(function () {
const archived = [new ObjectId(this.user._id)]
this.ProjectHelper.calculateArchivedArray.returns(archived)
this.ProjectMock.expects('findOne')
.withArgs({ _id: this.project._id })
.chain('exec')
.resolves(this.project)
this.ProjectMock.expects('updateOne')
.withArgs(
{ _id: this.project._id },
{
$addToSet: { trashed: new ObjectId(this.user._id) },
$set: { archived },
$pull: { archived: new ObjectId(this.user._id) },
}
)
.resolves()
@@ -663,27 +613,10 @@ describe('ProjectDeleter', function () {
)
this.ProjectMock.verify()
})
it('unarchives the project', async function () {
await this.ProjectDeleter.promises.trashProject(
this.project._id,
this.user._id
)
expect(this.ProjectHelper.calculateArchivedArray).to.have.been.calledWith(
this.project,
this.user._id,
'UNARCHIVE'
)
})
})
describe('untrashProject', function () {
beforeEach(function () {
this.ProjectMock.expects('findOne')
.withArgs({ _id: this.project._id })
.chain('exec')
.resolves(this.project)
this.ProjectMock.expects('updateOne')
.withArgs(
{ _id: this.project._id },
@@ -101,134 +101,6 @@ describe('ProjectHelper', function () {
})
})
describe('calculateArchivedArray', function () {
describe('project.archived being an array', function () {
it('returns an array adding the current user id when archiving', function () {
const project = { archived: [] }
const result = this.ProjectHelper.calculateArchivedArray(
project,
new ObjectId('5c922599cdb09e014aa7d499'),
'ARCHIVE'
)
expect(result).to.deep.equal([new ObjectId('5c922599cdb09e014aa7d499')])
})
it('returns an array without the current user id when unarchiving', function () {
const project = { archived: [new ObjectId('5c922599cdb09e014aa7d499')] }
const result = this.ProjectHelper.calculateArchivedArray(
project,
new ObjectId('5c922599cdb09e014aa7d499'),
'UNARCHIVE'
)
expect(result).to.deep.equal([])
})
})
describe('project.archived being a boolean and being true', function () {
it('returns an array of all associated user ids when archiving', function () {
const project = {
archived: true,
owner_ref: this.user._id,
collaberator_refs: [
new ObjectId('4f2cfb341eb5855a5b000f8b'),
new ObjectId('5c45f3bd425ead01488675aa'),
],
readOnly_refs: [new ObjectId('5c92243fcdb09e014aa7d487')],
tokenAccessReadAndWrite_refs: [
new ObjectId('5c922599cdb09e014aa7d499'),
],
tokenAccessReadOnly_refs: [],
}
const result = this.ProjectHelper.calculateArchivedArray(
project,
this.user._id,
'ARCHIVE'
)
expect(result).to.deep.equal([
this.user._id,
new ObjectId('4f2cfb341eb5855a5b000f8b'),
new ObjectId('5c45f3bd425ead01488675aa'),
new ObjectId('5c92243fcdb09e014aa7d487'),
new ObjectId('5c922599cdb09e014aa7d499'),
])
})
it('returns an array of all associated users without the current user id when unarchived', function () {
const project = {
archived: true,
owner_ref: this.user._id,
collaberator_refs: [
new ObjectId('4f2cfb341eb5855a5b000f8b'),
new ObjectId('5c45f3bd425ead01488675aa'),
new ObjectId('5c922599cdb09e014aa7d499'),
],
readOnly_refs: [new ObjectId('5c92243fcdb09e014aa7d487')],
tokenAccessReadAndWrite_refs: [
new ObjectId('5c922599cdb09e014aa7d499'),
],
tokenAccessReadOnly_refs: [],
}
const result = this.ProjectHelper.calculateArchivedArray(
project,
this.user._id,
'UNARCHIVE'
)
expect(result).to.deep.equal([
new ObjectId('4f2cfb341eb5855a5b000f8b'),
new ObjectId('5c45f3bd425ead01488675aa'),
new ObjectId('5c922599cdb09e014aa7d499'),
new ObjectId('5c92243fcdb09e014aa7d487'),
])
})
})
describe('project.archived being a boolean and being false', function () {
it('returns an array adding the current user id when archiving', function () {
const project = { archived: false }
const result = this.ProjectHelper.calculateArchivedArray(
project,
new ObjectId('5c922599cdb09e014aa7d499'),
'ARCHIVE'
)
expect(result).to.deep.equal([new ObjectId('5c922599cdb09e014aa7d499')])
})
it('returns an empty array when unarchiving', function () {
const project = { archived: false }
const result = this.ProjectHelper.calculateArchivedArray(
project,
new ObjectId('5c922599cdb09e014aa7d499'),
'UNARCHIVE'
)
expect(result).to.deep.equal([])
})
})
describe('project.archived not being set', function () {
it('returns an array adding the current user id when archiving', function () {
const project = { archived: undefined }
const result = this.ProjectHelper.calculateArchivedArray(
project,
new ObjectId('5c922599cdb09e014aa7d499'),
'ARCHIVE'
)
expect(result).to.deep.equal([new ObjectId('5c922599cdb09e014aa7d499')])
})
it('returns an empty array when unarchiving', function () {
const project = { archived: undefined }
const result = this.ProjectHelper.calculateArchivedArray(
project,
new ObjectId('5c922599cdb09e014aa7d499'),
'UNARCHIVE'
)
expect(result).to.deep.equal([])
})
})
})
describe('compilerFromV1Engine', function () {
it('returns the correct engine for latex_dvipdf', function () {
expect(this.ProjectHelper.compilerFromV1Engine('latex_dvipdf')).to.equal(